Merge the pre-production code back to gerrit 01/4801/2 preprod-22.06.1
authorRuoyu Ying <ruoyu.ying@intel.com>
Wed, 20 Apr 2022 06:08:15 +0000 (02:08 -0400)
committerRuoyu <ruoyu.ying@intel.com>
Wed, 20 Apr 2022 11:21:18 +0000 (07:21 -0400)
Change-Id: Iae6c6c93f4c43ff83b2d6d7bd1b901a05c3fdc59
Signed-off-by: Ruoyu <ruoyu.ying@intel.com>
295 files changed:
README.md
central-controller/build/Dockerfile
central-controller/deployments/README.md
central-controller/deployments/kubernetes/monitor-deploy.sh [deleted file]
central-controller/deployments/kubernetes/monitor-deploy.yaml [new file with mode: 0644]
central-controller/deployments/kubernetes/monitor-undeploy.sh [deleted file]
central-controller/deployments/kubernetes/monitor/cluster_role.yaml [deleted file]
central-controller/deployments/kubernetes/monitor/clusterrole_binding.yaml [deleted file]
central-controller/deployments/kubernetes/monitor/crds/k8splugin_v1alpha1_resourcebundlestate_cr.yaml [deleted file]
central-controller/deployments/kubernetes/monitor/crds/k8splugin_v1alpha1_resourcebundlestate_crd.yaml [deleted file]
central-controller/deployments/kubernetes/monitor/monitor-cleanup.sh [deleted file]
central-controller/deployments/kubernetes/monitor/operator.yaml [deleted file]
central-controller/deployments/kubernetes/monitor/role.yaml [deleted file]
central-controller/deployments/kubernetes/monitor/role_binding.yaml [deleted file]
central-controller/deployments/kubernetes/monitor/service_account.yaml [deleted file]
central-controller/deployments/kubernetes/scc.yaml
central-controller/deployments/kubernetes/scc_db.yaml [deleted file]
central-controller/deployments/kubernetes/scc_etcd.yaml [new file with mode: 0644]
central-controller/deployments/kubernetes/scc_mongo.yaml [new file with mode: 0644]
central-controller/deployments/kubernetes/scc_rsync.yaml
central-controller/deployments/kubernetes/scc_secret.yaml [new file with mode: 0644]
central-controller/src/monitor/.gitignore
central-controller/src/monitor/Dockerfile [new file with mode: 0644]
central-controller/src/monitor/LICENSE.txt
central-controller/src/monitor/Makefile
central-controller/src/monitor/PROJECT [new file with mode: 0644]
central-controller/src/monitor/cmd/manager/main.go [deleted file]
central-controller/src/monitor/controllers/commit.go [new file with mode: 0644]
central-controller/src/monitor/controllers/controller_list.go [new file with mode: 0644]
central-controller/src/monitor/controllers/helpers.go [new file with mode: 0644]
central-controller/src/monitor/controllers/resourcebundlestate_controller.go [new file with mode: 0644]
central-controller/src/monitor/controllers/resources.go [new file with mode: 0644]
central-controller/src/monitor/controllers/suite_test.go [new file with mode: 0644]
central-controller/src/monitor/go.mod
central-controller/src/monitor/go.sum
central-controller/src/monitor/hack/boilerplate.go.txt [new file with mode: 0644]
central-controller/src/monitor/main.go [new file with mode: 0644]
central-controller/src/monitor/pkg/apis/addtoscheme_k8splugin_v1alpha1.go [deleted file]
central-controller/src/monitor/pkg/apis/apis.go [deleted file]
central-controller/src/monitor/pkg/apis/k8splugin/group.go [deleted file]
central-controller/src/monitor/pkg/apis/k8splugin/v1alpha1/doc.go [deleted file]
central-controller/src/monitor/pkg/apis/k8splugin/v1alpha1/groupversion_info.go [new file with mode: 0644]
central-controller/src/monitor/pkg/apis/k8splugin/v1alpha1/register.go [deleted file]
central-controller/src/monitor/pkg/apis/k8splugin/v1alpha1/resourcebundlestate_types.go [new file with mode: 0644]
central-controller/src/monitor/pkg/apis/k8splugin/v1alpha1/types.go [deleted file]
central-controller/src/monitor/pkg/apis/k8splugin/v1alpha1/zz_generated.deepcopy.go
central-controller/src/monitor/pkg/apis/k8splugin/v1alpha1/zz_generated.openapi.go [deleted file]
central-controller/src/monitor/pkg/client/clientset/versioned/clientset.go [moved from central-controller/src/monitor/pkg/generated/clientset/versioned/clientset.go with 77% similarity]
central-controller/src/monitor/pkg/client/clientset/versioned/doc.go [new file with mode: 0644]
central-controller/src/monitor/pkg/client/clientset/versioned/fake/clientset_generated.go [moved from central-controller/src/monitor/pkg/generated/clientset/versioned/fake/clientset_generated.go with 67% similarity]
central-controller/src/monitor/pkg/client/clientset/versioned/fake/doc.go [new file with mode: 0644]
central-controller/src/monitor/pkg/client/clientset/versioned/fake/register.go [moved from central-controller/src/monitor/pkg/generated/clientset/versioned/fake/register.go with 65% similarity]
central-controller/src/monitor/pkg/client/clientset/versioned/scheme/doc.go [new file with mode: 0644]
central-controller/src/monitor/pkg/client/clientset/versioned/scheme/register.go [moved from central-controller/src/monitor/pkg/generated/clientset/versioned/scheme/register.go with 65% similarity]
central-controller/src/monitor/pkg/client/clientset/versioned/typed/k8splugin/v1alpha1/doc.go [new file with mode: 0644]
central-controller/src/monitor/pkg/client/clientset/versioned/typed/k8splugin/v1alpha1/fake/doc.go [new file with mode: 0644]
central-controller/src/monitor/pkg/client/clientset/versioned/typed/k8splugin/v1alpha1/fake/fake_k8splugin_client.go [new file with mode: 0644]
central-controller/src/monitor/pkg/client/clientset/versioned/typed/k8splugin/v1alpha1/fake/fake_resourcebundlestate.go [moved from central-controller/src/monitor/pkg/generated/clientset/versioned/typed/k8splugin/v1alpha1/fake/fake_resourcebundlestate.go with 86% similarity]
central-controller/src/monitor/pkg/client/clientset/versioned/typed/k8splugin/v1alpha1/generated_expansion.go [new file with mode: 0644]
central-controller/src/monitor/pkg/client/clientset/versioned/typed/k8splugin/v1alpha1/k8splugin_client.go [moved from central-controller/src/monitor/pkg/generated/clientset/versioned/typed/k8splugin/v1alpha1/k8splugin_client.go with 70% similarity]
central-controller/src/monitor/pkg/client/clientset/versioned/typed/k8splugin/v1alpha1/resourcebundlestate.go [moved from central-controller/src/monitor/pkg/generated/clientset/versioned/typed/k8splugin/v1alpha1/resourcebundlestate.go with 89% similarity]
central-controller/src/monitor/pkg/client/informers/externalversions/factory.go [moved from central-controller/src/monitor/pkg/generated/informers/externalversions/factory.go with 86% similarity]
central-controller/src/monitor/pkg/client/informers/externalversions/generic.go [moved from central-controller/src/monitor/pkg/generated/informers/externalversions/generic.go with 66% similarity]
central-controller/src/monitor/pkg/client/informers/externalversions/internalinterfaces/factory_interfaces.go [moved from central-controller/src/monitor/pkg/generated/informers/externalversions/internalinterfaces/factory_interfaces.go with 54% similarity]
central-controller/src/monitor/pkg/client/informers/externalversions/k8splugin/interface.go [moved from central-controller/src/monitor/pkg/generated/informers/externalversions/k8splugin/interface.go with 51% similarity]
central-controller/src/monitor/pkg/client/informers/externalversions/k8splugin/v1alpha1/interface.go [moved from central-controller/src/monitor/pkg/generated/informers/externalversions/k8splugin/v1alpha1/interface.go with 58% similarity]
central-controller/src/monitor/pkg/client/informers/externalversions/k8splugin/v1alpha1/resourcebundlestate.go [moved from central-controller/src/monitor/pkg/generated/informers/externalversions/k8splugin/v1alpha1/resourcebundlestate.go with 74% similarity]
central-controller/src/monitor/pkg/client/listers/k8splugin/v1alpha1/expansion_generated.go [new file with mode: 0644]
central-controller/src/monitor/pkg/client/listers/k8splugin/v1alpha1/resourcebundlestate.go [moved from central-controller/src/monitor/pkg/generated/listers/k8splugin/v1alpha1/resourcebundlestate.go with 82% similarity]
central-controller/src/monitor/pkg/controller/add_resourcebundlestate.go [deleted file]
central-controller/src/monitor/pkg/controller/controller.go [deleted file]
central-controller/src/monitor/pkg/controller/resourcebundlestate/configMap_controller.go [deleted file]
central-controller/src/monitor/pkg/controller/resourcebundlestate/configMap_predicate.go [deleted file]
central-controller/src/monitor/pkg/controller/resourcebundlestate/controller.go [deleted file]
central-controller/src/monitor/pkg/controller/resourcebundlestate/csr_controller.go [deleted file]
central-controller/src/monitor/pkg/controller/resourcebundlestate/csr_predicate.go [deleted file]
central-controller/src/monitor/pkg/controller/resourcebundlestate/daemonSet_controller.go [deleted file]
central-controller/src/monitor/pkg/controller/resourcebundlestate/daemonSet_predicate.go [deleted file]
central-controller/src/monitor/pkg/controller/resourcebundlestate/deployment_controller.go [deleted file]
central-controller/src/monitor/pkg/controller/resourcebundlestate/deployment_predicate.go [deleted file]
central-controller/src/monitor/pkg/controller/resourcebundlestate/handler.go [deleted file]
central-controller/src/monitor/pkg/controller/resourcebundlestate/helpers.go [deleted file]
central-controller/src/monitor/pkg/controller/resourcebundlestate/ingress_controller.go [deleted file]
central-controller/src/monitor/pkg/controller/resourcebundlestate/ingress_predicate.go [deleted file]
central-controller/src/monitor/pkg/controller/resourcebundlestate/job_controller.go [deleted file]
central-controller/src/monitor/pkg/controller/resourcebundlestate/job_predicate.go [deleted file]
central-controller/src/monitor/pkg/controller/resourcebundlestate/pod_controller.go [deleted file]
central-controller/src/monitor/pkg/controller/resourcebundlestate/pod_predicate.go [deleted file]
central-controller/src/monitor/pkg/controller/resourcebundlestate/secret_controller.go [deleted file]
central-controller/src/monitor/pkg/controller/resourcebundlestate/secret_predicate.go [deleted file]
central-controller/src/monitor/pkg/controller/resourcebundlestate/service_controller.go [deleted file]
central-controller/src/monitor/pkg/controller/resourcebundlestate/service_predicate.go [deleted file]
central-controller/src/monitor/pkg/controller/resourcebundlestate/statefulSet_controller.go [deleted file]
central-controller/src/monitor/pkg/controller/resourcebundlestate/statefulSet_predicate.go [deleted file]
central-controller/src/monitor/pkg/generated/clientset/versioned/doc.go [deleted file]
central-controller/src/monitor/pkg/generated/clientset/versioned/fake/doc.go [deleted file]
central-controller/src/monitor/pkg/generated/clientset/versioned/scheme/doc.go [deleted file]
central-controller/src/monitor/pkg/generated/clientset/versioned/typed/k8splugin/v1alpha1/doc.go [deleted file]
central-controller/src/monitor/pkg/generated/clientset/versioned/typed/k8splugin/v1alpha1/fake/doc.go [deleted file]
central-controller/src/monitor/pkg/generated/clientset/versioned/typed/k8splugin/v1alpha1/fake/fake_k8splugin_client.go [deleted file]
central-controller/src/monitor/pkg/generated/clientset/versioned/typed/k8splugin/v1alpha1/generated_expansion.go [deleted file]
central-controller/src/monitor/pkg/generated/listers/k8splugin/v1alpha1/expansion_generated.go [deleted file]
central-controller/src/monitor/tools.go [deleted file]
central-controller/src/monitor/version/version.go [deleted file]
central-controller/src/reg_cluster/README.md
central-controller/src/reg_cluster/go.mod
central-controller/src/reg_cluster/go.sum
central-controller/src/reg_cluster/ref-schemas/v1.yaml [new file with mode: 0644]
central-controller/src/reg_cluster/reg_cluster.go
central-controller/src/rsync/Makefile
central-controller/src/rsync/cmd/main.go
central-controller/src/rsync/coverage.html [deleted file]
central-controller/src/rsync/go.mod
central-controller/src/rsync/go.sum
central-controller/src/rsync/pkg/client/approve.go
central-controller/src/rsync/pkg/client/delete.go
central-controller/src/rsync/pkg/client/factory.go
central-controller/src/rsync/pkg/client/fake_client.go
central-controller/src/rsync/pkg/client/resource.go
central-controller/src/rsync/pkg/connector/connector.go
central-controller/src/rsync/pkg/connector/connector_new.go [new file with mode: 0644]
central-controller/src/rsync/pkg/context/cluster.go [new file with mode: 0644]
central-controller/src/rsync/pkg/context/context.go
central-controller/src/rsync/pkg/context/context_test.go [new file with mode: 0644]
central-controller/src/rsync/pkg/context/helpers.go [new file with mode: 0644]
central-controller/src/rsync/pkg/context/mock.go [new file with mode: 0644]
central-controller/src/rsync/pkg/context/queueUtils.go [new file with mode: 0644]
central-controller/src/rsync/pkg/context/restart.go [new file with mode: 0644]
central-controller/src/rsync/pkg/context/routines.go [new file with mode: 0644]
central-controller/src/rsync/pkg/db/cluster.go
central-controller/src/rsync/pkg/depend/depend.go [new file with mode: 0644]
central-controller/src/rsync/pkg/depend/depend_test.go [new file with mode: 0644]
central-controller/src/rsync/pkg/gitops/emcogit/emcogit.go [new file with mode: 0644]
central-controller/src/rsync/pkg/gitops/emcogithub/emcogithub.go [new file with mode: 0644]
central-controller/src/rsync/pkg/gitops/gitsupport/gitsupport.go [new file with mode: 0644]
central-controller/src/rsync/pkg/grpc/installappserver/installappserver.go
central-controller/src/rsync/pkg/grpc/mock_installapp/installapp.mock.go
central-controller/src/rsync/pkg/grpc/mock_readynotify/readynotify.mock.go [new file with mode: 0644]
central-controller/src/rsync/pkg/grpc/readynotifyserver/readynotifyserver.go
central-controller/src/rsync/pkg/grpc/readynotifyserver/readynotifyserver_test.go
central-controller/src/rsync/pkg/grpc/register.go [deleted file]
central-controller/src/rsync/pkg/grpc/updateapp/updateapp.pb.go [new file with mode: 0644]
central-controller/src/rsync/pkg/grpc/updateapp/updateapp.proto [new file with mode: 0644]
central-controller/src/rsync/pkg/grpc/updateappserver/updateappserver.go [new file with mode: 0644]
central-controller/src/rsync/pkg/internal/utils.go [deleted file]
central-controller/src/rsync/pkg/internal/utils/acutils.go [new file with mode: 0644]
central-controller/src/rsync/pkg/internal/utils/helpers.go [new file with mode: 0644]
central-controller/src/rsync/pkg/plugins/azurearc/config.go [new file with mode: 0644]
central-controller/src/rsync/pkg/plugins/azurearc/k8s.go [new file with mode: 0644]
central-controller/src/rsync/pkg/plugins/azurearc/resources.go [new file with mode: 0644]
central-controller/src/rsync/pkg/plugins/azurearc/status.go [new file with mode: 0644]
central-controller/src/rsync/pkg/plugins/fluxv2/config.go [new file with mode: 0644]
central-controller/src/rsync/pkg/plugins/fluxv2/k8s.go [new file with mode: 0644]
central-controller/src/rsync/pkg/plugins/fluxv2/resources.go [new file with mode: 0644]
central-controller/src/rsync/pkg/plugins/fluxv2/status.go [new file with mode: 0644]
central-controller/src/rsync/pkg/plugins/k8s/config.go [new file with mode: 0644]
central-controller/src/rsync/pkg/plugins/k8s/k8s.go [new file with mode: 0644]
central-controller/src/rsync/pkg/plugins/k8s/resources.go [new file with mode: 0644]
central-controller/src/rsync/pkg/plugins/k8s/status.go [new file with mode: 0644]
central-controller/src/rsync/pkg/plugins/k8sexp/configexp.go [new file with mode: 0644]
central-controller/src/rsync/pkg/plugins/k8sexp/k8sexp.go [new file with mode: 0644]
central-controller/src/rsync/pkg/plugins/k8sexp/resourcesexp.go [new file with mode: 0644]
central-controller/src/rsync/pkg/plugins/k8sexp/statusexp.go [new file with mode: 0644]
central-controller/src/rsync/pkg/status/deploymentutil.go [new file with mode: 0644]
central-controller/src/rsync/pkg/status/ready.go [new file with mode: 0644]
central-controller/src/rsync/pkg/status/res_status.go [new file with mode: 0644]
central-controller/src/rsync/pkg/status/status.go [deleted file]
central-controller/src/rsync/pkg/status/status_test.go [new file with mode: 0644]
central-controller/src/rsync/pkg/status/test/test.yaml [new file with mode: 0644]
central-controller/src/rsync/pkg/types/types.go [new file with mode: 0644]
central-controller/src/rsync/ref-schemas/v1.yaml [new file with mode: 0644]
central-controller/src/rsync/scripts/Dockerfile [deleted file]
central-controller/src/scc/api/api.go
central-controller/src/scc/cmd/main.go
central-controller/src/scc/go.mod
central-controller/src/scc/go.sum
central-controller/src/scc/pkg/client/rsyncclient.go
central-controller/src/scc/pkg/manager/certificate_objectmanager.go
central-controller/src/scc/pkg/manager/clustersync_objectmanager.go [new file with mode: 0644]
central-controller/src/scc/pkg/manager/cnf_objectmanager.go
central-controller/src/scc/pkg/manager/connection_manager.go
central-controller/src/scc/pkg/manager/constants.go
central-controller/src/scc/pkg/manager/controller_objectmanager.go
central-controller/src/scc/pkg/manager/dbutils.go
central-controller/src/scc/pkg/manager/device_objectmanager.go
central-controller/src/scc/pkg/manager/deviceconnection_objectmanager.go
central-controller/src/scc/pkg/manager/devicesite_objectmanager.go [new file with mode: 0644]
central-controller/src/scc/pkg/manager/hub_objectmanager.go
central-controller/src/scc/pkg/manager/hubconnection_objectmanager.go
central-controller/src/scc/pkg/manager/hubdevice_objectmanager.go
central-controller/src/scc/pkg/manager/iprange_objectmanager.go
central-controller/src/scc/pkg/manager/managerset.go
central-controller/src/scc/pkg/manager/overlay_objectmanager.go
central-controller/src/scc/pkg/manager/proposal_objectmanager.go
central-controller/src/scc/pkg/manager/resource_objectmanager.go
central-controller/src/scc/pkg/manager/resutils.go
central-controller/src/scc/pkg/manager/utils.go
central-controller/src/scc/pkg/module/clustersyncobject.go [new file with mode: 0644]
central-controller/src/scc/pkg/module/connectionobject.go
central-controller/src/scc/pkg/module/deviceobject.go
central-controller/src/scc/pkg/module/hubdeviceobject.go
central-controller/src/scc/pkg/module/hubobject.go
central-controller/src/scc/pkg/module/resourceobject.go
central-controller/src/scc/pkg/module/siteobject.go [new file with mode: 0644]
central-controller/src/scc/pkg/resource/empty_resource.go
central-controller/src/scc/pkg/resource/firewall_nat_resource.go
central-controller/src/scc/pkg/resource/hubsite_resource.go [new file with mode: 0644]
central-controller/src/scc/pkg/resource/route_resource.go
central-controller/src/scc/ref-schemas/v1.yaml [new file with mode: 0644]
central-controller/src/scc/rsync_config.json
central-controller/src/scc/tools/ewoctl/examples/clustersyncobject.yaml [new file with mode: 0644]
central-controller/src/vendor/github.com/open-ness/EMCO/src/go.mod [deleted file]
central-controller/src/vendor/github.com/open-ness/EMCO/src/orchestrator/go.mod [deleted file]
central-controller/src/vendor/github.com/open-ness/EMCO/src/orchestrator/pkg/appcontext/subresources/approval.go [deleted file]
central-controller/src/vendor/github.com/open-ness/EMCO/src/orchestrator/pkg/infra/config/config_test.go [deleted file]
central-controller/src/vendor/github.com/open-ness/EMCO/src/orchestrator/pkg/infra/db/mongo.go [deleted file]
central-controller/src/vendor/github.com/open-ness/EMCO/src/orchestrator/pkg/infra/rpc/rpc.go [deleted file]
central-controller/src/vendor/gitlab.com/project-emco/core/emco-base/src/go.mod [new file with mode: 0644]
central-controller/src/vendor/gitlab.com/project-emco/core/emco-base/src/orchestrator/go.mod [new file with mode: 0644]
central-controller/src/vendor/gitlab.com/project-emco/core/emco-base/src/orchestrator/pkg/appcontext/appcontext.go [moved from central-controller/src/vendor/github.com/open-ness/EMCO/src/orchestrator/pkg/appcontext/appcontext.go with 88% similarity]
central-controller/src/vendor/gitlab.com/project-emco/core/emco-base/src/orchestrator/pkg/appcontext/appcontext_test.go [moved from central-controller/src/vendor/github.com/open-ness/EMCO/src/orchestrator/pkg/appcontext/appcontext_test.go with 100% similarity]
central-controller/src/vendor/gitlab.com/project-emco/core/emco-base/src/orchestrator/pkg/appcontext/subresources/approval.go [new file with mode: 0644]
central-controller/src/vendor/gitlab.com/project-emco/core/emco-base/src/orchestrator/pkg/grpc/contextupdate/contextupdate.pb.go [moved from central-controller/src/vendor/github.com/open-ness/EMCO/src/orchestrator/pkg/grpc/contextupdate/contextupdate.pb.go with 100% similarity]
central-controller/src/vendor/gitlab.com/project-emco/core/emco-base/src/orchestrator/pkg/grpc/contextupdate/contextupdate.proto [moved from central-controller/src/vendor/github.com/open-ness/EMCO/src/orchestrator/pkg/grpc/contextupdate/contextupdate.proto with 100% similarity]
central-controller/src/vendor/gitlab.com/project-emco/core/emco-base/src/orchestrator/pkg/grpc/contextupdateclient/client.go [moved from central-controller/src/vendor/github.com/open-ness/EMCO/src/orchestrator/pkg/grpc/contextupdateclient/client.go with 74% similarity]
central-controller/src/vendor/gitlab.com/project-emco/core/emco-base/src/orchestrator/pkg/grpc/installappclient/client.go [moved from central-controller/src/vendor/github.com/open-ness/EMCO/src/orchestrator/pkg/grpc/installappclient/client.go with 93% similarity]
central-controller/src/vendor/gitlab.com/project-emco/core/emco-base/src/orchestrator/pkg/grpc/register.go [new file with mode: 0644]
central-controller/src/vendor/gitlab.com/project-emco/core/emco-base/src/orchestrator/pkg/grpc/statusnotify/statusnotify.pb.go [new file with mode: 0644]
central-controller/src/vendor/gitlab.com/project-emco/core/emco-base/src/orchestrator/pkg/grpc/statusnotify/statusnotify.proto [new file with mode: 0644]
central-controller/src/vendor/gitlab.com/project-emco/core/emco-base/src/orchestrator/pkg/infra/apierror/apierror.go [new file with mode: 0644]
central-controller/src/vendor/gitlab.com/project-emco/core/emco-base/src/orchestrator/pkg/infra/auth/auth.go [moved from central-controller/src/vendor/github.com/open-ness/EMCO/src/orchestrator/pkg/infra/auth/auth.go with 100% similarity]
central-controller/src/vendor/gitlab.com/project-emco/core/emco-base/src/orchestrator/pkg/infra/auth/auth_test.go [moved from central-controller/src/vendor/github.com/open-ness/EMCO/src/orchestrator/pkg/infra/auth/auth_test.go with 100% similarity]
central-controller/src/vendor/gitlab.com/project-emco/core/emco-base/src/orchestrator/pkg/infra/config/config.go [moved from central-controller/src/vendor/github.com/open-ness/EMCO/src/orchestrator/pkg/infra/config/config.go with 67% similarity]
central-controller/src/vendor/gitlab.com/project-emco/core/emco-base/src/orchestrator/pkg/infra/config/config_test.go [new file with mode: 0644]
central-controller/src/vendor/gitlab.com/project-emco/core/emco-base/src/orchestrator/pkg/infra/contextdb/contextdb.go [moved from central-controller/src/vendor/github.com/open-ness/EMCO/src/orchestrator/pkg/infra/contextdb/contextdb.go with 95% similarity]
central-controller/src/vendor/gitlab.com/project-emco/core/emco-base/src/orchestrator/pkg/infra/contextdb/etcd.go [moved from central-controller/src/vendor/github.com/open-ness/EMCO/src/orchestrator/pkg/infra/contextdb/etcd.go with 100% similarity]
central-controller/src/vendor/gitlab.com/project-emco/core/emco-base/src/orchestrator/pkg/infra/contextdb/etcd_test.go [moved from central-controller/src/vendor/github.com/open-ness/EMCO/src/orchestrator/pkg/infra/contextdb/etcd_test.go with 100% similarity]
central-controller/src/vendor/gitlab.com/project-emco/core/emco-base/src/orchestrator/pkg/infra/contextdb/mock.go [moved from central-controller/src/vendor/github.com/open-ness/EMCO/src/orchestrator/pkg/infra/contextdb/mock.go with 57% similarity]
central-controller/src/vendor/gitlab.com/project-emco/core/emco-base/src/orchestrator/pkg/infra/db/README.md [moved from central-controller/src/vendor/github.com/open-ness/EMCO/src/orchestrator/pkg/infra/db/README.md with 89% similarity]
central-controller/src/vendor/gitlab.com/project-emco/core/emco-base/src/orchestrator/pkg/infra/db/db_suite_test.go [new file with mode: 0644]
central-controller/src/vendor/gitlab.com/project-emco/core/emco-base/src/orchestrator/pkg/infra/db/mock.go [moved from central-controller/src/vendor/github.com/open-ness/EMCO/src/orchestrator/pkg/infra/db/mock.go with 77% similarity]
central-controller/src/vendor/gitlab.com/project-emco/core/emco-base/src/orchestrator/pkg/infra/db/mongo.go [new file with mode: 0644]
central-controller/src/vendor/gitlab.com/project-emco/core/emco-base/src/orchestrator/pkg/infra/db/mongo_test.go [moved from central-controller/src/vendor/github.com/open-ness/EMCO/src/orchestrator/pkg/infra/db/mongo_test.go with 100% similarity]
central-controller/src/vendor/gitlab.com/project-emco/core/emco-base/src/orchestrator/pkg/infra/db/newmock.go [new file with mode: 0644]
central-controller/src/vendor/gitlab.com/project-emco/core/emco-base/src/orchestrator/pkg/infra/db/schema.go [new file with mode: 0644]
central-controller/src/vendor/gitlab.com/project-emco/core/emco-base/src/orchestrator/pkg/infra/db/schema_mock.go [new file with mode: 0644]
central-controller/src/vendor/gitlab.com/project-emco/core/emco-base/src/orchestrator/pkg/infra/db/schema_test.go [new file with mode: 0644]
central-controller/src/vendor/gitlab.com/project-emco/core/emco-base/src/orchestrator/pkg/infra/db/store.go [moved from central-controller/src/vendor/github.com/open-ness/EMCO/src/orchestrator/pkg/infra/db/store.go with 94% similarity]
central-controller/src/vendor/gitlab.com/project-emco/core/emco-base/src/orchestrator/pkg/infra/db/store_test.go [moved from central-controller/src/vendor/github.com/open-ness/EMCO/src/orchestrator/pkg/infra/db/store_test.go with 100% similarity]
central-controller/src/vendor/gitlab.com/project-emco/core/emco-base/src/orchestrator/pkg/infra/db/test-schemas/duplicate-resource.yaml [new file with mode: 0644]
central-controller/src/vendor/gitlab.com/project-emco/core/emco-base/src/orchestrator/pkg/infra/db/test-schemas/duplicate-schema.yaml [new file with mode: 0644]
central-controller/src/vendor/gitlab.com/project-emco/core/emco-base/src/orchestrator/pkg/infra/db/test-schemas/emco-base.yaml [new file with mode: 0644]
central-controller/src/vendor/gitlab.com/project-emco/core/emco-base/src/orchestrator/pkg/infra/db/test-schemas/invalid-resource-name.yaml [new file with mode: 0644]
central-controller/src/vendor/gitlab.com/project-emco/core/emco-base/src/orchestrator/pkg/infra/db/test-schemas/invalid-schema.yaml [new file with mode: 0644]
central-controller/src/vendor/gitlab.com/project-emco/core/emco-base/src/orchestrator/pkg/infra/db/test-schemas/loop.yaml [new file with mode: 0644]
central-controller/src/vendor/gitlab.com/project-emco/core/emco-base/src/orchestrator/pkg/infra/db/test-schemas/missing-name.yaml [new file with mode: 0644]
central-controller/src/vendor/gitlab.com/project-emco/core/emco-base/src/orchestrator/pkg/infra/db/test-schemas/missing-parent.yaml [new file with mode: 0644]
central-controller/src/vendor/gitlab.com/project-emco/core/emco-base/src/orchestrator/pkg/infra/db/test-schemas/missing-resource.yaml [new file with mode: 0644]
central-controller/src/vendor/gitlab.com/project-emco/core/emco-base/src/orchestrator/pkg/infra/db/test-schemas/new-controller.yaml [new file with mode: 0644]
central-controller/src/vendor/gitlab.com/project-emco/core/emco-base/src/orchestrator/pkg/infra/logutils/logger.go [moved from central-controller/src/vendor/github.com/open-ness/EMCO/src/orchestrator/pkg/infra/logutils/logger.go with 96% similarity]
central-controller/src/vendor/gitlab.com/project-emco/core/emco-base/src/orchestrator/pkg/infra/rpc/rpc.go [new file with mode: 0644]
central-controller/src/vendor/gitlab.com/project-emco/core/emco-base/src/orchestrator/pkg/infra/rpc/rpc_test.go [new file with mode: 0644]
central-controller/src/vendor/gitlab.com/project-emco/core/emco-base/src/orchestrator/pkg/infra/utils/objectencryptor.go [new file with mode: 0644]
central-controller/src/vendor/gitlab.com/project-emco/core/emco-base/src/orchestrator/pkg/infra/utils/utils.go [moved from central-controller/src/vendor/github.com/open-ness/EMCO/src/orchestrator/pkg/infra/utils/utils.go with 100% similarity]
central-controller/src/vendor/gitlab.com/project-emco/core/emco-base/src/orchestrator/pkg/infra/validation/validation.go [moved from central-controller/src/vendor/github.com/open-ness/EMCO/src/orchestrator/pkg/infra/validation/validation.go with 97% similarity]
central-controller/src/vendor/gitlab.com/project-emco/core/emco-base/src/orchestrator/pkg/infra/validation/validation_test.go [moved from central-controller/src/vendor/github.com/open-ness/EMCO/src/orchestrator/pkg/infra/validation/validation_test.go with 100% similarity]
central-controller/src/vendor/gitlab.com/project-emco/core/emco-base/src/orchestrator/pkg/module/controller/controller.go [moved from central-controller/src/vendor/github.com/open-ness/EMCO/src/orchestrator/pkg/module/controller/controller.go with 78% similarity]
central-controller/src/vendor/gitlab.com/project-emco/core/emco-base/src/orchestrator/pkg/module/controller/controller_test.go [moved from central-controller/src/vendor/github.com/open-ness/EMCO/src/orchestrator/pkg/module/controller/controller_test.go with 80% similarity]
central-controller/src/vendor/gitlab.com/project-emco/core/emco-base/src/orchestrator/pkg/module/types/cluster.go [new file with mode: 0644]
central-controller/src/vendor/gitlab.com/project-emco/core/emco-base/src/orchestrator/pkg/module/types/types.go [moved from central-controller/src/vendor/github.com/open-ness/EMCO/src/orchestrator/pkg/module/types/types.go with 94% similarity]
central-controller/src/vendor/gitlab.com/project-emco/core/emco-base/src/orchestrator/pkg/resourcestatus/resourcestatus.go [moved from central-controller/src/vendor/github.com/open-ness/EMCO/src/orchestrator/pkg/resourcestatus/resourcestatus.go with 100% similarity]
central-controller/src/vendor/gitlab.com/project-emco/core/emco-base/src/orchestrator/pkg/rtcontext/rtcontext.go [moved from central-controller/src/vendor/github.com/open-ness/EMCO/src/orchestrator/pkg/rtcontext/rtcontext.go with 98% similarity]
central-controller/src/vendor/gitlab.com/project-emco/core/emco-base/src/orchestrator/pkg/rtcontext/rtcontext_test.go [moved from central-controller/src/vendor/github.com/open-ness/EMCO/src/orchestrator/pkg/rtcontext/rtcontext_test.go with 99% similarity]
platform/cnf-openwrt/src/rest_v1/app_rest.lua
platform/cnf-openwrt/src/rest_v1/fw_rest.lua [new file with mode: 0644]
platform/cnf-openwrt/src/rest_v1/index.lua
platform/crd-ctrlr/src/api/v1alpha1/bucket_permission_webhook.go
platform/crd-ctrlr/src/api/v1alpha1/cnfhubsite_types.go [new file with mode: 0644]
platform/crd-ctrlr/src/api/v1alpha1/cnfservice_types.go
platform/crd-ctrlr/src/api/v1alpha1/label_validate_webhook.go
platform/crd-ctrlr/src/api/v1alpha1/networkfirewallrule_types.go [new file with mode: 0644]
platform/crd-ctrlr/src/api/v1alpha1/zz_generated.deepcopy.go
platform/crd-ctrlr/src/config/crd/bases/batch.sdewan.akraino.org_cnfhubsites.yaml [new file with mode: 0644]
platform/crd-ctrlr/src/config/crd/bases/batch.sdewan.akraino.org_networkfirewallrules.yaml [new file with mode: 0644]
platform/crd-ctrlr/src/config/crd/kustomization.yaml
platform/crd-ctrlr/src/config/rbac/role.yaml
platform/crd-ctrlr/src/config/webhook/manifests.yaml
platform/crd-ctrlr/src/controllers/cnfhubsite_controller.go [new file with mode: 0644]
platform/crd-ctrlr/src/controllers/cnfservice_controller.go
platform/crd-ctrlr/src/controllers/networkfirewallrule_controller.go [new file with mode: 0644]
platform/crd-ctrlr/src/main.go
platform/crd-ctrlr/src/openwrt/networkfirewall.go [new file with mode: 0644]
platform/deployment/helm/sdewan_controllers/templates/crd.yaml
platform/deployment/helm/sdewan_controllers/templates/role.yaml
platform/deployment/helm/sdewan_controllers/templates/webhook.yaml

index 578f935..06fdfcf 100644 (file)
--- a/README.md
+++ b/README.md
@@ -1,3 +1,8 @@
+**NOTICE: This is a PreProd version.**
+
+**We are actively working on this to make it for Prod release. For now, please DO NOT use it for any Prod environment!**
+
+
 # Introduction to Akraino ICN SD-EWAN solution
 
 SD-EWAN main functionality include
@@ -44,6 +49,34 @@ central-controller's high level design can be found at: https://www.linkedin.com
 - [End2End](https://wiki.akraino.org/display/AK/ICN+R3+Test+Document#ICNR3TestDocument-SDEWAN)
 - [Validation Result](https://wiki.akraino.org/display/AK/ICN+R3+Test+Document#ICNR3TestDocument-BluValTesting)
 
+## Environment Settings Recommendations
+To make our project work for your solution, please do the environment settings following the best practices that are widely known by the communities and industries.
+
+### Docker Image Usage
+Please follow the best know practices of Docker in your development lifecycle that will give you more productivity and security.
+
+- [Development Best Practices](https://docs.docker.com/develop/dev-best-practices/)
+- [Image Build Best Practices](https://docs.docker.com/get-started/09_image_best/)
+- [Only Use Trusted Registry Service Like Docker Hub](https://docs.docker.com/docker-hub/)
+- [Using Docker Hub for CI CD](https://docs.docker.com/ci-cd/best-practices/)
+
+### Etcd
+Etcd is a is a strongly consistent, distributed key-value store. It's a critical Kubernetes component which stores information on state and secrets, and it should be protected differently from the rest of your cluster. Administrators should always use strong credentials from the API servers to their etcd server, such as mutual auth via TLS client certificates, and it is often recommended to isolate the etcd servers behind a firewall that only the API servers may access.
+
+Access to etcd (the datastore of Kubernetes) should be limited to the control plane only. Depending on your configuration, you should attempt to use etcd over TLS. More information can be found in the [etcd documentation](https://github.com/etcd-io/etcd/tree/master/Documentation).
+
+Wherever possible, it's a good practice to encrypt all storage at rest. Since etcd holds the state of the entire cluster (including Secrets) its disk should especially be encrypted at rest. e.g. [Kubernetes documentation on encrypting data at rest](https://kubernetes.io/docs/tasks/administer-cluster/encrypt-data/)
+
+
+### MongoDB
+Please follow the best known practices of MongoDB
+- [Basic Practices](https://www.mongodb.com/basics/best-practices)
+- [Security Manual](https://www.mongodb.com/docs/manual/security/)
+- [Encrypt Data At Rest](https://www.mongodb.com/docs/manual/core/security-encryption-at-rest/)
+
+### Istio
+Our project can be used with Istio to enable a secure running environment. Please follow the general practice of [the Istio Service Mesh](https://istio.io/latest/about/service-mesh/) and [Istio / Security](https://istio.io/latest/docs/concepts/security/) to complete the settings for your own solution. In addition to that, in order to get a general idea or quick impression about the usage, you can also reference our introduction to a [demo](https://github.com/intel-sandbox/akraino-sdewan/tree/main/central-controller/docs/istio). 
+
 ## Contact Us
 
 For any questions about ovn4nfv k8s , feel free to ask a question in
index 81173f6..0f5b03b 100644 (file)
@@ -25,6 +25,7 @@ RUN addgroup -S scc && adduser -S -G scc scc
 RUN chown scc:scc /opt/scc -R
 
 COPY --chown=scc --from=0 /go/src/github.com/central-controller/src/scc/scc ./
+COPY --chown=scc --from=0 /go/src/github.com/central-controller/src/scc/ref-schemas ./ref-schemas/
 COPY --chown=scc --from=0 /go/src/github.com/central-controller/src/rsync/rsync ./
 COPY --chown=scc --from=0 /go/src/github.com/central-controller/src/monitor/monitor ./
 COPY --chown=scc --from=0 /go/src/github.com/central-controller/build/entrypoint ./
index 4a12721..5e14c39 100644 (file)
@@ -13,7 +13,9 @@
 
 **2. Create Databases used by SDEWAN Central Controller v1 Microservices for Etcd and Mongo**
 
-`$ kubectl apply -f scc_db.yaml -n sdewan-system`
+`$ kubectl apply -f scc_secret.yaml -n sdewan-system`
+`$ kubectl apply -f scc_etcd.yaml -n sdewan-system`
+`$ kubectl apply -f scc_mongo.yaml -n sdewan-system`
 
 **3. create SDEWAN Central Controller v1 Microservices**
 
@@ -23,4 +25,4 @@
 
 **4. install monitor resources**
 
-`$ ./monitor-deploy.sh`
+`$ kubectl apply -f monitor-deploy.yaml -n sdewan-sysyem`
diff --git a/central-controller/deployments/kubernetes/monitor-deploy.sh b/central-controller/deployments/kubernetes/monitor-deploy.sh
deleted file mode 100644 (file)
index 77dbef6..0000000
+++ /dev/null
@@ -1,7 +0,0 @@
-kubectl apply -f monitor/crds/k8splugin_v1alpha1_resourcebundlestate_crd.yaml
-kubectl apply -f monitor/role.yaml
-kubectl apply -f monitor/cluster_role.yaml
-kubectl apply -f monitor/role_binding.yaml
-kubectl apply -f monitor/clusterrole_binding.yaml
-kubectl apply -f monitor/service_account.yaml
-kubectl apply -f monitor/operator.yaml
diff --git a/central-controller/deployments/kubernetes/monitor-deploy.yaml b/central-controller/deployments/kubernetes/monitor-deploy.yaml
new file mode 100644 (file)
index 0000000..d459330
--- /dev/null
@@ -0,0 +1,340 @@
+# SPDX-License-Identifier: Apache-2.0
+# Copyright (c) 2020 Intel Corporation
+---
+apiVersion: rbac.authorization.k8s.io/v1
+kind: Role
+metadata:
+  creationTimestamp: null
+  name: monitor
+rules:
+- apiGroups:
+  - ""
+  resources:
+  - pods
+  - services
+  - endpoints
+  - persistentvolumeclaims
+  - events
+  - configmaps
+  - secrets
+  verbs:
+  - '*'
+- apiGroups:
+  - apps
+  resources:
+  - deployments
+  - daemonsets
+  - replicasets
+  - statefulsets
+  verbs:
+  - '*'
+- apiGroups:
+  - monitoring.coreos.com
+  resources:
+  - servicemonitors
+  verbs:
+  - get
+  - create
+- apiGroups:
+  - apps
+  resourceNames:
+  - monitor
+  resources:
+  - deployments/finalizers
+  verbs:
+  - update
+- apiGroups:
+  - ""
+  resources:
+  - pods
+  verbs:
+  - get
+- apiGroups:
+  - apps
+  resources:
+  - replicasets
+  verbs:
+  - get
+- apiGroups:
+  - k8splugin.io
+  resources:
+  - '*'
+  verbs:
+  - '*'
+- apiGroups:
+  - batch
+  resources:
+  - '*'
+  verbs:
+  - '*'
+- apiGroups:
+  - extensions
+  resources:
+  - '*'
+  verbs:
+  - '*'
+- apiGroups:
+  - certificates.k8s.io
+  resources:
+  - '*'
+  verbs:
+  - '*'
+
+---
+apiVersion: rbac.authorization.k8s.io/v1
+kind: ClusterRole
+metadata:
+  creationTimestamp: null
+  name: monitor
+rules:
+- apiGroups:
+  - ""
+  resources:
+  - pods
+  - services
+  - endpoints
+  - persistentvolumeclaims
+  - events
+  - configmaps
+  - secrets
+  - resourcequotas
+  verbs:
+  - '*'
+- apiGroups:
+  - apps
+  resources:
+  - deployments
+  - daemonsets
+  - replicasets
+  - statefulsets
+  verbs:
+  - '*'
+- apiGroups:
+  - monitoring.coreos.com
+  resources:
+  - servicemonitors
+  verbs:
+  - get
+  - create
+- apiGroups:
+  - apps
+  resourceNames:
+  - monitor
+  resources:
+  - deployments/finalizers
+  verbs:
+  - update
+- apiGroups:
+  - ""
+  resources:
+  - pods
+  verbs:
+  - get
+- apiGroups:
+  - apps
+  resources:
+  - replicasets
+  verbs:
+  - get
+- apiGroups:
+  - k8splugin.io
+  resources:
+  - '*'
+  verbs:
+  - '*'
+- apiGroups:
+  - batch
+  resources:
+  - '*'
+  verbs:
+  - '*'
+- apiGroups:
+  - extensions
+  resources:
+  - '*'
+  verbs:
+  - '*'
+- apiGroups:
+  - rbac.authorization.k8s.io
+  resources:
+  - '*'
+  verbs:
+  - '*'
+- apiGroups:
+  - certificates.k8s.io
+  resources:
+  - '*'
+  verbs:
+  - '*'
+
+---
+kind: RoleBinding
+apiVersion: rbac.authorization.k8s.io/v1
+metadata:
+  name: monitor
+subjects:
+- kind: ServiceAccount
+  name: monitor
+roleRef:
+  kind: Role
+  name: monitor
+  apiGroup: rbac.authorization.k8s.io
+
+---
+kind: ClusterRoleBinding
+apiVersion: rbac.authorization.k8s.io/v1
+metadata:
+  name: monitor
+subjects:
+- kind: ServiceAccount
+  name: monitor
+  namespace: default
+roleRef:
+  kind: ClusterRole
+  name: monitor
+  apiGroup: rbac.authorization.k8s.io
+
+---
+apiVersion: v1
+kind: ServiceAccount
+metadata:
+  name: monitor
+
+---
+apiVersion: apps/v1
+kind: Deployment
+metadata:
+  name: monitor
+  labels:
+    "emco/deployment-id": "monitor"
+spec:
+  replicas: 1
+  selector:
+    matchLabels:
+      "emco/deployment-id": "monitor"
+  template:
+    metadata:
+      labels:
+        "emco/deployment-id": "monitor"
+    spec:
+      serviceAccountName: monitor
+      containers:
+        - name: monitor
+          # Replace this with the built image name
+          image: scc:latest
+          command: ["/opt/scc/entrypoint", "monitor"]
+          imagePullPolicy: IfNotPresent
+          env:
+            - name: WATCH_NAMESPACE
+              value: ""
+            - name: POD_NAME
+              valueFrom:
+                fieldRef:
+                  fieldPath: metadata.name
+            - name: OPERATOR_NAME
+              value: "monitor"
+
+---
+apiVersion: apiextensions.k8s.io/v1
+kind: CustomResourceDefinition
+metadata:
+  name: resourcebundlestates.k8splugin.io
+spec:
+  group: k8splugin.io
+  names:
+    kind: ResourceBundleState
+    listKind: ResourceBundleStateList
+    plural: resourcebundlestates
+    singular: resourcebundlestate
+  scope: Namespaced
+  versions:
+  - name: v1alpha1
+    schema:
+      openAPIV3Schema:
+        properties:
+          apiVersion:
+            description: 'APIVersion defines the versioned schema of this representation
+            of an object. Servers should convert recognized schemas to the latest
+            internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/api-conventions.md#resources'
+            type: string
+          kind:
+            description: 'Kind is a string value representing the REST resource this
+            object represents. Servers may infer this from the endpoint the client
+              submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/api-conventions.md#types-kinds'
+            type: string
+          metadata:
+            type: object
+          spec:
+            properties:
+              selector:
+                type: object
+            required:
+            - selector
+            type: object
+          status:
+            properties:
+              podStatuses:
+                items:
+                  type: object
+                type: array
+              ready:
+                type: boolean
+              resourceCount:
+                format: int32
+                type: integer
+              serviceStatuses:
+                items:
+                  type: object
+                type: array
+              configMapStatuses:
+                items:
+                  type: object
+                type: array
+              deploymentStatuses:
+                items:
+                  type: object
+                type: array
+              secretStatuses:
+                items:
+                  type: object
+                type: array
+              daemonSetStatuses:
+                items:
+                  type: object
+                type: array
+              ingressStatuses:
+                items:
+                  type: object
+                type: array
+              jobStatuses:
+                items:
+                  type: object
+                type: array
+              statefulSetStatuses:
+                items:
+                  type: object
+                type: array
+              csrStatuses:
+                items:
+                  type: object
+                type: array
+            required:
+            - ready
+            - resourceCount
+            - podStatuses
+            - serviceStatuses
+            - configMapStatuses
+            - deploymentStatuses
+            - secretStatuses
+            - daemonSetStatuses
+            - ingressStatuses
+            - jobStatuses
+            - statefulSetStatuses
+            - csrStatuses
+            type: object
+        type: object
+    served: true
+    storage: true
+    subresources:
+      status: {}
diff --git a/central-controller/deployments/kubernetes/monitor-undeploy.sh b/central-controller/deployments/kubernetes/monitor-undeploy.sh
deleted file mode 100644 (file)
index 7d75a2e..0000000
+++ /dev/null
@@ -1,7 +0,0 @@
-kubectl delete -f monitor/crds/k8splugin_v1alpha1_resourcebundlestate_crd.yaml
-kubectl delete -f monitor/role.yaml
-kubectl delete -f monitor/cluster_role.yaml
-kubectl delete -f monitor/role_binding.yaml
-kubectl delete -f monitor/clusterrole_binding.yaml
-kubectl delete -f monitor/service_account.yaml
-kubectl delete -f monitor/operator.yaml
diff --git a/central-controller/deployments/kubernetes/monitor/cluster_role.yaml b/central-controller/deployments/kubernetes/monitor/cluster_role.yaml
deleted file mode 100644 (file)
index 9330a68..0000000
+++ /dev/null
@@ -1,78 +0,0 @@
-apiVersion: rbac.authorization.k8s.io/v1
-kind: ClusterRole
-metadata:
-  creationTimestamp: null
-  name: monitor
-rules:
-- apiGroups:
-  - ""
-  resources:
-  - pods
-  - services
-  - endpoints
-  - persistentvolumeclaims
-  - events
-  - configmaps
-  - secrets
-  verbs:
-  - '*'
-- apiGroups:
-  - apps
-  resources:
-  - deployments
-  - daemonsets
-  - replicasets
-  - statefulsets
-  verbs:
-  - '*'
-- apiGroups:
-  - monitoring.coreos.com
-  resources:
-  - servicemonitors
-  verbs:
-  - get
-  - create
-- apiGroups:
-  - apps
-  resourceNames:
-  - monitor
-  resources:
-  - deployments/finalizers
-  verbs:
-  - update
-- apiGroups:
-  - ""
-  resources:
-  - pods
-  verbs:
-  - get
-- apiGroups:
-  - apps
-  resources:
-  - replicasets
-  verbs:
-  - get
-- apiGroups:
-  - k8splugin.io
-  resources:
-  - '*'
-  verbs:
-  - '*'
-- apiGroups:
-  - batch
-  resources:
-  - '*'
-  verbs:
-  - '*'
-- apiGroups:
-  - extensions
-  resources:
-  - '*'
-  verbs:
-  - '*'
-- apiGroups:
-  - certificates.k8s.io
-  resources:
-  - '*'
-  verbs:
-  - '*'
diff --git a/central-controller/deployments/kubernetes/monitor/clusterrole_binding.yaml b/central-controller/deployments/kubernetes/monitor/clusterrole_binding.yaml
deleted file mode 100644 (file)
index 73e7403..0000000
+++ /dev/null
@@ -1,12 +0,0 @@
-kind: ClusterRoleBinding
-apiVersion: rbac.authorization.k8s.io/v1
-metadata:
-  name: monitor
-subjects:
-- kind: ServiceAccount
-  name: monitor
-  namespace: default
-roleRef:
-  kind: ClusterRole
-  name: monitor
-  apiGroup: rbac.authorization.k8s.io
diff --git a/central-controller/deployments/kubernetes/monitor/crds/k8splugin_v1alpha1_resourcebundlestate_cr.yaml b/central-controller/deployments/kubernetes/monitor/crds/k8splugin_v1alpha1_resourcebundlestate_cr.yaml
deleted file mode 100644 (file)
index 86fe055..0000000
+++ /dev/null
@@ -1,12 +0,0 @@
-apiVersion: k8splugin.io/v1alpha1
-kind: ResourceBundleState
-metadata:
-  name: example-resourcebundlestate
-  labels:
-    "emco/deployment-id": "bionic-beaver"
-spec:
-  selector:
-    matchLabels:
-      "emco/deployment-id": "bionic-beaver"
-status:
-  ready: false
diff --git a/central-controller/deployments/kubernetes/monitor/crds/k8splugin_v1alpha1_resourcebundlestate_crd.yaml b/central-controller/deployments/kubernetes/monitor/crds/k8splugin_v1alpha1_resourcebundlestate_crd.yaml
deleted file mode 100644 (file)
index 4ae37c9..0000000
+++ /dev/null
@@ -1,102 +0,0 @@
-apiVersion: apiextensions.k8s.io/v1
-kind: CustomResourceDefinition
-metadata:
-  name: resourcebundlestates.k8splugin.io
-spec:
-  group: k8splugin.io
-  names:
-    kind: ResourceBundleState
-    listKind: ResourceBundleStateList
-    plural: resourcebundlestates
-    singular: resourcebundlestate
-  scope: Namespaced
-  versions:
-  - name: v1alpha1
-    schema:
-      openAPIV3Schema:
-        properties:
-          apiVersion:
-            description: 'APIVersion defines the versioned schema of this representation
-            of an object. Servers should convert recognized schemas to the latest
-            internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/api-conventions.md#resources'
-            type: string
-          kind:
-            description: 'Kind is a string value representing the REST resource this
-            object represents. Servers may infer this from the endpoint the client
-              submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/api-conventions.md#types-kinds'
-            type: string
-          metadata:
-            type: object
-          spec:
-            properties:
-              selector:
-                type: object
-            required:
-            - selector
-            type: object
-          status:
-            properties:
-              podStatuses:
-                items:
-                  type: object
-                type: array
-              ready:
-                type: boolean
-              resourceCount:
-                format: int32
-                type: integer
-              serviceStatuses:
-                items:
-                  type: object
-                type: array
-              configMapStatuses:
-                items:
-                  type: object
-                type: array
-              deploymentStatuses:
-                items:
-                  type: object
-                type: array
-              secretStatuses:
-                items:
-                  type: object
-                type: array
-              daemonSetStatuses:
-                items:
-                  type: object
-                type: array
-              ingressStatuses:
-                items:
-                  type: object
-                type: array
-              jobStatuses:
-                items:
-                  type: object
-                type: array
-              statefulSetStatuses:
-                items:
-                  type: object
-                type: array
-              csrStatuses:
-                items:
-                  type: object
-                type: array
-            required:
-            - ready
-            - resourceCount
-            - podStatuses
-            - serviceStatuses
-            - configMapStatuses
-            - deploymentStatuses
-            - secretStatuses
-            - daemonSetStatuses
-            - ingressStatuses
-            - jobStatuses
-            - statefulSetStatuses
-            - csrStatuses
-            type: object
-        type: object
-    served: true
-    storage: true
-    subresources:
-      status: {}
diff --git a/central-controller/deployments/kubernetes/monitor/monitor-cleanup.sh b/central-controller/deployments/kubernetes/monitor/monitor-cleanup.sh
deleted file mode 100644 (file)
index 2172507..0000000
+++ /dev/null
@@ -1,6 +0,0 @@
-kubectl delete rolebinding monitor
-kubectl delete clusterrolebinding monitor
-kubectl delete role monitor
-kubectl delete clusterrole monitor
-kubectl delete serviceaccount monitor
-kubectl delete deploy monitor
diff --git a/central-controller/deployments/kubernetes/monitor/operator.yaml b/central-controller/deployments/kubernetes/monitor/operator.yaml
deleted file mode 100644 (file)
index 2c69345..0000000
+++ /dev/null
@@ -1,32 +0,0 @@
-apiVersion: apps/v1
-kind: Deployment
-metadata:
-  name: monitor
-  labels:
-    "emco/deployment-id": "monitor"
-spec:
-  replicas: 1
-  selector:
-    matchLabels:
-      "emco/deployment-id": "monitor"
-  template:
-    metadata:
-      labels:
-        "emco/deployment-id": "monitor"
-    spec:
-      serviceAccountName: monitor
-      containers:
-        - name: monitor
-          # Replace this with the built image name
-          image: scc:latest
-          command: ["/opt/scc/entrypoint", "monitor"]
-          imagePullPolicy: IfNotPresent
-          env:
-            - name: WATCH_NAMESPACE
-              value: ""
-            - name: POD_NAME
-              valueFrom:
-                fieldRef:
-                  fieldPath: metadata.name
-            - name: OPERATOR_NAME
-              value: "monitor"
diff --git a/central-controller/deployments/kubernetes/monitor/role.yaml b/central-controller/deployments/kubernetes/monitor/role.yaml
deleted file mode 100644 (file)
index c48141a..0000000
+++ /dev/null
@@ -1,72 +0,0 @@
-apiVersion: rbac.authorization.k8s.io/v1
-kind: Role
-metadata:
-  creationTimestamp: null
-  name: monitor
-rules:
-- apiGroups:
-  - ""
-  resources:
-  - pods
-  - services
-  - endpoints
-  - persistentvolumeclaims
-  - events
-  - configmaps
-  - secrets
-  verbs:
-  - '*'
-- apiGroups:
-  - apps
-  resources:
-  - deployments
-  - daemonsets
-  - replicasets
-  - statefulsets
-  verbs:
-  - '*'
-- apiGroups:
-  - monitoring.coreos.com
-  resources:
-  - servicemonitors
-  verbs:
-  - get
-  - create
-- apiGroups:
-  - apps
-  resourceNames:
-  - monitor
-  resources:
-  - deployments/finalizers
-  verbs:
-  - update
-- apiGroups:
-  - ""
-  resources:
-  - pods
-  verbs:
-  - get
-- apiGroups:
-  - apps
-  resources:
-  - replicasets
-  verbs:
-  - get
-- apiGroups:
-  - k8splugin.io
-  resources:
-  - '*'
-  verbs:
-  - '*'
-- apiGroups:
-  - batch
-  resources:
-  - '*'
-  verbs:
-  - '*'
-- apiGroups:
-  - extensions
-  resources:
-  - '*'
-  verbs:
-  - '*'
diff --git a/central-controller/deployments/kubernetes/monitor/role_binding.yaml b/central-controller/deployments/kubernetes/monitor/role_binding.yaml
deleted file mode 100644 (file)
index 69cd293..0000000
+++ /dev/null
@@ -1,11 +0,0 @@
-kind: RoleBinding
-apiVersion: rbac.authorization.k8s.io/v1
-metadata:
-  name: monitor
-subjects:
-- kind: ServiceAccount
-  name: monitor
-roleRef:
-  kind: Role
-  name: monitor
-  apiGroup: rbac.authorization.k8s.io
diff --git a/central-controller/deployments/kubernetes/monitor/service_account.yaml b/central-controller/deployments/kubernetes/monitor/service_account.yaml
deleted file mode 100644 (file)
index ba9b61c..0000000
+++ /dev/null
@@ -1,4 +0,0 @@
-apiVersion: v1
-kind: ServiceAccount
-metadata:
-  name: monitor
index 421f783..6e5c336 100644 (file)
@@ -32,7 +32,7 @@ data:
   rsync_config.json: |
           {
           "rsync-ip": "rsync",
-          "rsync-port": "9041"
+          "rsync-port": "9031"
           }
 
 ---
@@ -85,6 +85,26 @@ spec:
           - name: rsync-config
             mountPath: /opt/scc/rsync_config.json
             subPath: rsync_config.json
+          env:
+          - name: DB_EMCO_USERNAME
+            value: "scc"
+          - name: DB_EMCO_PASSWORD
+            valueFrom:
+              secretKeyRef:
+                name: mongo-secret
+                key: userPassword
+          - name: CONTEXTDB_EMCO_USERNAME
+            value: "scc"
+          - name: CONTEXTDB_EMCO_PASSWORD
+            valueFrom:
+              secretKeyRef:
+                name: etcd-secret
+                key: userPassword
+          - name: EMCO_DATA_KEY
+            valueFrom:
+              secretKeyRef:
+                name: mongo-data-secret
+                key: key
       volumes:
         - name: config
           configMap:
diff --git a/central-controller/deployments/kubernetes/scc_db.yaml b/central-controller/deployments/kubernetes/scc_db.yaml
deleted file mode 100644 (file)
index cb212b3..0000000
+++ /dev/null
@@ -1,87 +0,0 @@
-# Resources to create Databases used by SDEWAN Central Controller v1 Microservices
----
-#Etcd Service
-apiVersion: v1
-kind: Service
-metadata:
-  labels:
-    app: etcd
-  name: etcd
-spec:
-  ports:
-  - name: "2379"
-    port: 2379
-    targetPort: 2379
-  - name: "2380"
-    port: 2380
-    targetPort: 2380
-  selector:
-    app: etcd
-
----
-#Mongo Service
-apiVersion: v1
-kind: Service
-metadata:
-  labels:
-    app: mongo
-  name: mongo
-spec:
-  ports:
-  - name: "27017"
-    port: 27017
-    targetPort: 27017
-  selector:
-    app: mongo
-
----
-#Etcd Deployment
-apiVersion: apps/v1
-kind: Deployment
-metadata:
-  name: etcd
-spec:
-  replicas: 1
-  selector:
-    matchLabels:
-      app: etcd
-  template:
-    metadata:
-      labels:
-        app: etcd
-    spec:
-      containers:
-      - image: bitnami/etcd:3
-        imagePullPolicy: IfNotPresent
-        name: etcd
-        env:
-          - name: "ALLOW_NONE_AUTHENTICATION"
-            value: "yes"
-        ports:
-        - containerPort: 2379
-        - containerPort: 2380
-
----
-#Mongo Deployment
-apiVersion: apps/v1
-kind: Deployment
-metadata:
-  labels:
-    app: mongo
-  name: mongo
-spec:
-  replicas: 1
-  selector:
-    matchLabels:
-      app: mongo
-  template:
-    metadata:
-      labels:
-        app: mongo
-    spec:
-      containers:
-      - image: mongo
-        imagePullPolicy: IfNotPresent
-        name: mongo
-        ports:
-        - containerPort: 27017
diff --git a/central-controller/deployments/kubernetes/scc_etcd.yaml b/central-controller/deployments/kubernetes/scc_etcd.yaml
new file mode 100644 (file)
index 0000000..915d2aa
--- /dev/null
@@ -0,0 +1,96 @@
+# Resources to create context Databases used by SDEWAN Central Controller v1 Microservices\r
+kind: ConfigMap\r
+apiVersion: v1\r
+metadata:\r
+  name: etcd-init\r
+  labels:\r
+    app: etcd\r
+data:\r
+  etcd-setup.sh: |\r
+    until etcdctl version\r
+    do\r
+      sleep 1\r
+    done\r
+    etcdctl user add "$CONTEXTDB_ROOT_USERNAME":"$CONTEXTDB_ROOT_PASSWORD"\r
+    etcdctl user grant-role "$ETCD_ROOT_USER" root\r
+    etcdctl role add emcorole\r
+    etcdctl role grant-permission --prefix=true  emcorole readwrite '/context/'\r
+    etcdctl role grant-permission --prefix=true  emcorole readwrite '/activecontext/'\r
+    etcdctl user add "$CONTEXTDB_EMCO_USERNAME":"$CONTEXTDB_EMCO_PASSWORD"\r
+    etcdctl user grant-role "$CONTEXTDB_EMCO_USERNAME" emcorole\r
+    etcdctl auth enable\r
+\r
+---\r
+# Etcd Service\r
+apiVersion: v1\r
+kind: Service\r
+metadata:\r
+  labels:\r
+    app: etcd\r
+  name: etcd\r
+spec:\r
+  ports:\r
+  - name: "2379"\r
+    port: 2379\r
+    targetPort: 2379\r
+  - name: "2380"\r
+    port: 2380\r
+    targetPort: 2380\r
+  selector:\r
+    app: etcd\r
+\r
+---\r
+#Etcd Deployment\r
+apiVersion: apps/v1\r
+kind: Deployment\r
+metadata:\r
+  name: etcd\r
+spec:\r
+  replicas: 1\r
+  selector:\r
+    matchLabels:\r
+      app: etcd\r
+  template:\r
+    metadata:\r
+      labels:\r
+        app: etcd\r
+    spec:\r
+      containers:\r
+      - image: bitnami/etcd:3\r
+        imagePullPolicy: IfNotPresent\r
+        name: etcd\r
+        env:\r
+          - name: "ALLOW_NONE_AUTHENTICATION"\r
+            value: "yes"\r
+          - name: CONTEXTDB_EMCO_USERNAME\r
+            value: "scc"\r
+          - name: CONTEXTDB_EMCO_PASSWORD\r
+            valueFrom:\r
+              secretKeyRef:\r
+                name: etcd-secret\r
+                key: userPassword\r
+          - name: CONTEXTDB_ROOT_USERNAME\r
+            value: "root"\r
+          - name: CONTEXTDB_ROOT_PASSWORD\r
+            valueFrom:\r
+              secretKeyRef:\r
+                name: etcd-secret\r
+                key: rootPassword\r
+        lifecycle:\r
+          postStart:\r
+            exec:\r
+              command:\r
+              - /bin/sh\r
+              - -c\r
+              - /tmp/etcd-setup.sh\r
+        volumeMounts:\r
+        - mountPath: /tmp\r
+          name: etcd-init\r
+        ports:\r
+        - containerPort: 2379\r
+        - containerPort: 2380\r
+      volumes:\r
+      - configMap:\r
+          defaultMode: 511\r
+          name: etcd-init\r
+        name: etcd-init \r
diff --git a/central-controller/deployments/kubernetes/scc_mongo.yaml b/central-controller/deployments/kubernetes/scc_mongo.yaml
new file mode 100644 (file)
index 0000000..ef383be
--- /dev/null
@@ -0,0 +1,91 @@
+# Resources to create Mongo Databases used by SDEWAN Central Controller v1 Microservices\r
+kind: ConfigMap\r
+apiVersion: v1\r
+metadata:\r
+  name: mongo-init\r
+  labels:\r
+    app: mongo\r
+data:\r
+  mongo-user.sh: |\r
+    mongo -u "$MONGO_INITDB_ROOT_USERNAME" -p "$MONGO_INITDB_ROOT_PASSWORD" <<EOF\r
+    use scc\r
+    db.createUser(\r
+      {\r
+        user: "$DB_EMCO_USERNAME",\r
+        pwd: "$DB_EMCO_PASSWORD",\r
+        roles: [\r
+           { role: "dbOwner", db: "scc" },\r
+           { role: "clusterMonitor", db: "admin" }\r
+        ]\r
+      }\r
+    )\r
+    EOF\r
+\r
+---\r
+#Mongo Service\r
+apiVersion: v1\r
+kind: Service\r
+metadata:\r
+  labels:\r
+    app: mongo\r
+  name: mongo\r
+spec:\r
+  ports:\r
+  - name: "27017"\r
+    port: 27017\r
+    targetPort: 27017\r
+  selector:\r
+    app: mongo\r
+\r
+---\r
+#Mongo Deployment\r
+apiVersion: apps/v1\r
+kind: Deployment\r
+metadata:\r
+  labels:\r
+    app: mongo\r
+  name: mongo\r
+spec:\r
+  replicas: 1\r
+  selector:\r
+    matchLabels:\r
+      app: mongo\r
+  template:\r
+    metadata:\r
+      labels:\r
+        app: mongo\r
+    spec:\r
+      containers:\r
+      - image: mongo\r
+        imagePullPolicy: IfNotPresent\r
+        name: mongo\r
+        ports:\r
+        - containerPort: 27017\r
+        command:\r
+        - docker-entrypoint.sh\r
+        args:\r
+        - --auth\r
+        env:\r
+        - name: MONGO_INITDB_ROOT_USERNAME\r
+          value: "admin"\r
+        - name: MONGO_INITDB_ROOT_PASSWORD\r
+          valueFrom:\r
+            secretKeyRef:\r
+              name: mongo-secret\r
+              key: rootPassword\r
+        - name: MONGO_INITDB_DATABASE\r
+          value: "scc"\r
+        - name: DB_EMCO_USERNAME\r
+          value: "scc"\r
+        - name: DB_EMCO_PASSWORD\r
+          valueFrom:\r
+            secretKeyRef:\r
+              name: mongo-secret\r
+              key: userPassword\r
+        volumeMounts:\r
+        - name: mongo-init\r
+          mountPath: /docker-entrypoint-initdb.d\r
+      volumes:\r
+      - name: mongo-init\r
+        configMap:\r
+          name: mongo-init
\ No newline at end of file
index 9106982..3a39b37 100644 (file)
@@ -29,9 +29,9 @@ spec:
   type: NodePort
   ports:
   - name: internal
-    port: 9041
+    port: 9031
     protocol: TCP
-    targetPort: 9041
+    targetPort: 9031
     nodePort: 31297
 
 ---
@@ -57,15 +57,35 @@ spec:
           command: ["/opt/scc/entrypoint", "rsync"]
           workingDir: /opt/scc
           ports:
-          - containerPort: 9041
+          - containerPort: 9031
           volumeMounts:
           - name: config
             mountPath: /opt/scc/config.json
             subPath: config.json
+          env:
+          - name: DB_EMCO_USERNAME
+            value: "scc"
+          - name: DB_EMCO_PASSWORD
+            valueFrom:
+              secretKeyRef:
+                name: mongo-secret
+                key: userPassword
+          - name: CONTEXTDB_EMCO_USERNAME
+            value: "scc"
+          - name: CONTEXTDB_EMCO_PASSWORD
+            valueFrom:
+              secretKeyRef:
+                name: etcd-secret
+                key: userPassword
+          - name: EMCO_DATA_KEY
+            valueFrom:
+              secretKeyRef:
+                name: mongo-data-secret
+                key: key
       volumes:
         - name: config
           configMap:
             name: rsync
             items:
             - key: config.json
-              path: config.json
\ No newline at end of file
+              path: config.json
diff --git a/central-controller/deployments/kubernetes/scc_secret.yaml b/central-controller/deployments/kubernetes/scc_secret.yaml
new file mode 100644 (file)
index 0000000..fa9b874
--- /dev/null
@@ -0,0 +1,28 @@
+# Secret resources\r
+apiVersion: v1\r
+kind: Secret\r
+metadata:\r
+  name: mongo-secret\r
+type: Opaque\r
+stringData:\r
+  userPassword: "scc-user"\r
+  rootPassword: "scc-root"\r
+\r
+---\r
+apiVersion: v1\r
+kind: Secret\r
+metadata:\r
+  name: etcd-secret\r
+type: Opaque\r
+stringData:\r
+  userPassword: "scc-user"\r
+  rootPassword: "scc-root"\r
+\r
+---\r
+apiVersion: v1\r
+kind: Secret\r
+metadata:\r
+  name: mongo-data-secret\r
+type: Opaque\r
+stringData:\r
+  key: "data-secret"
\ No newline at end of file
index 571ef64..92009a8 100644 (file)
@@ -1,7 +1,26 @@
-# Temporary Build Files
-build/_output
-build/_test
-/output
-### VisualStudioCode ###
+
+# Binaries for programs and plugins
+*.exe
+*.exe~
+*.dll
+*.so
+*.dylib
+bin
+testbin/*
+
+# Test binary, build with `go test -c`
+*.test
+
+# Output of the go coverage tool, specifically when used with LiteIDE
+*.out
+
+# Kubernetes Generated files - skip generated files, except for vendored files
+
+!vendor/**/zz_generated.*
+
+# editor and IDE paraphernalia
+.idea
+*.swp
 .vscode/*
-.history
+*.swo
+*~
diff --git a/central-controller/src/monitor/Dockerfile b/central-controller/src/monitor/Dockerfile
new file mode 100644 (file)
index 0000000..c384026
--- /dev/null
@@ -0,0 +1,28 @@
+# Build the manager binary
+FROM golang:1.17 as builder
+
+WORKDIR /workspace
+# Copy the Go Modules manifests
+COPY go.mod go.mod
+COPY go.sum go.sum
+# cache deps before building and copying source so that we don't need to re-download as much
+# and so that source changes don't invalidate our downloaded layer
+RUN go mod download
+
+# Copy the go source
+COPY main.go main.go
+COPY pkg/ pkg/
+COPY controllers/ controllers/
+
+# Build
+RUN CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build -a -o manager main.go
+
+# Use distroless as minimal base image to package the manager binary
+# Refer to https://github.com/GoogleContainerTools/distroless for more details
+#FROM gcr.io/distroless/static:nonroot
+FROM alpine:latest
+WORKDIR /
+COPY --from=builder /workspace/manager .
+USER 65532:65532
+
+ENTRYPOINT ["/manager"]
index 6b088b1..8ea15ff 100644 (file)
@@ -1,2 +1,2 @@
 // SPDX-License-Identifier: Apache-2.0
-// Copyright (c) 2020 Intel Corporation
\ No newline at end of file
+// Copyright (c) 2020 Intel Corporation
index 5822bba..d2d0bb4 100644 (file)
@@ -6,7 +6,7 @@ export GO111MODULE=on
 all: clean
        CGO_ENABLED=0 GOOS=linux GOARCH=amd64 \
        go build -a -ldflags '-extldflags "-static"' \
-       -o ./monitor ./cmd/manager/main.go
+       -o ./monitor main.go
 
 build: clean test cover
 deploy: build
@@ -19,7 +19,7 @@ format:
        @go fmt ./...
 
 clean:
-       @rm -f monitor
+       @rm -f ./monitor
 
 .PHONY: cover
 cover:
diff --git a/central-controller/src/monitor/PROJECT b/central-controller/src/monitor/PROJECT
new file mode 100644 (file)
index 0000000..74f313f
--- /dev/null
@@ -0,0 +1,19 @@
+domain: io
+layout:
+- go.kubebuilder.io/v3
+plugins:
+  manifests.sdk.operatorframework.io/v2: {}
+  scorecard.sdk.operatorframework.io/v2: {}
+projectName: monitor
+repo: src/monitor
+resources:
+- api:
+    crdVersion: v1
+    namespaced: true
+  controller: true
+  domain: io
+  group: k8splugin
+  kind: ResourceBundleState
+  path: src/monitor/api/v1alpha1
+  version: v1alpha1
+version: "3"
diff --git a/central-controller/src/monitor/cmd/manager/main.go b/central-controller/src/monitor/cmd/manager/main.go
deleted file mode 100644 (file)
index fa69d5e..0000000
+++ /dev/null
@@ -1,110 +0,0 @@
-package main
-
-import (
-       "context"
-       "flag"
-       "fmt"
-       "os"
-       "runtime"
-
-       "github.com/open-ness/EMCO/src/monitor/pkg/apis"
-       "github.com/open-ness/EMCO/src/monitor/pkg/controller"
-       "github.com/operator-framework/operator-sdk/pkg/k8sutil"
-       "github.com/operator-framework/operator-sdk/pkg/leader"
-       sdkVersion "github.com/operator-framework/operator-sdk/version"
-       "github.com/spf13/pflag"
-       "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"
-)
-
-// Change below variables to serve metrics on different host or port.
-var (
-       metricsHost               = "0.0.0.0"
-       metricsPort         int32 = 8383
-       operatorMetricsPort int32 = 8686
-)
-var log = logf.Log.WithName("cmd")
-
-func printVersion() {
-       log.Info(fmt.Sprintf("Go Version: %s", runtime.Version()))
-       log.Info(fmt.Sprintf("Go OS/Arch: %s/%s", runtime.GOOS, runtime.GOARCH))
-       log.Info(fmt.Sprintf("Version of operator-sdk: %v", sdkVersion.Version))
-}
-
-func main() {
-       // Add the zap logger flag set to the CLI. The flag set must
-       // be added before calling pflag.Parse().
-       //pflag.CommandLine.AddFlagSet(zap.FlagSet())
-
-       // Add flags registered by imported packages (e.g. glog and
-       // controller-runtime)
-       pflag.CommandLine.AddGoFlagSet(flag.CommandLine)
-
-       pflag.Parse()
-
-       // Use a zap logr.Logger implementation. If none of the zap
-       // flags are configured (or if the zap flag set is not being
-       // used), this defaults to a production zap logger.
-       //
-       // The logger instantiated here can be changed to any logger
-       // implementing the logr.Logger interface. This logger will
-       // be propagated through the whole operator, generating
-       // uniform and structured logs.
-       //logf.SetLogger(zap.Logger())
-
-       printVersion()
-
-       namespace, err := k8sutil.GetWatchNamespace()
-       if err != nil {
-               log.Error(err, "Failed to get watch namespace")
-               os.Exit(1)
-       }
-
-       // Get a config to talk to the apiserver
-       cfg, err := config.GetConfig()
-       if err != nil {
-               log.Error(err, "")
-               os.Exit(1)
-       }
-
-       ctx := context.TODO()
-       // Become the leader before proceeding
-       err = leader.Become(ctx, "monitor-lock")
-       if err != nil {
-               log.Error(err, "")
-               os.Exit(1)
-       }
-
-       // Create a new Cmd to provide shared dependencies and start components
-       mgr, err := manager.New(cfg, manager.Options{
-               Namespace:          namespace,
-               MetricsBindAddress: fmt.Sprintf("%s:%d", metricsHost, metricsPort),
-       })
-       if err != nil {
-               log.Error(err, "")
-               os.Exit(1)
-       }
-
-       log.Info("Registering Components.")
-
-       // Setup Scheme for all resources
-       if err := apis.AddToScheme(mgr.GetScheme()); err != nil {
-               log.Error(err, "")
-               os.Exit(1)
-       }
-
-       // Setup all Controllers
-       if err := controller.AddToManager(mgr); err != nil {
-               log.Error(err, "")
-               os.Exit(1)
-       }
-       log.Info("Starting the Cmd.")
-
-       // Start the Cmd
-       if err := mgr.Start(signals.SetupSignalHandler()); err != nil {
-               log.Error(err, "Manager exited non-zero")
-               os.Exit(1)
-       }
-}
diff --git a/central-controller/src/monitor/controllers/commit.go b/central-controller/src/monitor/controllers/commit.go
new file mode 100644 (file)
index 0000000..30d54a7
--- /dev/null
@@ -0,0 +1,160 @@
+// SPDX-License-Identifier: Apache-2.0
+// Copyright (c) 2022 Intel Corporation
+
+package controllers
+
+import (
+       "bytes"
+       "context"
+       "encoding/json"
+       "fmt"
+       "github.com/fluxcd/go-git-providers/github"
+       "github.com/fluxcd/go-git-providers/gitprovider"
+       k8spluginv1alpha1 "gitlab.com/project-emco/core/emco-base/src/monitor/pkg/apis/k8splugin/v1alpha1"
+       k8serrors "k8s.io/apimachinery/pkg/api/errors"
+       "log"
+       "os"
+       "sigs.k8s.io/controller-runtime/pkg/client"
+       "strings"
+       "sync"
+)
+
+type GithubAccessClient struct {
+       cl           gitprovider.Client
+       gitUser      string
+       gitRepo      string
+       cluster      string
+       githubDomain string
+}
+
+var GitHubClient GithubAccessClient
+
+func SetupGitHubClient() error {
+       var err error
+       GitHubClient, err = NewGitHubClient()
+       return err
+}
+
+func NewGitHubClient() (GithubAccessClient, error) {
+
+       githubDomain := "github.com"
+       gitUser := os.Getenv("GIT_USERNAME")
+       gitToken := os.Getenv("GIT_TOKEN")
+       gitRepo := os.Getenv("GIT_REPO")
+       clusterName := os.Getenv("GIT_CLUSTERNAME")
+
+       // If any value is not provided then can't store in Git location
+       if len(gitRepo) <= 0 || len(gitToken) <= 0 || len(gitUser) <= 0 || len(clusterName) <= 0 {
+               log.Printf("Github information not found:: Skipping Github storage")
+               return GithubAccessClient{}, nil
+       }
+       log.Println("GitHub Info found", "gitRepo::", gitRepo, "cluster::", clusterName)
+
+       cl, err := github.NewClient(gitprovider.WithOAuth2Token(gitToken), gitprovider.WithDestructiveAPICalls(true))
+       if err != nil {
+               return GithubAccessClient{}, err
+       }
+       return GithubAccessClient{
+               cl:           cl,
+               gitUser:      gitUser,
+               gitRepo:      gitRepo,
+               githubDomain: githubDomain,
+               cluster:      clusterName,
+       }, nil
+}
+
+func CommitCR(c client.Client, cr *k8spluginv1alpha1.ResourceBundleState, org *k8spluginv1alpha1.ResourceBundleStateStatus) error {
+
+       // Compare status and update if status changed
+       resBytesCr, err := json.Marshal(cr.Status)
+       if err != nil {
+               log.Println("json Marshal error for resource::", cr, err)
+               return err
+       }
+       resBytesOrg, err := json.Marshal(org)
+       if err != nil {
+               log.Println("json Marshal error for resource::", cr, err)
+               return err
+       }
+       // If the status is not changed no need to update CR
+       if bytes.Compare(resBytesCr, resBytesOrg) == 0 {
+               fmt.Println("Not changed")
+               return nil
+       }
+       err = c.Status().Update(context.TODO(), cr)
+       if err != nil {
+               if k8serrors.IsConflict(err) {
+                       return err
+               } else {
+                       log.Println("CR Update Error::", err)
+                       return err
+               }
+       }
+       resBytes, err := json.Marshal(cr)
+       if err != nil {
+               log.Println("json Marshal error for resource::", cr, err)
+               return err
+       }
+       fmt.Println("Ready to commit to github")
+
+       // Check if GIT Info is provided if so store the information in the Git Repo also
+       err = GitHubClient.CommitCRToGitHub(resBytes, cr.GetLabels())
+       if err != nil {
+               log.Println("Error commiting status to Github", err)
+       }
+       return nil
+}
+
+var mutex = sync.Mutex{}
+
+func (c *GithubAccessClient) CommitCRToGitHub(resBytes []byte, l map[string]string) error {
+
+       // Check if Github Client is available
+       if c.cl == nil {
+               return nil
+       }
+       // Get cid and app id
+       v, ok := l["emco/deployment-id"]
+       if !ok {
+               return fmt.Errorf("Unexpected error:: Inconsistent labels %v", l)
+       }
+       result := strings.SplitN(v, "-", 2)
+       if len(result) != 2 {
+               return fmt.Errorf("Unexpected error:: Inconsistent labels %v", l)
+       }
+       app := result[1]
+       cid := result[0]
+       path := "clusters/" + c.cluster + "/status/" + cid + "/app/" + app + "/" + v
+
+       userRef := gitprovider.UserRef{
+               Domain:    c.githubDomain,
+               UserLogin: c.gitUser,
+       }
+       // Create the repo reference
+       userRepoRef := gitprovider.UserRepositoryRef{
+               UserRef:        userRef,
+               RepositoryName: c.gitRepo,
+       }
+       s := string(resBytes)
+       var files []gitprovider.CommitFile
+       files = append(files, gitprovider.CommitFile{
+               Path:    &path,
+               Content: &s,
+       })
+       commitMessage := "Adding Status for " + path
+       fmt.Println("Commit to github prepared")
+
+       // Only one process to commit to Github location to avoid conflicts
+       mutex.Lock()
+       defer mutex.Unlock()
+       userRepo, err := c.cl.UserRepositories().Get(context.Background(), userRepoRef)
+       if err != nil {
+               return err
+       }
+       //Commit file to this repo to a branch status
+       _, err = userRepo.Commits().Create(context.Background(), "main", commitMessage, files)
+       if err != nil {
+               return err
+       }
+       return nil
+}
diff --git a/central-controller/src/monitor/controllers/controller_list.go b/central-controller/src/monitor/controllers/controller_list.go
new file mode 100644 (file)
index 0000000..d48da68
--- /dev/null
@@ -0,0 +1,229 @@
+// SPDX-License-Identifier: Apache-2.0
+// Copyright (c) 2022 Intel Corporation
+
+package controllers
+
+import (
+       "context"
+       "encoding/json"
+       k8serrors "k8s.io/apimachinery/pkg/api/errors"
+       metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
+       "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
+       "k8s.io/apimachinery/pkg/runtime"
+       "k8s.io/apimachinery/pkg/runtime/schema"
+       "k8s.io/client-go/dynamic"
+       "log"
+       "os"
+       ctrl "sigs.k8s.io/controller-runtime"
+       "sigs.k8s.io/controller-runtime/pkg/builder"
+       "sigs.k8s.io/controller-runtime/pkg/client"
+       slog "sigs.k8s.io/controller-runtime/pkg/log"
+       "sigs.k8s.io/controller-runtime/pkg/predicate"
+)
+
+type GvkElement struct {
+       resource   string
+       defaultRes bool
+}
+
+var defaultType GvkElement = GvkElement{defaultRes: true}
+
+// List of resources with special handling in Monitor
+var GVKList = map[schema.GroupVersionKind]GvkElement{
+       {Version: "v1", Kind: "ConfigMap"}:                                               defaultType,
+       {Group: "apps", Version: "v1", Kind: "DaemonSet"}:                                defaultType,
+       {Group: "apps", Version: "v1", Kind: "Deployment"}:                               defaultType,
+       {Group: "batch", Version: "v1", Kind: "Job"}:                                     defaultType,
+       {Version: "v1", Kind: "Service"}:                                                 defaultType,
+       {Version: "v1", Kind: "Pod"}:                                                     defaultType,
+       {Group: "apps", Version: "v1", Kind: "StatefulSet"}:                              defaultType,
+       {Group: "certificates.k8s.io", Version: "v1", Kind: "CertificateSigningRequest"}: defaultType,
+       {Group: "rbac.authorization.k8s.io", Version: "v1", Kind: "Role"}:                {resource: "roles", defaultRes: false},
+       {Group: "rbac.authorization.k8s.io", Version: "v1", Kind: "RoleBinding"}:         {resource: "rolebindings", defaultRes: false},
+       {Group: "rbac.authorization.k8s.io", Version: "v1", Kind: "ClusterRole"}:         {resource: "roles", defaultRes: false},
+       {Group: "rbac.authorization.k8s.io", Version: "v1", Kind: "ClusterRoleBinding"}:  {resource: "clusterrolebindings", defaultRes: false},
+       {Version: "v1", Kind: "ResourceQuota"}:                                           {resource: "resourcequotas", defaultRes: false},
+       {Version: "v1", Kind: "Namespace"}:                                               {resource: "namespaces", defaultRes: false},
+}
+
+var GvkMap map[schema.GroupVersionKind]GvkElement
+
+// ResourceBundleStateReconciler reconciles a ResourceBundleState object
+type ControllerListReconciler struct {
+       client.Client
+       Scheme *runtime.Scheme
+       gvk    *schema.GroupVersionKind
+}
+
+func runtimeObjFromGVK(r schema.GroupVersionKind) runtime.Object {
+       obj := &unstructured.Unstructured{}
+       obj.SetGroupVersionKind(r)
+       return obj
+}
+
+//+kubebuilder:rbac:groups=k8splugin.io,resources=resourcebundlestates,verbs=get;list;watch;create;update;patch;delete
+//+kubebuilder:rbac:groups=k8splugin.io,resources=resourcebundlestates/status,verbs=get;update;patch
+//+kubebuilder:rbac:groups=k8splugin.io,resources=resourcebundlestates/finalizers,verbs=update
+
+func (r *ControllerListReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Result, error) {
+       _ = slog.FromContext(ctx)
+
+       log.Println("Reconcile", req.Name, req.Namespace, r.gvk)
+       // Note: Create an unstructued type for the Client to use and set the Kind
+       // so that it can GET/UPDATE/DELETE etc
+       resource := &unstructured.Unstructured{}
+       resource.SetGroupVersionKind(*r.gvk)
+
+       err := r.Get(ctx, req.NamespacedName, resource)
+       if err != nil {
+               if k8serrors.IsNotFound(err) {
+                       if g, ok := GvkMap[*r.gvk]; ok {
+                               var err1 error
+                               if g.defaultRes {
+                                       err1 = DeleteFromAllCRs(r.Client, req.NamespacedName, *r.gvk)
+                               } else {
+                                       err1 = DeleteResourceStatusFromAllCRs(r.Client, req.NamespacedName, *r.gvk)
+                               }
+                               return ctrl.Result{}, err1
+                       }
+                       return ctrl.Result{}, nil
+               }
+               return ctrl.Result{}, err
+       }
+       // If resource not a default resource for the controller
+       // Add status to ResourceStatues array
+       if g, ok := GvkMap[*r.gvk]; ok {
+               if g.defaultRes {
+                       err = UpdateCR(r.Client, resource, req.NamespacedName, *r.gvk)
+               } else {
+                       err = UpdateResourceStatus(r.Client, resource, req.NamespacedName.Name, req.NamespacedName.Namespace)
+               }
+       }
+       if err != nil {
+               // Requeue the update
+               return ctrl.Result{}, err
+       }
+       return ctrl.Result{}, nil
+}
+
+//
+func GetResourcesDynamically(group string, version string, resource string, namespace string) (
+       []unstructured.Unstructured, error) {
+
+       ctx := context.Background()
+       config := ctrl.GetConfigOrDie()
+       dynamic := dynamic.NewForConfigOrDie(config)
+       resourceId := schema.GroupVersionResource{
+               Group:    group,
+               Version:  version,
+               Resource: resource,
+       }
+       list, err := dynamic.Resource(resourceId).Namespace("").
+               List(ctx, metav1.ListOptions{})
+
+       if err != nil {
+               log.Println("Error listing resource:", resourceId, err)
+               return nil, err
+       }
+
+       return list.Items, nil
+}
+
+// SetupWithManager sets up the controller with the Manager.
+func (r *ControllerListReconciler) SetupWithManager(mgr ctrl.Manager) error {
+
+       resource := &unstructured.Unstructured{}
+       resource.SetGroupVersionKind(*r.gvk)
+
+       return ctrl.NewControllerManagedBy(mgr).
+               Named(r.gvk.Kind+"-emco-monitor").
+               For(resource, builder.WithPredicates(predicate.NewPredicateFuncs(func(object client.Object) bool {
+                       labels := object.GetLabels()
+                       _, ok := labels["emco/deployment-id"]
+                       if !ok {
+                               return false
+                       }
+                       return true
+               }))).
+               Complete(r)
+}
+
+func SetupControllerForType(mgr ctrl.Manager, gv schema.GroupVersionKind, breakonError bool) error {
+       r := ControllerListReconciler{
+               Client: mgr.GetClient(),
+               Scheme: mgr.GetScheme(),
+               gvk:    &gv,
+       }
+
+       if err := (&r).SetupWithManager(mgr); err != nil {
+               log.Println(err, "unable to create controller", "controller", gv)
+               if breakonError {
+                       os.Exit(1)
+               }
+       }
+       return nil
+}
+
+type configResource struct {
+       Group    string `json:"group"`
+       Version  string `json:"version"`
+       Kind     string `json:"kind"`
+       Resource string `json:"resource"`
+}
+
+// readConfigFile reads the specified smsConfig file to setup some env variables
+func readGVKList(file string) ([]configResource, error) {
+       f, err := os.Open(file)
+       if err != nil {
+               log.Println("FILE not found::", file, err)
+               return []configResource{}, err
+       }
+       defer f.Close()
+
+       // Read the configuration from json file
+       result := make([]configResource, 0)
+       decoder := json.NewDecoder(f)
+       decoder.DisallowUnknownFields()
+       err = decoder.Decode(&result)
+       //err = decoder.Decode(&conf)
+       if err != nil {
+               log.Println("FILE Decode error::", file, err)
+               return []configResource{}, err
+       }
+       return result, nil
+}
+
+func SetupControllers(mgr ctrl.Manager) error {
+
+       // Copy map
+       GvkMap = make(map[schema.GroupVersionKind]GvkElement, len(GVKList))
+       for k, v := range GVKList {
+               GvkMap[k] = v
+       }
+
+       l, err := readGVKList("/opt/emco/monitor/gvk.conf")
+       if err != nil {
+               log.Println("Error reading configmap for GVK List")
+       }
+
+       for _, gv := range l {
+               _, err = GetResourcesDynamically(gv.Group, gv.Version, gv.Resource, "default")
+               if err != nil {
+                       log.Println("Invalid resource for the cluster", gv)
+                       continue
+               }
+               gvk := schema.GroupVersionKind{
+                       Group:   gv.Group,
+                       Kind:    gv.Kind,
+                       Version: gv.Version,
+               }
+               if _, ok := GvkMap[gvk]; !ok {
+                       GvkMap[gvk] = GvkElement{defaultRes: false, resource: gv.Resource}
+               }
+       }
+       log.Println("Adding controllers for::", GvkMap)
+       for k, v := range GvkMap {
+               SetupControllerForType(mgr, k, v.defaultRes)
+       }
+       return nil
+}
diff --git a/central-controller/src/monitor/controllers/helpers.go b/central-controller/src/monitor/controllers/helpers.go
new file mode 100644 (file)
index 0000000..1808a22
--- /dev/null
@@ -0,0 +1,328 @@
+// SPDX-License-Identifier: Apache-2.0
+// Copyright (c) 2020 Intel Corporation
+
+package controllers
+
+import (
+       "context"
+       "encoding/json"
+       "fmt"
+       k8spluginv1alpha1 "gitlab.com/project-emco/core/emco-base/src/monitor/pkg/apis/k8splugin/v1alpha1"
+       "log"
+
+       metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
+       "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
+       "k8s.io/apimachinery/pkg/labels"
+       "k8s.io/apimachinery/pkg/runtime"
+       "k8s.io/apimachinery/pkg/runtime/schema"
+       "k8s.io/apimachinery/pkg/types"
+       "sigs.k8s.io/controller-runtime/pkg/client"
+)
+
+type ResourceProvider interface {
+       GetClient() client.Client
+       UpdateStatus(*k8spluginv1alpha1.ResourceBundleState, runtime.Object) (bool, error)
+       DeleteObj(*k8spluginv1alpha1.ResourceBundleState, string) bool
+}
+
+// checkLabel verifies if the expected label exists and returns bool
+func checkLabel(labels map[string]string) bool {
+
+       _, ok := labels["emco/deployment-id"]
+       if !ok {
+               return false
+       }
+       return true
+}
+
+// returnLabel verifies if the expected label exists and returns a map
+func returnLabel(labels map[string]string) map[string]string {
+
+       l, ok := labels["emco/deployment-id"]
+       if !ok {
+               return nil
+       }
+       return map[string]string{
+               "emco/deployment-id": l,
+       }
+}
+
+// listResources lists resources based on the selectors provided
+// The data is returned in the pointer to the runtime.Object
+// provided as argument.
+func listResources(cli client.Client, namespace string,
+       labelSelector map[string]string, returnData client.ObjectList) error {
+
+       listOptions := &client.ListOptions{
+               Namespace:     namespace,
+               LabelSelector: labels.SelectorFromSet(labelSelector),
+       }
+
+       err := cli.List(context.TODO(), returnData, listOptions)
+       if err != nil {
+               log.Printf("Failed to list CRs: %v", err)
+               return err
+       }
+
+       return nil
+}
+
+// listClusterResources lists non-namespace resources based
+// on the selectors provided.
+// The data is returned in the pointer to the runtime.Object
+// provided as argument.
+func listClusterResources(cli client.Client,
+       labelSelector map[string]string, returnData client.ObjectList) error {
+       return listResources(cli, "", labelSelector, returnData)
+}
+
+func GetCRListForResource(client client.Client, item *unstructured.Unstructured) (*k8spluginv1alpha1.ResourceBundleStateList, error) {
+       rbStatusList := &k8spluginv1alpha1.ResourceBundleStateList{}
+
+       // Find the CRs which track this resource via the labelselector
+       crSelector := returnLabel(item.GetLabels())
+       if crSelector == nil {
+               log.Println("We should not be here. The predicate should have filtered this resource")
+               return rbStatusList, fmt.Errorf("Unexpected Error: Resource not filtered by predicate")
+       }
+       // Get the CRs which have this label and update them all
+       // Ideally, we will have only one CR, but there is nothing
+       // preventing the creation of multiple.
+       err := listResources(client, item.GetNamespace(), crSelector, rbStatusList)
+       if err != nil {
+               return rbStatusList, err
+       }
+       if len(rbStatusList.Items) == 0 {
+               return rbStatusList, nil
+       }
+       return rbStatusList, nil
+}
+
+func UpdateCR(c client.Client, item *unstructured.Unstructured, namespacedName types.NamespacedName, gvk schema.GroupVersionKind) error {
+       var err error
+       var found bool
+       rbStatusList, err := GetCRListForResource(c, item)
+       if err != nil {
+               return err
+       }
+
+       for _, cr := range rbStatusList.Items {
+               orgStatus := cr.Status.DeepCopy()
+
+               // Not scheduled for deletion
+               if item.GetDeletionTimestamp() == nil {
+                       _, err := UpdateStatus(&cr, item)
+                       if err != nil {
+                               fmt.Println("Error updating CR")
+                               return err
+                       }
+                       // Commit
+                       err = CommitCR(c, &cr, orgStatus)
+               } else {
+                       // Scheduled for deletion
+                       found, err = DeleteObj(&cr, namespacedName.Name, gvk)
+                       if found && err == nil {
+                               err = CommitCR(c, &cr, orgStatus)
+                       }
+               }
+       }
+       return err
+}
+
+func UpdateStatus(cr *k8spluginv1alpha1.ResourceBundleState, item *unstructured.Unstructured) (bool, error) {
+
+       switch item.GetObjectKind().GroupVersionKind() {
+       case schema.GroupVersionKind{Version: "v1", Kind: "ConfigMap"}:
+               return ConfigMapUpdateStatus(cr, item)
+       case schema.GroupVersionKind{Version: "v1", Kind: "Service"}:
+               return ServiceUpdateStatus(cr, item)
+       case schema.GroupVersionKind{Group: "apps", Version: "v1", Kind: "DaemonSet"}:
+               return DaemonSetUpdateStatus(cr, item)
+       case schema.GroupVersionKind{Group: "apps", Version: "v1", Kind: "Deployment"}:
+               return DeploymentUpdateStatus(cr, item)
+       case schema.GroupVersionKind{Group: "batch", Version: "v1", Kind: "Job"}:
+               return JobUpdateStatus(cr, item)
+       case schema.GroupVersionKind{Version: "v1", Kind: "Pod"}:
+               return PodUpdateStatus(cr, item)
+       case schema.GroupVersionKind{Group: "apps", Version: "v1", Kind: "StatefulSet"}:
+               return StatefulSetUpdateStatus(cr, item)
+       case schema.GroupVersionKind{Group: "certificates.k8s.io", Version: "v1", Kind: "CertificateSigningRequest"}:
+               return CsrUpdateStatus(cr, item)
+       }
+       return false, fmt.Errorf("Resource not supported explicitly")
+}
+
+func DeleteObj(cr *k8spluginv1alpha1.ResourceBundleState, name string, gvk schema.GroupVersionKind) (bool, error) {
+
+       switch gvk {
+       case schema.GroupVersionKind{Version: "v1", Kind: "ConfigMap"}:
+               return ConfigMapDeleteObj(cr, name)
+       case schema.GroupVersionKind{Version: "v1", Kind: "Service"}:
+               return ServiceDeleteObj(cr, name)
+       case schema.GroupVersionKind{Group: "apps", Version: "v1", Kind: "DaemonSet"}:
+               return DaemonSetDeleteObj(cr, name)
+       case schema.GroupVersionKind{Group: "apps", Version: "v1", Kind: "Deployment"}:
+               return DeploymentDeleteObj(cr, name)
+       case schema.GroupVersionKind{Group: "batch", Version: "v1", Kind: "Job"}:
+               return JobDeleteObj(cr, name)
+       case schema.GroupVersionKind{Version: "v1", Kind: "Pod"}:
+               return PodDeleteObj(cr, name)
+       case schema.GroupVersionKind{Group: "apps", Version: "v1", Kind: "StatefulSet"}:
+               return StatefulSetDeleteObj(cr, name)
+       case schema.GroupVersionKind{Group: "certificates.k8s.io", Version: "v1", Kind: "CertificateSigningRequest"}:
+               return CsrDeleteObj(cr, name)
+       }
+       return false, fmt.Errorf("Resource not supported explicitly")
+}
+
+func DeleteFromSingleCR(c client.Client, cr *k8spluginv1alpha1.ResourceBundleState, name string, gvk schema.GroupVersionKind) error {
+
+       found, _ := DeleteObj(cr, name, gvk)
+       if found {
+               fieldMgr := "emco-monitor"
+               err := c.Status().Update(context.TODO(), cr, &client.UpdateOptions{FieldManager: fieldMgr})
+               if err != nil {
+                       log.Printf("failed to update rbstate: %v\n", err)
+                       return err
+               }
+       }
+       return nil
+}
+
+func DeleteFromAllCRs(c client.Client, namespacedName types.NamespacedName, gvk schema.GroupVersionKind) error {
+       var err error
+       var found bool
+       rbStatusList := &k8spluginv1alpha1.ResourceBundleStateList{}
+       err = listResources(c, namespacedName.Namespace, nil, rbStatusList)
+       if err != nil || len(rbStatusList.Items) == 0 {
+               log.Printf("Did not find any CRs tracking this resource\n")
+               return fmt.Errorf("Did not find any CRs tracking this resource")
+       }
+       for _, cr := range rbStatusList.Items {
+               orgStatus := cr.Status.DeepCopy()
+               found, err = DeleteObj(&cr, namespacedName.Name, gvk)
+               if found && err == nil {
+                       err = CommitCR(c, &cr, orgStatus)
+               }
+       }
+       return err
+}
+
+func ClearLastApplied(annotations map[string]string) map[string]string {
+       _, ok := annotations["kubectl.kubernetes.io/last-applied-configuration"]
+       if ok {
+               annotations["kubectl.kubernetes.io/last-applied-configuration"] = ""
+       }
+       return annotations
+}
+
+//Update CR status for generic resources
+func UpdateResourceStatus(c client.Client, item *unstructured.Unstructured, name, namespace string) error {
+       var err error
+
+       rbStatusList, err := GetCRListForResource(c, item)
+       if err != nil {
+               return err
+       }
+       var found bool
+       for _, cr := range rbStatusList.Items {
+               orgStatus := cr.Status.DeepCopy()
+               // Not scheduled for deletion
+               if item.GetDeletionTimestamp() == nil {
+                       found, err = UpdateResourceStatusCR(&cr, item, name, namespace)
+
+                       if err == nil {
+                               err = CommitCR(c, &cr, orgStatus)
+                       }
+               } else {
+                       found, err = DeleteResourceStatusCR(&cr, item.GetName(), item.GetNamespace(), item.GroupVersionKind())
+                       if found && err == nil {
+                               err = CommitCR(c, &cr, orgStatus)
+                       }
+               }
+
+       }
+       return err
+}
+
+func DeleteResourceStatusFromAllCRs(c client.Client, namespacedName types.NamespacedName, gvk schema.GroupVersionKind) error {
+       var err error
+       var found bool
+       rbStatusList := &k8spluginv1alpha1.ResourceBundleStateList{}
+       err = listResources(c, namespacedName.Namespace, nil, rbStatusList)
+       if err != nil || len(rbStatusList.Items) == 0 {
+               log.Printf("Did not find any CRs tracking this resource\n")
+               return fmt.Errorf("Did not find any CRs tracking this resource")
+       }
+       for _, cr := range rbStatusList.Items {
+               orgStatus := cr.Status.DeepCopy()
+               found, err = DeleteResourceStatusCR(&cr, namespacedName.Name, namespacedName.Namespace, gvk)
+               if found && err == nil {
+                       err = CommitCR(c, &cr, orgStatus)
+               }
+       }
+       return err
+}
+
+func DeleteResourceStatusCR(cr *k8spluginv1alpha1.ResourceBundleState, name, namespace string, gvk schema.GroupVersionKind) (bool, error) {
+       var found bool
+       length := len(cr.Status.ResourceStatuses)
+       for i, rstatus := range cr.Status.ResourceStatuses {
+               if (rstatus.Group == gvk.Group) && (rstatus.Version == gvk.Version) && (rstatus.Kind == gvk.Kind) && (rstatus.Name == name) && (rstatus.Namespace == namespace) {
+                       found = true
+                       //Delete that status from the array
+                       cr.Status.ResourceStatuses[i] = cr.Status.ResourceStatuses[length-1]
+                       cr.Status.ResourceStatuses[length-1] = k8spluginv1alpha1.ResourceStatus{}
+                       cr.Status.ResourceStatuses = cr.Status.ResourceStatuses[:length-1]
+                       break
+               }
+       }
+       return found, nil
+}
+
+func UpdateResourceStatusCR(cr *k8spluginv1alpha1.ResourceBundleState, item *unstructured.Unstructured, name, namespace string) (bool, error) {
+       var found bool
+       var res k8spluginv1alpha1.ResourceStatus
+
+       // Clear up some fields to reduce size
+       item.SetManagedFields([]metav1.ManagedFieldsEntry{})
+       item.SetAnnotations(ClearLastApplied(item.GetAnnotations()))
+
+       unstruct := item.UnstructuredContent()
+       err := runtime.DefaultUnstructuredConverter.FromUnstructured(unstruct, &res)
+       if err != nil {
+               log.Println("DefaultUnstructuredConverter error", name, namespace, err)
+               return found, fmt.Errorf("Unknown resource")
+       }
+
+       group := item.GetObjectKind().GroupVersionKind().Group
+       version := item.GetObjectKind().GroupVersionKind().Version
+       kind := item.GetObjectKind().GroupVersionKind().Kind
+
+       for _, rstatus := range cr.Status.ResourceStatuses {
+               if (rstatus.Group == group) && (rstatus.Version == version) && (rstatus.Kind == kind) && (rstatus.Name == name) && (rstatus.Namespace == namespace) {
+                       found = true
+                       // Replace
+                       res.DeepCopyInto(&rstatus)
+                       break
+               }
+       }
+       if !found {
+               resBytes, err := json.Marshal(item)
+               if err != nil {
+                       log.Println("json Marshal error for resource::", item, err)
+                       return found, err
+               }
+               // Add resource to ResourceMap
+               res := k8spluginv1alpha1.ResourceStatus{
+                       Group:     group,
+                       Version:   version,
+                       Kind:      kind,
+                       Name:      name,
+                       Namespace: namespace,
+                       Res:       resBytes,
+               }
+               cr.Status.ResourceStatuses = append(cr.Status.ResourceStatuses, res)
+       }
+       return found, nil
+}
diff --git a/central-controller/src/monitor/controllers/resourcebundlestate_controller.go b/central-controller/src/monitor/controllers/resourcebundlestate_controller.go
new file mode 100644 (file)
index 0000000..aa3ce53
--- /dev/null
@@ -0,0 +1,355 @@
+// SPDX-License-Identifier: Apache-2.0
+// Copyright (c) 2022 Intel Corporation
+
+package controllers
+
+import (
+       "context"
+       "fmt"
+       k8spluginv1alpha1 "gitlab.com/project-emco/core/emco-base/src/monitor/pkg/apis/k8splugin/v1alpha1"
+       appsv1 "k8s.io/api/apps/v1"
+       v1 "k8s.io/api/batch/v1"
+       certsapi "k8s.io/api/certificates/v1"
+       corev1 "k8s.io/api/core/v1"
+       k8serrors "k8s.io/apimachinery/pkg/api/errors"
+       metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
+       "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
+       "k8s.io/apimachinery/pkg/runtime"
+       "log"
+       ctrl "sigs.k8s.io/controller-runtime"
+       "sigs.k8s.io/controller-runtime/pkg/client"
+       slog "sigs.k8s.io/controller-runtime/pkg/log"
+)
+
+// ResourceBundleStateReconciler reconciles a ResourceBundleState object
+type ResourceBundleStateReconciler struct {
+       client.Client
+       Scheme *runtime.Scheme
+}
+
+//+kubebuilder:rbac:groups=k8splugin.io,resources=resourcebundlestates,verbs=get;list;watch;create;update;patch;delete
+//+kubebuilder:rbac:groups=k8splugin.io,resources=resourcebundlestates/status,verbs=get;update;patch
+//+kubebuilder:rbac:groups=k8splugin.io,resources=resourcebundlestates/finalizers,verbs=update
+
+// Reconcile is part of the main kubernetes reconciliation loop which aims to
+// move the current state of the cluster closer to the desired state.
+// TODO(user): Modify the Reconcile function to compare the state specified by
+// the ResourceBundleState object against the actual cluster state, and then
+// perform operations to make the cluster state reflect the state specified by
+// the user.
+//
+// For more details, check Reconcile and its Result here:
+// - https://pkg.go.dev/sigs.k8s.io/controller-runtime@v0.10.0/pkg/reconcile
+func (r *ResourceBundleStateReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Result, error) {
+       _ = slog.FromContext(ctx)
+       log.Println("Reconcile CR", req)
+       rbstate := &k8spluginv1alpha1.ResourceBundleState{}
+       err := r.Get(context.TODO(), req.NamespacedName, rbstate)
+       if err != nil {
+               if k8serrors.IsNotFound(err) {
+                       log.Printf("Object not found: %+v. Ignore as it must have been deleted.\n", req.NamespacedName)
+                       return ctrl.Result{}, nil
+               }
+               log.Printf("Failed to get object: %+v\n", req.NamespacedName)
+               return ctrl.Result{}, err
+       }
+       rbstate.Status.Ready = true
+       orgStatus := &k8spluginv1alpha1.ResourceBundleStateStatus{}
+       rbstate.Status.DeepCopyInto(orgStatus)
+
+       err = r.updatePods(rbstate, rbstate.Spec.Selector.MatchLabels)
+       if err != nil {
+               log.Printf("Error adding podstatuses: %v\n", err)
+               return ctrl.Result{}, err
+       }
+
+       err = r.updateServices(rbstate, rbstate.Spec.Selector.MatchLabels)
+       if err != nil {
+               log.Printf("Error adding servicestatuses: %v\n", err)
+               return ctrl.Result{}, err
+       }
+
+       err = r.updateConfigMaps(rbstate, rbstate.Spec.Selector.MatchLabels)
+       if err != nil {
+               log.Printf("Error adding configmapstatuses: %v\n", err)
+               return ctrl.Result{}, err
+       }
+
+       err = r.updateDeployments(rbstate, rbstate.Spec.Selector.MatchLabels)
+       if err != nil {
+               log.Printf("Error adding deploymentstatuses: %v\n", err)
+               return ctrl.Result{}, err
+       }
+
+       err = r.updateDaemonSets(rbstate, rbstate.Spec.Selector.MatchLabels)
+       if err != nil {
+               log.Printf("Error adding daemonSetstatuses: %v\n", err)
+               return ctrl.Result{}, err
+       }
+
+       err = r.updateJobs(rbstate, rbstate.Spec.Selector.MatchLabels)
+       if err != nil {
+               log.Printf("Error adding jobstatuses: %v\n", err)
+               return ctrl.Result{}, err
+       }
+
+       err = r.updateStatefulSets(rbstate, rbstate.Spec.Selector.MatchLabels)
+       if err != nil {
+               log.Printf("Error adding statefulSetstatuses: %v\n", err)
+               return ctrl.Result{}, err
+       }
+
+       err = r.updateCsrs(rbstate, rbstate.Spec.Selector.MatchLabels)
+       if err != nil {
+               log.Printf("Error adding csrStatuses: %v\n", err)
+               return ctrl.Result{}, err
+       }
+
+       err = r.updateDynResources(rbstate, rbstate.Spec.Selector.MatchLabels)
+       if err != nil {
+               log.Printf("Error adding dynamic resources: %v\n", err)
+               return ctrl.Result{}, err
+       }
+
+       fmt.Println("Commit CR with status")
+       fmt.Println(rbstate)
+       err = CommitCR(r.Client, rbstate, orgStatus)
+       if err != nil {
+               return ctrl.Result{}, err
+       }
+       return ctrl.Result{}, nil
+}
+
+// SetupWithManager sets up the controller with the Manager.
+func (r *ResourceBundleStateReconciler) SetupWithManager(mgr ctrl.Manager) error {
+       return ctrl.NewControllerManagedBy(mgr).
+               For(&k8spluginv1alpha1.ResourceBundleState{}).
+               Complete(r)
+}
+
+func (r *ResourceBundleStateReconciler) updateServices(rbstate *k8spluginv1alpha1.ResourceBundleState,
+       selectors map[string]string) error {
+
+       // Update the CR with the Services created as well
+       serviceList := &corev1.ServiceList{}
+
+       err := listResources(r.Client, rbstate.Namespace, selectors, serviceList)
+       if err != nil {
+               log.Printf("Failed to list services: %v", err)
+               return err
+       }
+
+       for _, svc := range serviceList.Items {
+               newUnstr, err := runtime.DefaultUnstructuredConverter.ToUnstructured(&svc)
+               if err == nil {
+                       un := &unstructured.Unstructured{}
+                       un.SetUnstructuredContent(newUnstr)
+                       ServiceUpdateStatus(rbstate, un)
+               } else {
+                       return err
+               }
+       }
+
+       return nil
+}
+
+func (r *ResourceBundleStateReconciler) updatePods(rbstate *k8spluginv1alpha1.ResourceBundleState,
+       selectors map[string]string) error {
+
+       // Update the CR with the pods tracked
+       podList := &corev1.PodList{}
+       err := listResources(r.Client, rbstate.Namespace, selectors, podList)
+       if err != nil {
+               log.Printf("Failed to list pods: %v", err)
+               return err
+       }
+
+       for _, pod := range podList.Items {
+               newUnstr, err := runtime.DefaultUnstructuredConverter.ToUnstructured(&pod)
+               if err == nil {
+                       un := &unstructured.Unstructured{}
+                       un.SetUnstructuredContent(newUnstr)
+                       PodUpdateStatus(rbstate, un)
+               } else {
+                       return err
+               }
+       }
+       return nil
+}
+
+func (r *ResourceBundleStateReconciler) updateConfigMaps(rbstate *k8spluginv1alpha1.ResourceBundleState,
+       selectors map[string]string) error {
+
+       // Update the CR with the ConfigMaps created as well
+       configMapList := &corev1.ConfigMapList{}
+       err := listResources(r.Client, rbstate.Namespace, selectors, configMapList)
+       if err != nil {
+               log.Printf("Failed to list configMaps: %v", err)
+               return err
+       }
+       for _, cm := range configMapList.Items {
+               newUnstr, err := runtime.DefaultUnstructuredConverter.ToUnstructured(&cm)
+               if err == nil {
+                       un := &unstructured.Unstructured{}
+                       un.SetUnstructuredContent(newUnstr)
+                       ConfigMapUpdateStatus(rbstate, un)
+               } else {
+                       return err
+               }
+       }
+
+       return nil
+}
+
+func (r *ResourceBundleStateReconciler) updateDeployments(rbstate *k8spluginv1alpha1.ResourceBundleState,
+       selectors map[string]string) error {
+
+       // Update the CR with the Deployments created as well
+       deploymentList := &appsv1.DeploymentList{}
+       err := listResources(r.Client, rbstate.Namespace, selectors, deploymentList)
+       if err != nil {
+               log.Printf("Failed to list deployments: %v", err)
+               return err
+       }
+
+       for _, dep := range deploymentList.Items {
+               newUnstr, err := runtime.DefaultUnstructuredConverter.ToUnstructured(&dep)
+               if err == nil {
+                       un := &unstructured.Unstructured{}
+                       un.SetUnstructuredContent(newUnstr)
+                       DeploymentUpdateStatus(rbstate, un)
+               } else {
+                       return err
+               }
+       }
+       return nil
+}
+
+func (r *ResourceBundleStateReconciler) updateDaemonSets(rbstate *k8spluginv1alpha1.ResourceBundleState,
+       selectors map[string]string) error {
+
+       // Update the CR with the DaemonSets created as well
+       daemonSetList := &appsv1.DaemonSetList{}
+       err := listResources(r.Client, rbstate.Namespace, selectors, daemonSetList)
+       if err != nil {
+               log.Printf("Failed to list DaemonSets: %v", err)
+               return err
+       }
+
+       for _, ds := range daemonSetList.Items {
+               newUnstr, err := runtime.DefaultUnstructuredConverter.ToUnstructured(&ds)
+               if err == nil {
+                       un := &unstructured.Unstructured{}
+                       un.SetUnstructuredContent(newUnstr)
+                       DaemonSetUpdateStatus(rbstate, un)
+               } else {
+                       return err
+               }
+       }
+
+       return nil
+}
+
+func (r *ResourceBundleStateReconciler) updateJobs(rbstate *k8spluginv1alpha1.ResourceBundleState,
+       selectors map[string]string) error {
+
+       // Update the CR with the Services created as well
+       jobList := &v1.JobList{}
+       err := listResources(r.Client, rbstate.Namespace, selectors, jobList)
+       if err != nil {
+               log.Printf("Failed to list jobs: %v", err)
+               return err
+       }
+
+       for _, job := range jobList.Items {
+               newUnstr, err := runtime.DefaultUnstructuredConverter.ToUnstructured(&job)
+               if err == nil {
+                       un := &unstructured.Unstructured{}
+                       un.SetUnstructuredContent(newUnstr)
+                       JobUpdateStatus(rbstate, un)
+               } else {
+                       return err
+               }
+       }
+
+       return nil
+}
+
+func (r *ResourceBundleStateReconciler) updateStatefulSets(rbstate *k8spluginv1alpha1.ResourceBundleState,
+       selectors map[string]string) error {
+
+       // Update the CR with the StatefulSets created as well
+       statefulSetList := &appsv1.StatefulSetList{}
+       err := listResources(r.Client, rbstate.Namespace, selectors, statefulSetList)
+       if err != nil {
+               log.Printf("Failed to list statefulSets: %v", err)
+               return err
+       }
+
+       for _, sfs := range statefulSetList.Items {
+               newUnstr, err := runtime.DefaultUnstructuredConverter.ToUnstructured(&sfs)
+               if err == nil {
+                       un := &unstructured.Unstructured{}
+                       un.SetUnstructuredContent(newUnstr)
+                       StatefulSetUpdateStatus(rbstate, un)
+               } else {
+                       return err
+               }
+       }
+
+       return nil
+}
+
+func (r *ResourceBundleStateReconciler) updateCsrs(rbstate *k8spluginv1alpha1.ResourceBundleState,
+       selectors map[string]string) error {
+
+       // Update the CR with the csrs tracked
+       csrList := &certsapi.CertificateSigningRequestList{}
+       err := listResources(r.Client, "", selectors, csrList)
+       if err != nil {
+               log.Printf("Failed to list csrs: %v", err)
+               return err
+       }
+
+       rbstate.Status.CsrStatuses = []certsapi.CertificateSigningRequest{}
+
+       for _, csr := range csrList.Items {
+               resStatus := certsapi.CertificateSigningRequest{
+                       TypeMeta:   csr.TypeMeta,
+                       ObjectMeta: csr.ObjectMeta,
+                       Status:     csr.Status,
+                       Spec:       csr.Spec,
+               }
+               resStatus.ObjectMeta.ManagedFields = []metav1.ManagedFieldsEntry{}
+               resStatus.Annotations = ClearLastApplied(resStatus.Annotations)
+               rbstate.Status.CsrStatuses = append(rbstate.Status.CsrStatuses, resStatus)
+       }
+       return nil
+}
+
+// updateDynResources updates non default resources
+func (r *ResourceBundleStateReconciler) updateDynResources(rbstate *k8spluginv1alpha1.ResourceBundleState,
+       selectors map[string]string) error {
+
+       for gvk, item := range GvkMap {
+               if item.defaultRes {
+                       // Already handled
+                       continue
+               }
+               resourceList := &unstructured.UnstructuredList{}
+               resourceList.SetGroupVersionKind(gvk)
+
+               err := listResources(r.Client, rbstate.Namespace, selectors, resourceList)
+               if err != nil {
+                       log.Printf("Failed to list resources: %v", err)
+                       return err
+               }
+               for _, res := range resourceList.Items {
+                       err = UpdateResourceStatus(r.Client, &res, res.GetName(), res.GetNamespace())
+                       if err != nil {
+                               log.Println("Error updating status for resource", gvk, res.GetName())
+                       }
+               }
+       }
+       return nil
+}
diff --git a/central-controller/src/monitor/controllers/resources.go b/central-controller/src/monitor/controllers/resources.go
new file mode 100644 (file)
index 0000000..fdbddb6
--- /dev/null
@@ -0,0 +1,412 @@
+// SPDX-License-Identifier: Apache-2.0
+// Copyright (c) 2022 Intel Corporation
+
+package controllers
+
+import (
+       "fmt"
+       k8spluginv1alpha1 "gitlab.com/project-emco/core/emco-base/src/monitor/pkg/apis/k8splugin/v1alpha1"
+       appsv1 "k8s.io/api/apps/v1"
+       batchv1 "k8s.io/api/batch/v1"
+       certsapi "k8s.io/api/certificates/v1"
+       v1 "k8s.io/api/core/v1"
+       metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
+       "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
+       "k8s.io/apimachinery/pkg/runtime"
+)
+
+func ServiceUpdateStatus(cr *k8spluginv1alpha1.ResourceBundleState, obj *unstructured.Unstructured) (bool, error) {
+       var found bool
+       var service v1.Service
+       // Convert the unstructured object to actual
+       unstructured := obj.UnstructuredContent()
+       err := runtime.DefaultUnstructuredConverter.FromUnstructured(unstructured, &service)
+       if err != nil {
+               return found, fmt.Errorf("Unknown resource %v", obj)
+       }
+       for i, rstatus := range cr.Status.ServiceStatuses {
+               // Look for the status if we already have it in the CR
+               if rstatus.Name == service.Name {
+                       service.Status.DeepCopyInto(&cr.Status.ServiceStatuses[i].Status)
+                       found = true
+                       break
+               }
+       }
+       if !found {
+               // Add it to CR
+               svc := v1.Service{
+                       TypeMeta:   service.TypeMeta,
+                       ObjectMeta: service.ObjectMeta,
+                       Status:     service.Status,
+                       Spec:       service.Spec,
+               }
+               svc.ObjectMeta.ManagedFields = []metav1.ManagedFieldsEntry{}
+               svc.ObjectMeta.Annotations = ClearLastApplied(svc.Annotations)
+               cr.Status.ServiceStatuses = append(cr.Status.ServiceStatuses, svc)
+       }
+       return found, nil
+}
+
+func ServiceDeleteObj(cr *k8spluginv1alpha1.ResourceBundleState, name string) (bool, error) {
+       var found bool
+       length := len(cr.Status.ServiceStatuses)
+       for i, rstatus := range cr.Status.ServiceStatuses {
+               if rstatus.Name == name {
+                       found = true
+                       //Delete that status from the array
+                       cr.Status.ServiceStatuses[i] = cr.Status.ServiceStatuses[length-1]
+                       cr.Status.ServiceStatuses[length-1] = v1.Service{}
+                       cr.Status.ServiceStatuses = cr.Status.ServiceStatuses[:length-1]
+                       break
+               }
+       }
+       return found, nil
+}
+
+func ConfigMapDeleteObj(cr *k8spluginv1alpha1.ResourceBundleState, name string) (bool, error) {
+       var found bool
+       length := len(cr.Status.ConfigMapStatuses)
+       for i, rstatus := range cr.Status.ConfigMapStatuses {
+               if rstatus.Name == name {
+                       found = true
+                       //Delete that status from the array
+                       cr.Status.ConfigMapStatuses[i] = cr.Status.ConfigMapStatuses[length-1]
+                       cr.Status.ConfigMapStatuses = cr.Status.ConfigMapStatuses[:length-1]
+                       break
+               }
+       }
+       return found, nil
+}
+
+func ConfigMapUpdateStatus(cr *k8spluginv1alpha1.ResourceBundleState, obj *unstructured.Unstructured) (bool, error) {
+
+       var found bool
+       var cm v1.ConfigMap
+       // Convert the unstructured object to actual
+       unstructured := obj.UnstructuredContent()
+       err := runtime.DefaultUnstructuredConverter.FromUnstructured(unstructured, &cm)
+       if err != nil {
+               return found, fmt.Errorf("Unknown resource %v", obj)
+       }
+       // Update status after searching for it in the list of resourceStatuses
+       for _, rstatus := range cr.Status.ConfigMapStatuses {
+               // Look for the status if we already have it in the CR
+               if rstatus.Name == cm.Name {
+                       found = true
+                       break
+               }
+       }
+
+       if !found {
+               // Add it to CR
+               c := v1.ConfigMap{
+                       TypeMeta:   cm.TypeMeta,
+                       ObjectMeta: cm.ObjectMeta,
+               }
+               c.ObjectMeta.ManagedFields = []metav1.ManagedFieldsEntry{}
+               c.Annotations = ClearLastApplied(c.Annotations)
+               cr.Status.ConfigMapStatuses = append(cr.Status.ConfigMapStatuses, c)
+       }
+
+       return found, nil
+}
+
+func DaemonSetDeleteObj(cr *k8spluginv1alpha1.ResourceBundleState, name string) (bool, error) {
+       var found bool
+       length := len(cr.Status.DaemonSetStatuses)
+       for i, rstatus := range cr.Status.DaemonSetStatuses {
+               if rstatus.Name == name {
+                       found = true
+                       //Delete that status from the array
+                       cr.Status.DaemonSetStatuses[i] = cr.Status.DaemonSetStatuses[length-1]
+                       cr.Status.DaemonSetStatuses[length-1].Status = appsv1.DaemonSetStatus{}
+                       cr.Status.DaemonSetStatuses = cr.Status.DaemonSetStatuses[:length-1]
+                       break
+               }
+       }
+       return found, nil
+}
+
+func DaemonSetUpdateStatus(cr *k8spluginv1alpha1.ResourceBundleState, obj *unstructured.Unstructured) (bool, error) {
+
+       var found bool
+       var ds appsv1.DaemonSet
+       // Convert the unstructured object to actual
+       unstructured := obj.UnstructuredContent()
+       err := runtime.DefaultUnstructuredConverter.FromUnstructured(unstructured, &ds)
+       if err != nil {
+               return found, fmt.Errorf("Unknown resource %v", obj)
+       }
+       // Update status after searching for it in the list of resourceStatuses
+       for i, rstatus := range cr.Status.DaemonSetStatuses {
+               // Look for the status if we already have it in the CR
+               if rstatus.Name == ds.Name {
+                       ds.Status.DeepCopyInto(&cr.Status.DaemonSetStatuses[i].Status)
+                       found = true
+                       break
+               }
+       }
+       if !found {
+               // Add it to CR
+               c := appsv1.DaemonSet{
+                       TypeMeta:   ds.TypeMeta,
+                       ObjectMeta: ds.ObjectMeta,
+                       Spec:       ds.Spec,
+                       Status:     ds.Status,
+               }
+               c.ObjectMeta.ManagedFields = []metav1.ManagedFieldsEntry{}
+               c.Annotations = ClearLastApplied(c.Annotations)
+               cr.Status.DaemonSetStatuses = append(cr.Status.DaemonSetStatuses, c)
+       }
+       return found, nil
+}
+
+func DeploymentDeleteObj(cr *k8spluginv1alpha1.ResourceBundleState, name string) (bool, error) {
+       var found bool
+       length := len(cr.Status.DeploymentStatuses)
+       for i, rstatus := range cr.Status.DeploymentStatuses {
+               if rstatus.Name == name {
+                       found = true
+                       //Delete that status from the array
+                       cr.Status.DeploymentStatuses[i] = cr.Status.DeploymentStatuses[length-1]
+                       cr.Status.DeploymentStatuses[length-1].Status = appsv1.DeploymentStatus{}
+                       cr.Status.DeploymentStatuses = cr.Status.DeploymentStatuses[:length-1]
+                       break
+               }
+       }
+       return found, nil
+}
+
+func DeploymentUpdateStatus(cr *k8spluginv1alpha1.ResourceBundleState, obj *unstructured.Unstructured) (bool, error) {
+
+       var found bool
+       var dm appsv1.Deployment
+       // Convert the unstructured object to actual
+       unstructured := obj.UnstructuredContent()
+       err := runtime.DefaultUnstructuredConverter.FromUnstructured(unstructured, &dm)
+       if err != nil {
+               return found, fmt.Errorf("Unknown resource %v", obj)
+       }
+       // Update status after searching for it in the list of resourceStatuses
+       for i, rstatus := range cr.Status.DeploymentStatuses {
+               // Look for the status if we already have it in the CR
+               if rstatus.Name == dm.Name {
+                       dm.Status.DeepCopyInto(&cr.Status.DeploymentStatuses[i].Status)
+                       found = true
+                       break
+               }
+       }
+       if !found {
+               // Add it to CR
+               c := appsv1.Deployment{
+                       TypeMeta:   dm.TypeMeta,
+                       ObjectMeta: dm.ObjectMeta,
+                       Spec:       dm.Spec,
+                       Status:     dm.Status,
+               }
+               c.ObjectMeta.ManagedFields = []metav1.ManagedFieldsEntry{}
+               c.Annotations = ClearLastApplied(c.Annotations)
+               cr.Status.DeploymentStatuses = append(cr.Status.DeploymentStatuses, c)
+       }
+       return found, nil
+}
+
+func JobDeleteObj(cr *k8spluginv1alpha1.ResourceBundleState, name string) (bool, error) {
+       var found bool
+       length := len(cr.Status.JobStatuses)
+       for i, rstatus := range cr.Status.JobStatuses {
+               if rstatus.Name == name {
+                       found = true
+                       //Delete that status from the array
+                       cr.Status.JobStatuses[i] = cr.Status.JobStatuses[length-1]
+                       cr.Status.JobStatuses[length-1].Status = batchv1.JobStatus{}
+                       cr.Status.JobStatuses = cr.Status.JobStatuses[:length-1]
+                       break
+               }
+       }
+       return found, nil
+}
+
+func JobUpdateStatus(cr *k8spluginv1alpha1.ResourceBundleState, obj *unstructured.Unstructured) (bool, error) {
+
+       var found bool
+       var job batchv1.Job
+       // Convert the unstructured object to actual
+       unstructured := obj.UnstructuredContent()
+       err := runtime.DefaultUnstructuredConverter.FromUnstructured(unstructured, &job)
+       if err != nil {
+               return found, fmt.Errorf("Unknown resource %v", obj)
+       }
+       // Update status after searching for it in the list of resourceStatuses
+       for i, rstatus := range cr.Status.JobStatuses {
+               // Look for the status if we already have it in the CR
+               if rstatus.Name == job.Name {
+                       job.Status.DeepCopyInto(&cr.Status.JobStatuses[i].Status)
+                       found = true
+                       break
+               }
+       }
+       if !found {
+               // Add it to CR
+               c := batchv1.Job{
+                       TypeMeta:   job.TypeMeta,
+                       ObjectMeta: job.ObjectMeta,
+                       Spec:       job.Spec,
+                       Status:     job.Status,
+               }
+               c.ObjectMeta.ManagedFields = []metav1.ManagedFieldsEntry{}
+               c.Annotations = ClearLastApplied(c.Annotations)
+               cr.Status.JobStatuses = append(cr.Status.JobStatuses, c)
+       }
+       return found, nil
+}
+
+func PodUpdateStatus(cr *k8spluginv1alpha1.ResourceBundleState, obj *unstructured.Unstructured) (bool, error) {
+       var found bool
+
+       // Convert the unstructured object to actual
+       unstructured := obj.UnstructuredContent()
+       var pod v1.Pod
+       err := runtime.DefaultUnstructuredConverter.FromUnstructured(unstructured, &pod)
+       if err != nil {
+               return found, fmt.Errorf("Unknown resource %v", obj)
+       }
+       for i, rstatus := range cr.Status.PodStatuses {
+               // Look for the status if we already have it in the CR
+               if rstatus.Name == pod.Name {
+                       pod.Status.DeepCopyInto(&cr.Status.PodStatuses[i].Status)
+                       found = true
+                       break
+               }
+       }
+       if !found {
+               // Add it to CR
+               ps := v1.Pod{
+                       TypeMeta:   pod.TypeMeta,
+                       ObjectMeta: pod.ObjectMeta,
+                       Status:     pod.Status,
+                       Spec:       pod.Spec,
+               }
+               ps.ObjectMeta = metav1.ObjectMeta{}
+               ps.ObjectMeta.Name = pod.GetName()
+               ps.ObjectMeta.ManagedFields = []metav1.ManagedFieldsEntry{}
+               ps.Annotations = ClearLastApplied(ps.Annotations)
+               cr.Status.PodStatuses = append(cr.Status.PodStatuses, ps)
+       }
+       return found, nil
+}
+
+func PodDeleteObj(cr *k8spluginv1alpha1.ResourceBundleState, name string) (bool, error) {
+       var found bool
+       length := len(cr.Status.PodStatuses)
+       for i, rstatus := range cr.Status.PodStatuses {
+               if rstatus.Name == name {
+                       found = true
+                       //Delete that status from the array
+                       cr.Status.PodStatuses[i] = cr.Status.PodStatuses[length-1]
+                       cr.Status.PodStatuses[length-1] = v1.Pod{}
+                       cr.Status.PodStatuses = cr.Status.PodStatuses[:length-1]
+                       break
+               }
+       }
+       return found, nil
+}
+
+func StatefulSetDeleteObj(cr *k8spluginv1alpha1.ResourceBundleState, name string) (bool, error) {
+       var found bool
+       length := len(cr.Status.StatefulSetStatuses)
+       for i, rstatus := range cr.Status.StatefulSetStatuses {
+               if rstatus.Name == name {
+                       found = true
+                       //Delete that status from the array
+                       cr.Status.StatefulSetStatuses[i] = cr.Status.StatefulSetStatuses[length-1]
+                       cr.Status.StatefulSetStatuses[length-1].Status = appsv1.StatefulSetStatus{}
+                       cr.Status.StatefulSetStatuses = cr.Status.StatefulSetStatuses[:length-1]
+                       break
+               }
+       }
+       return found, nil
+}
+
+func StatefulSetUpdateStatus(cr *k8spluginv1alpha1.ResourceBundleState, obj *unstructured.Unstructured) (bool, error) {
+
+       var found bool
+       var ss appsv1.StatefulSet
+
+       // Convert the unstructured object to actual
+       unstructured := obj.UnstructuredContent()
+       err := runtime.DefaultUnstructuredConverter.FromUnstructured(unstructured, &ss)
+       if err != nil {
+               return found, fmt.Errorf("Unknown resource %v", obj)
+       }
+       // Update status after searching for it in the list of resourceStatuses
+       for i, rstatus := range cr.Status.StatefulSetStatuses {
+               // Look for the status if we already have it in the CR
+               if rstatus.Name == ss.Name {
+                       ss.Status.DeepCopyInto(&cr.Status.StatefulSetStatuses[i].Status)
+                       found = true
+                       break
+               }
+       }
+       if !found {
+               // Add it to CR
+               c := appsv1.StatefulSet{
+                       TypeMeta:   ss.TypeMeta,
+                       ObjectMeta: ss.ObjectMeta,
+                       Spec:       ss.Spec,
+                       Status:     ss.Status,
+               }
+               c.ObjectMeta.ManagedFields = []metav1.ManagedFieldsEntry{}
+               c.Annotations = ClearLastApplied(c.Annotations)
+               cr.Status.StatefulSetStatuses = append(cr.Status.StatefulSetStatuses, c)
+       }
+       return found, nil
+}
+
+func CsrDeleteObj(cr *k8spluginv1alpha1.ResourceBundleState, name string) (bool, error) {
+       var found bool
+       length := len(cr.Status.CsrStatuses)
+       for i, rstatus := range cr.Status.CsrStatuses {
+               if rstatus.Name == name {
+                       found = true
+                       //Delete that status from the array
+                       cr.Status.CsrStatuses[i] = cr.Status.CsrStatuses[length-1]
+                       cr.Status.CsrStatuses[length-1] = certsapi.CertificateSigningRequest{}
+                       cr.Status.CsrStatuses = cr.Status.CsrStatuses[:length-1]
+                       break
+               }
+       }
+       return found, nil
+}
+
+func CsrUpdateStatus(cr *k8spluginv1alpha1.ResourceBundleState, obj *unstructured.Unstructured) (bool, error) {
+
+       var found bool
+       var csr *certsapi.CertificateSigningRequest
+
+       // Convert the unstructured object to actual
+       unstructured := obj.UnstructuredContent()
+       err := runtime.DefaultUnstructuredConverter.FromUnstructured(unstructured, &csr)
+       if err != nil {
+               return found, fmt.Errorf("Unknown resource %v", obj)
+       }
+       // Update status after searching for it in the list of resourceStatuses
+       for i, rstatus := range cr.Status.CsrStatuses {
+               // Look for the status if we already have it in the CR
+               if rstatus.Name == csr.Name {
+                       csr.Status.DeepCopyInto(&cr.Status.CsrStatuses[i].Status)
+                       found = true
+                       break
+               }
+       }
+       if !found {
+               // Add it to CR
+               cr.Status.CsrStatuses = append(cr.Status.CsrStatuses, certsapi.CertificateSigningRequest{
+                       TypeMeta:   csr.TypeMeta,
+                       ObjectMeta: csr.ObjectMeta,
+                       Status:     csr.Status,
+                       Spec:       csr.Spec,
+               })
+       }
+       return found, nil
+}
diff --git a/central-controller/src/monitor/controllers/suite_test.go b/central-controller/src/monitor/controllers/suite_test.go
new file mode 100644 (file)
index 0000000..6d6e4e4
--- /dev/null
@@ -0,0 +1,67 @@
+// SPDX-License-Identifier: Apache-2.0
+// Copyright (c) 2022 Intel Corporation
+
+package controllers
+
+import (
+       "path/filepath"
+       "testing"
+
+       . "github.com/onsi/ginkgo"
+       . "github.com/onsi/gomega"
+       "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"
+       //      "sigs.k8s.io/controller-runtime/pkg/envtest/printer"
+       logf "sigs.k8s.io/controller-runtime/pkg/log"
+       "sigs.k8s.io/controller-runtime/pkg/log/zap"
+
+       k8spluginv1alpha1 "gitlab.com/project-emco/core/emco-base/src/monitor/pkg/apis/k8splugin/v1alpha1"
+       //+kubebuilder:scaffold:imports
+)
+
+// These tests use Ginkgo (BDD-style Go testing framework). Refer to
+// http://onsi.github.io/ginkgo/ to learn more about Ginkgo.
+
+var cfg *rest.Config
+var k8sClient client.Client
+var testEnv *envtest.Environment
+
+func TestAPIs(t *testing.T) {
+       RegisterFailHandler(Fail)
+
+       //      RunSpecsWithDefaultAndCustomReporters(t,
+       //              "Controller Suite",
+       //              []Reporter{printer.NewlineReporter{}})
+}
+
+var _ = BeforeSuite(func() {
+       logf.SetLogger(zap.New(zap.WriteTo(GinkgoWriter), zap.UseDevMode(true)))
+
+       By("bootstrapping test environment")
+       testEnv = &envtest.Environment{
+               CRDDirectoryPaths:     []string{filepath.Join("..", "config", "crd", "bases")},
+               ErrorIfCRDPathMissing: true,
+       }
+
+       cfg, err := testEnv.Start()
+       Expect(err).NotTo(HaveOccurred())
+       Expect(cfg).NotTo(BeNil())
+
+       err = k8spluginv1alpha1.AddToScheme(scheme.Scheme)
+       Expect(err).NotTo(HaveOccurred())
+
+       //+kubebuilder:scaffold:scheme
+
+       k8sClient, err = client.New(cfg, client.Options{Scheme: scheme.Scheme})
+       Expect(err).NotTo(HaveOccurred())
+       Expect(k8sClient).NotTo(BeNil())
+
+}, 60)
+
+var _ = AfterSuite(func() {
+       By("tearing down the test environment")
+       err := testEnv.Stop()
+       Expect(err).NotTo(HaveOccurred())
+})
index afffcef..0bfd3b2 100644 (file)
@@ -1,81 +1,83 @@
-module github.com/open-ness/EMCO/src/monitor
+module gitlab.com/project-emco/core/emco-base/src/monitor
 
 go 1.17
 
 require (
-       github.com/go-openapi/spec v0.19.4
-       github.com/operator-framework/operator-sdk v0.19.0
-       github.com/spf13/pflag v1.0.5
-       k8s.io/api v0.19.4
-       k8s.io/apimachinery v0.19.4
-       k8s.io/client-go v12.0.0+incompatible
-       k8s.io/kube-openapi v0.0.0-20200805222855-6aeccd4b50c6
-       sigs.k8s.io/controller-runtime v0.6.0
-       sigs.k8s.io/controller-tools v0.3.0
+       github.com/fluxcd/go-git-providers v0.5.4
+       github.com/onsi/ginkgo v1.16.5
+       github.com/onsi/gomega v1.17.0
+       k8s.io/api v0.23.1
+       k8s.io/apimachinery v0.23.1
+       k8s.io/client-go v0.23.1
+       sigs.k8s.io/controller-runtime v0.11.0
 )
 
 require (
-       github.com/PuerkitoBio/purell v1.1.1 // indirect
-       github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578 // indirect
+       cloud.google.com/go v0.81.0 // indirect
+       github.com/Azure/go-autorest v14.2.0+incompatible // indirect
+       github.com/Azure/go-autorest/autorest v0.11.18 // indirect
+       github.com/Azure/go-autorest/autorest/adal v0.9.13 // indirect
+       github.com/Azure/go-autorest/autorest/date v0.3.0 // indirect
+       github.com/Azure/go-autorest/logger v0.2.1 // indirect
+       github.com/Azure/go-autorest/tracing v0.6.0 // indirect
        github.com/beorn7/perks v1.0.1 // indirect
        github.com/cespare/xxhash/v2 v2.1.1 // indirect
        github.com/davecgh/go-spew v1.1.1 // indirect
-       github.com/emicklei/go-restful v2.9.5+incompatible // indirect
-       github.com/evanphx/json-patch v4.9.0+incompatible // indirect
-       github.com/fsnotify/fsnotify v1.4.9 // indirect
-       github.com/go-logr/logr v0.2.1 // indirect
-       github.com/go-logr/zapr v0.2.0 // indirect
-       github.com/go-openapi/jsonpointer v0.19.3 // indirect
-       github.com/go-openapi/jsonreference v0.19.3 // indirect
-       github.com/go-openapi/swag v0.19.5 // indirect
-       github.com/gobuffalo/flect v0.2.1 // indirect
-       github.com/gogo/protobuf v1.3.1 // indirect
-       github.com/golang/groupcache v0.0.0-20191227052852-215e87163ea7 // indirect
-       github.com/golang/protobuf v1.4.2 // indirect
-       github.com/google/go-cmp v0.4.0 // indirect
+       github.com/evanphx/json-patch v4.12.0+incompatible // indirect
+       github.com/form3tech-oss/jwt-go v3.2.3+incompatible // indirect
+       github.com/fsnotify/fsnotify v1.5.1 // indirect
+       github.com/go-logr/logr v1.2.2 // indirect
+       github.com/go-logr/zapr v1.2.2 // indirect
+       github.com/gogo/protobuf v1.3.2 // indirect
+       github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect
+       github.com/golang/protobuf v1.5.2 // indirect
+       github.com/google/go-cmp v0.5.6 // indirect
+       github.com/google/go-github/v41 v41.0.0 // indirect
+       github.com/google/go-querystring v1.1.0 // indirect
        github.com/google/gofuzz v1.1.0 // indirect
-       github.com/google/uuid v1.1.1 // indirect
-       github.com/googleapis/gnostic v0.4.1 // indirect
-       github.com/hashicorp/golang-lru v0.5.4 // indirect
-       github.com/imdario/mergo v0.3.9 // indirect
-       github.com/json-iterator/go v1.1.10 // indirect
-       github.com/mailru/easyjson v0.7.0 // indirect
-       github.com/matttproud/golang_protobuf_extensions v1.0.1 // indirect
+       github.com/google/uuid v1.1.2 // indirect
+       github.com/googleapis/gnostic v0.5.5 // indirect
+       github.com/gregjones/httpcache v0.0.0-20190611155906-901d90724c79 // indirect
+       github.com/imdario/mergo v0.3.12 // indirect
+       github.com/json-iterator/go v1.1.12 // indirect
+       github.com/matttproud/golang_protobuf_extensions v1.0.2-0.20181231171920-c182affec369 // indirect
        github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
-       github.com/modern-go/reflect2 v1.0.1 // indirect
+       github.com/modern-go/reflect2 v1.0.2 // indirect
+       github.com/nxadm/tail v1.4.8 // indirect
        github.com/pkg/errors v0.9.1 // indirect
-       github.com/prometheus/client_golang v1.5.1 // indirect
+       github.com/prometheus/client_golang v1.11.0 // indirect
        github.com/prometheus/client_model v0.2.0 // indirect
-       github.com/prometheus/common v0.9.1 // indirect
-       github.com/prometheus/procfs v0.0.11 // indirect
-       go.uber.org/atomic v1.6.0 // indirect
-       go.uber.org/multierr v1.5.0 // indirect
-       go.uber.org/zap v1.14.1 // indirect
-       golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9 // indirect
-       golang.org/x/net v0.0.0-20200707034311-ab3426394381 // indirect
-       golang.org/x/oauth2 v0.0.0-20191202225959-858c2ad4c8b6 // indirect
-       golang.org/x/sys v0.0.0-20200622214017-ed371f2e16b4 // indirect
-       golang.org/x/text v0.3.3 // indirect
-       golang.org/x/time v0.0.0-20191024005414-555d28b269f0 // indirect
-       golang.org/x/tools v0.0.0-20200403190813-44a64ad78b9b // indirect
-       golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543 // indirect
-       gomodules.xyz/jsonpatch/v2 v2.0.1 // indirect
-       google.golang.org/appengine v1.6.5 // indirect
-       google.golang.org/protobuf v1.24.0 // indirect
+       github.com/prometheus/common v0.28.0 // indirect
+       github.com/prometheus/procfs v0.6.0 // indirect
+       github.com/spf13/pflag v1.0.5 // indirect
+       go.uber.org/atomic v1.7.0 // indirect
+       go.uber.org/multierr v1.6.0 // indirect
+       go.uber.org/zap v1.19.1 // indirect
+       golang.org/x/crypto v0.0.0-20211215153901-e495a2d5b3d3 // indirect
+       golang.org/x/net v0.0.0-20211209124913-491a49abca63 // indirect
+       golang.org/x/oauth2 v0.0.0-20210819190943-2bc19b11175f // indirect
+       golang.org/x/sys v0.0.0-20211029165221-6e7872819dc8 // indirect
+       golang.org/x/term v0.0.0-20210615171337-6886f2dfbf5b // indirect
+       golang.org/x/text v0.3.7 // indirect
+       golang.org/x/time v0.0.0-20210723032227-1f47c861a9ac // indirect
+       gomodules.xyz/jsonpatch/v2 v2.2.0 // indirect
+       google.golang.org/appengine v1.6.7 // indirect
+       google.golang.org/protobuf v1.27.1 // indirect
+       gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c // indirect
        gopkg.in/inf.v0 v0.9.1 // indirect
-       gopkg.in/yaml.v2 v2.3.0 // indirect
-       k8s.io/apiextensions-apiserver v0.18.6 // indirect
-       k8s.io/klog/v2 v2.2.0 // indirect
-       k8s.io/utils v0.0.0-20200729134348-d5654de09c73 // indirect
-       sigs.k8s.io/structured-merge-diff/v4 v4.0.1 // indirect
-       sigs.k8s.io/yaml v1.2.0 // indirect
+       gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 // indirect
+       gopkg.in/yaml.v2 v2.4.0 // indirect
+       gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b // indirect
+       k8s.io/apiextensions-apiserver v0.23.0 // indirect
+       k8s.io/component-base v0.23.0 // indirect
+       k8s.io/klog/v2 v2.30.0 // indirect
+       k8s.io/kube-openapi v0.0.0-20211115234752-e816edb12b65 // indirect
+       k8s.io/utils v0.0.0-20210930125809-cb0fa318a74b // indirect
+       sigs.k8s.io/json v0.0.0-20211020170558-c049b76a60c6 // indirect
+       sigs.k8s.io/structured-merge-diff/v4 v4.2.0 // indirect
+       sigs.k8s.io/yaml v1.3.0 // indirect
 )
 
-// Pinned to kubernetes-1.13.4
 replace (
-       github.com/Sirupsen/logrus => github.com/sirupsen/logrus v1.7.0
-       k8s.io/api => k8s.io/api v0.19.4
-       k8s.io/apimachinery => k8s.io/apimachinery v0.19.4
-       k8s.io/client-go => k8s.io/client-go v0.19.4
-       sigs.k8s.io/controller-runtime => sigs.k8s.io/controller-runtime v0.6.3
+       github.com/prometheus/client_golang => github.com/prometheus/client_golang v1.11.1
 )
index c492fdd..70210f7 100644 (file)
-bazil.org/fuse v0.0.0-20160811212531-371fbbdaa898/go.mod h1:Xbm+BRKSBEpa4q4hTSxohYNQpsxXPbPry4JJWOB3LB8=
 cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
 cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
-cloud.google.com/go v0.37.4/go.mod h1:NHPJ89PdicEuT9hdPXMROBD91xc5uRDxsMtSB16k7hw=
 cloud.google.com/go v0.38.0/go.mod h1:990N+gfupTy94rShfmMCWGDn0LpTmnzTp2qbd1dvSRU=
 cloud.google.com/go v0.44.1/go.mod h1:iSa0KzasP4Uvy3f1mN/7PiObzGgflwredwwASm/v6AU=
 cloud.google.com/go v0.44.2/go.mod h1:60680Gw3Yr4ikxnPRS/oxxkBccT6SA1yMk63TGekxKY=
 cloud.google.com/go v0.45.1/go.mod h1:RpBamKRgapWJb87xiFSdk4g1CME7QZg3uwTez+TSTjc=
 cloud.google.com/go v0.46.3/go.mod h1:a6bKKbmY7er1mI7TEI4lsAkts/mkhTSZK8w33B4RAg0=
-cloud.google.com/go v0.49.0/go.mod h1:hGvAdzcWNbyuxS3nWhD7H2cIJxjRRTRLQVB0bdputVY=
-cloud.google.com/go v0.51.0/go.mod h1:hWtGJ6gnXH+KgDv+V0zFGDvpi07n3z8ZNj3T1RW0Gcw=
+cloud.google.com/go v0.50.0/go.mod h1:r9sluTvynVuxRIOHXQEHMFffphuXHOMZMycpNR5e6To=
+cloud.google.com/go v0.52.0/go.mod h1:pXajvRH/6o3+F9jDHZWQ5PbGhn+o8w9qiu/CffaVdO4=
+cloud.google.com/go v0.53.0/go.mod h1:fp/UouUEsRkN6ryDKNW/Upv/JBKnv6WDthjR6+vze6M=
+cloud.google.com/go v0.54.0/go.mod h1:1rq2OEkV3YMf6n/9ZvGWI3GWw0VoqH/1x2nd8Is/bPc=
+cloud.google.com/go v0.56.0/go.mod h1:jr7tqZxxKOVYizybht9+26Z/gUq7tiRzu+ACVAMbKVk=
+cloud.google.com/go v0.57.0/go.mod h1:oXiQ6Rzq3RAkkY7N6t3TcE6jE+CIBBbA36lwQ1JyzZs=
+cloud.google.com/go v0.62.0/go.mod h1:jmCYTdRCQuc1PHIIJ/maLInMho30T/Y0M4hTdTShOYc=
+cloud.google.com/go v0.65.0/go.mod h1:O5N8zS7uWy9vkA9vayVHs65eM1ubvY4h553ofrNHObY=
+cloud.google.com/go v0.72.0/go.mod h1:M+5Vjvlc2wnp6tjzE102Dw08nGShTscUx2nZMufOKPI=
+cloud.google.com/go v0.74.0/go.mod h1:VV1xSbzvo+9QJOxLDaJfTjx5e+MePCpCWwvftOeQmWk=
+cloud.google.com/go v0.78.0/go.mod h1:QjdrLG0uq+YwhjoVOLsS1t7TW8fs36kLs4XO5R5ECHg=
+cloud.google.com/go v0.79.0/go.mod h1:3bzgcEeQlzbuEAYu4mrWhKqWjmpprinYgKJLgKHnbb8=
+cloud.google.com/go v0.81.0 h1:at8Tk2zUz63cLPR0JPWm5vp77pEZmzxEQBEfRKn1VV8=
+cloud.google.com/go v0.81.0/go.mod h1:mk/AM35KwGk/Nm2YSeZbxXdrNK3KZOYHmLkOqC2V6E0=
 cloud.google.com/go/bigquery v1.0.1/go.mod h1:i/xbL2UlR5RvWAURpBYZTtm/cXjCha9lbfbpx4poX+o=
 cloud.google.com/go/bigquery v1.3.0/go.mod h1:PjpwJnslEMmckchkHFfq+HTD2DmtT67aNFKH1/VBDHE=
+cloud.google.com/go/bigquery v1.4.0/go.mod h1:S8dzgnTigyfTmLBfrtrhyYhwRxG72rYxvftPBK2Dvzc=
+cloud.google.com/go/bigquery v1.5.0/go.mod h1:snEHRnqQbz117VIFhE8bmtwIDY80NLUZUMb4Nv6dBIg=
+cloud.google.com/go/bigquery v1.7.0/go.mod h1://okPTzCYNXSlb24MZs83e2Do+h+VXtc4gLoIoXIAPc=
+cloud.google.com/go/bigquery v1.8.0/go.mod h1:J5hqkt3O0uAFnINi6JXValWIb1v0goeZM77hZzJN/fQ=
 cloud.google.com/go/datastore v1.0.0/go.mod h1:LXYbyblFSglQ5pkeyhO+Qmw7ukd3C+pD7TKLgZqpHYE=
+cloud.google.com/go/datastore v1.1.0/go.mod h1:umbIZjpQpHh4hmRpGhH4tLFup+FVzqBi1b3c64qFpCk=
+cloud.google.com/go/firestore v1.1.0/go.mod h1:ulACoGHTpvq5r8rxGJ4ddJZBZqakUQqClKRT5SZwBmk=
 cloud.google.com/go/pubsub v1.0.1/go.mod h1:R0Gpsv3s54REJCy4fxDixWD93lHJMoZTyQ2kNxGRt3I=
+cloud.google.com/go/pubsub v1.1.0/go.mod h1:EwwdRX2sKPjnvnqCa270oGRyludottCI76h+R3AArQw=
+cloud.google.com/go/pubsub v1.2.0/go.mod h1:jhfEVHT8odbXTkndysNHCcx0awwzvfOlguIAii9o8iA=
+cloud.google.com/go/pubsub v1.3.1/go.mod h1:i+ucay31+CNRpDW4Lu78I4xXG+O1r/MAHgjpRVR+TSU=
 cloud.google.com/go/storage v1.0.0/go.mod h1:IhtSnM/ZTZV8YYJWCY8RULGVqBDmpoyjwiyrjsg+URw=
-cloud.google.com/go/storage v1.3.0/go.mod h1:9IAwXhoyBJ7z9LcAwkj0/7NnPzYaPeZxxVp3zm+5IqA=
-contrib.go.opencensus.io/exporter/ocagent v0.6.0/go.mod h1:zmKjrJcdo0aYcVS7bmEeSEBLPA9YJp5bjrofdU3pIXs=
+cloud.google.com/go/storage v1.5.0/go.mod h1:tpKbwo567HUNpVclU5sGELwQWBDZ8gh0ZeosJ0Rtdos=
+cloud.google.com/go/storage v1.6.0/go.mod h1:N7U0C8pVQ/+NIKOBQyamJIeKQKkZ+mxpohlUTyfDhBk=
+cloud.google.com/go/storage v1.8.0/go.mod h1:Wv1Oy7z6Yz3DshWRJFhqM/UCfaWIRTdp0RXyy7KQOVs=
+cloud.google.com/go/storage v1.10.0/go.mod h1:FLPqc6j+Ki4BU591ie1oL6qBQGu2Bl/tZ9ullr3+Kg0=
 dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU=
-github.com/Azure/azure-pipeline-go v0.2.1/go.mod h1:UGSo8XybXnIGZ3epmeBw7Jdz+HiUVpqIlpz/HKHylF4=
-github.com/Azure/azure-pipeline-go v0.2.2/go.mod h1:4rQ/NZncSvGqNkkOsNpOU1tgoNuIlp9AfUH5G1tvCHc=
-github.com/Azure/azure-sdk-for-go v16.2.1+incompatible/go.mod h1:9XXNKU+eRnpl9moKnB4QOLf1HestfXbmab5FXxiDBjc=
-github.com/Azure/azure-sdk-for-go v23.2.0+incompatible/go.mod h1:9XXNKU+eRnpl9moKnB4QOLf1HestfXbmab5FXxiDBjc=
-github.com/Azure/azure-sdk-for-go v36.1.0+incompatible/go.mod h1:9XXNKU+eRnpl9moKnB4QOLf1HestfXbmab5FXxiDBjc=
-github.com/Azure/azure-storage-blob-go v0.8.0/go.mod h1:lPI3aLPpuLTeUwh1sViKXFxwl2B6teiRqI0deQUvsw0=
-github.com/Azure/go-ansiterm v0.0.0-20170929234023-d6e3b3328b78/go.mod h1:LmzpDX56iTiv29bbRTIsUNlaFfuhWRQBWjQdVyAevI8=
-github.com/Azure/go-autorest v10.8.1+incompatible/go.mod h1:r+4oMnoxhatjLLJ6zxSWATqVooLgysK6ZNox3g/xq24=
-github.com/Azure/go-autorest v11.2.8+incompatible/go.mod h1:r+4oMnoxhatjLLJ6zxSWATqVooLgysK6ZNox3g/xq24=
-github.com/Azure/go-autorest/autorest v0.9.0/go.mod h1:xyHB1BMZT0cuDHU7I0+g046+BFDTQ8rEZB0s4Yfa6bI=
-github.com/Azure/go-autorest/autorest v0.9.3-0.20191028180845-3492b2aff503/go.mod h1:xyHB1BMZT0cuDHU7I0+g046+BFDTQ8rEZB0s4Yfa6bI=
-github.com/Azure/go-autorest/autorest v0.9.6/go.mod h1:/FALq9T/kS7b5J5qsQ+RSTUdAmGFqi0vUdVNNx8q630=
-github.com/Azure/go-autorest/autorest/adal v0.5.0/go.mod h1:8Z9fGy2MpX0PvDjB1pEgQTmVqjGhiHBW7RJJEciWzS0=
-github.com/Azure/go-autorest/autorest/adal v0.8.1-0.20191028180845-3492b2aff503/go.mod h1:Z6vX6WXXuyieHAXwMj0S6HY6e6wcHn37qQMBQlvY3lc=
-github.com/Azure/go-autorest/autorest/adal v0.8.2/go.mod h1:ZjhuQClTqx435SRJ2iMlOxPYt3d2C/T/7TiQCVZSn3Q=
-github.com/Azure/go-autorest/autorest/date v0.1.0/go.mod h1:plvfp3oPSKwf2DNjlBjWF/7vwR+cUD/ELuzDCXwHUVA=
-github.com/Azure/go-autorest/autorest/date v0.2.0/go.mod h1:vcORJHLJEh643/Ioh9+vPmf1Ij9AEBM5FuBIXLmIy0g=
-github.com/Azure/go-autorest/autorest/mocks v0.1.0/go.mod h1:OTyCOPRA2IgIlWxVYxBee2F5Gr4kF2zd2J5cFRaIDN0=
-github.com/Azure/go-autorest/autorest/mocks v0.2.0/go.mod h1:OTyCOPRA2IgIlWxVYxBee2F5Gr4kF2zd2J5cFRaIDN0=
-github.com/Azure/go-autorest/autorest/mocks v0.3.0/go.mod h1:a8FDP3DYzQ4RYfVAxAN3SVSiiO77gL2j2ronKKP0syM=
-github.com/Azure/go-autorest/autorest/to v0.3.1-0.20191028180845-3492b2aff503/go.mod h1:MgwOyqaIuKdG4TL/2ywSsIWKAfJfgHDo8ObuUk3t5sA=
-github.com/Azure/go-autorest/autorest/validation v0.2.1-0.20191028180845-3492b2aff503/go.mod h1:3EEqHnBxQGHXRYq3HT1WyXAvT7LLY3tl70hw6tQIbjI=
-github.com/Azure/go-autorest/logger v0.1.0/go.mod h1:oExouG+K6PryycPJfVSxi/koC6LSNgds39diKLz7Vrc=
-github.com/Azure/go-autorest/tracing v0.5.0/go.mod h1:r/s2XiOKccPW3HrqB+W0TQzfbtp2fGCgRFtBroKn4Dk=
-github.com/BurntSushi/toml v0.3.1 h1:WXkYYl6Yr3qBf1K79EBnL4mak0OimBfB0XUf9Vl28OQ=
+github.com/Azure/go-ansiterm v0.0.0-20210608223527-2377c96fe795/go.mod h1:LmzpDX56iTiv29bbRTIsUNlaFfuhWRQBWjQdVyAevI8=
+github.com/Azure/go-ansiterm v0.0.0-20210617225240-d185dfc1b5a1/go.mod h1:xomTg63KZ2rFqZQzSB4Vz2SUXa1BpHTVz9L5PTmPC4E=
+github.com/Azure/go-autorest v14.2.0+incompatible h1:V5VMDjClD3GiElqLWO7mz2MxNAK/vTfRHdAubSIPRgs=
+github.com/Azure/go-autorest v14.2.0+incompatible/go.mod h1:r+4oMnoxhatjLLJ6zxSWATqVooLgysK6ZNox3g/xq24=
+github.com/Azure/go-autorest/autorest v0.11.18 h1:90Y4srNYrwOtAgVo3ndrQkTYn6kf1Eg/AjTFJ8Is2aM=
+github.com/Azure/go-autorest/autorest v0.11.18/go.mod h1:dSiJPy22c3u0OtOKDNttNgqpNFY/GeWa7GH/Pz56QRA=
+github.com/Azure/go-autorest/autorest/adal v0.9.13 h1:Mp5hbtOePIzM8pJVRa3YLrWWmZtoxRXqUEzCfJt3+/Q=
+github.com/Azure/go-autorest/autorest/adal v0.9.13/go.mod h1:W/MM4U6nLxnIskrw4UwWzlHfGjwUS50aOsc/I3yuU8M=
+github.com/Azure/go-autorest/autorest/date v0.3.0 h1:7gUk1U5M/CQbp9WoqinNzJar+8KY+LPI6wiWrP/myHw=
+github.com/Azure/go-autorest/autorest/date v0.3.0/go.mod h1:BI0uouVdmngYNUzGWeSYnokU+TrmwEsOqdt8Y6sso74=
+github.com/Azure/go-autorest/autorest/mocks v0.4.1 h1:K0laFcLE6VLTOwNgSxaGbUcLPuGXlNkbVvq4cW4nIHk=
+github.com/Azure/go-autorest/autorest/mocks v0.4.1/go.mod h1:LTp+uSrOhSkaKrUy935gNZuuIPPVsHlr9DSOxSayd+k=
+github.com/Azure/go-autorest/logger v0.2.1 h1:IG7i4p/mDa2Ce4TRyAO8IHnVhAVF3RFU+ZtXWSmf4Tg=
+github.com/Azure/go-autorest/logger v0.2.1/go.mod h1:T9E3cAhj2VqvPOtCYAvby9aBXkZmbF5NWuPV8+WeEW8=
+github.com/Azure/go-autorest/tracing v0.6.0 h1:TYi4+3m5t6K48TGI9AUdb+IzbnSxvnvUMfuitfgcfuo=
+github.com/Azure/go-autorest/tracing v0.6.0/go.mod h1:+vhtPC754Xsa23ID7GlGsrdKBpUA79WCAKPPZVC2DeU=
 github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
 github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo=
-github.com/DATA-DOG/go-sqlmock v1.4.1/go.mod h1:f/Ixk793poVmq4qj/V1dPUg2JEAKC73Q5eFN3EC/SaM=
-github.com/DataDog/datadog-go v3.2.0+incompatible/go.mod h1:LButxg5PwREeZtORoXG3tL4fMGNddJ+vMq1mwgfaqoQ=
-github.com/MakeNowJust/heredoc v0.0.0-20170808103936-bb23615498cd/go.mod h1:64YHyfSL2R96J44Nlwm39UHepQbyR5q10x7iYa1ks2E=
-github.com/Masterminds/goutils v1.1.0/go.mod h1:8cTjp+g8YejhMuvIA5y2vz3BpJxksy863GQaJW2MFNU=
-github.com/Masterminds/semver/v3 v3.1.0/go.mod h1:VPu/7SZ7ePZ3QOrcuXROw5FAcLl4a0cBrbBpGY/8hQs=
-github.com/Masterminds/sprig/v3 v3.1.0/go.mod h1:ONGMf7UfYGAbMXCZmQLy8x3lCDIPrEZE/rU8pmrbihA=
-github.com/Masterminds/squirrel v1.2.0/go.mod h1:yaPeOnPG5ZRwL9oKdTsO/prlkPbXWZlRVMQ/gGlzIuA=
-github.com/Masterminds/vcs v1.13.1/go.mod h1:N09YCmOQr6RLxC6UNHzuVwAdodYbbnycGHSmwVJjcKA=
-github.com/Microsoft/go-winio v0.4.11/go.mod h1:VhR8bwka0BXejwEJY73c50VrPtXAaKcyvVC4A4RozmA=
-github.com/Microsoft/go-winio v0.4.15-0.20190919025122-fc70bd9a86b5/go.mod h1:tTuCMEN+UleMWgg9dVx4Hu52b1bJo+59jBh3ajtinzw=
-github.com/Microsoft/hcsshim v0.8.7/go.mod h1:OHd7sQqRFrYd3RmSgbgji+ctCwkbq2wbEYNSzOYtcBQ=
-github.com/Microsoft/hcsshim v0.8.9/go.mod h1:5692vkUqntj1idxauYlpoINNKeqCiG6Sg38RRsjT5y8=
+github.com/Microsoft/go-winio v0.4.14/go.mod h1:qXqCSQ3Xa7+6tgxaGTIe4Kpcdsi+P8jBhyzoq1bpyYA=
+github.com/Microsoft/go-winio v0.4.16/go.mod h1:XB6nPKklQyQ7GC9LdcBEcBl8PF76WugXOPRXwdLnMv0=
 github.com/NYTimes/gziphandler v0.0.0-20170623195520-56545f4a5d46/go.mod h1:3wb06e3pkSAbeQ52E9H9iFoQsEEwGN64994WTCIhntQ=
 github.com/NYTimes/gziphandler v1.1.1/go.mod h1:n/CVRwUEOgIxrgPvAQhUUr9oeUtvrhMomdKFjzJNB0c=
-github.com/Nvveen/Gotty v0.0.0-20120604004816-cd527374f1e5/go.mod h1:lmUJ/7eu/Q8D7ML55dXQrVaamCz2vxCfdQBasLZfHKk=
 github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU=
-github.com/OneOfOne/xxhash v1.2.6/go.mod h1:eZbhyaAYD41SGSSsnmcpxVoRiQ/MPUTjUdIIOT9Um7Q=
-github.com/PuerkitoBio/purell v1.0.0/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbtSwDGJws/X0=
-github.com/PuerkitoBio/purell v1.1.0/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbtSwDGJws/X0=
-github.com/PuerkitoBio/purell v1.1.1 h1:WEQqlqaGbrPkxLJWfBwQmfEAE1Z7ONdDLqrN38tNFfI=
+github.com/ProtonMail/go-crypto v0.0.0-20210428141323-04723f9f07d7/go.mod h1:z4/9nQmJSSwwds7ejkxaJwO37dru3geImFUdJlaLzQo=
 github.com/PuerkitoBio/purell v1.1.1/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbtSwDGJws/X0=
-github.com/PuerkitoBio/urlesc v0.0.0-20160726150825-5bd2802263f2/go.mod h1:uGdkoq3SwY9Y+13GIhn11/XLaGBb4BfwItxLd5jeuXE=
-github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578 h1:d+Bc7a5rLufV/sSk/8dngufqelfh6jnri85riMAaF/M=
 github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578/go.mod h1:uGdkoq3SwY9Y+13GIhn11/XLaGBb4BfwItxLd5jeuXE=
-github.com/Shopify/logrus-bugsnag v0.0.0-20171204204709-577dee27f20d/go.mod h1:HI8ITrYtUY+O+ZhtlqUnD8+KwNPOyugEhfP9fdUIaEQ=
-github.com/Shopify/sarama v1.19.0/go.mod h1:FVkBWblsNy7DGZRfXLU0O9RCGt5g3g3yEuWXgklEdEo=
-github.com/Shopify/toxiproxy v2.1.4+incompatible/go.mod h1:OXgGpZ6Cli1/URJOF1DMxUHB2q5Ap20/P/eIdh4G0pI=
-github.com/agnivade/levenshtein v1.0.1/go.mod h1:CURSv5d9Uaml+FovSIICkLbAUZ9S4RqaHDIsdSBg7lM=
-github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
-github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
-github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=
-github.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=
+github.com/acomagu/bufpipe v1.0.3/go.mod h1:mxdxdup/WdsKVreO5GpW4+M/1CE2sMG4jeGJ2sYmHc4=
 github.com/alecthomas/units v0.0.0-20190924025748-f65c72e2690d/go.mod h1:rBZYJk541a8SKzHPHnH3zbiI+7dagKZ0cgpgrD7Fyho=
-github.com/aliyun/aliyun-oss-go-sdk v2.0.4+incompatible/go.mod h1:T/Aws4fEfogEE9v+HPhhw+CntffsBHJ8nXQCwKr0/g8=
-github.com/andreyvit/diff v0.0.0-20170406064948-c7f18ee00883/go.mod h1:rCTlJbsFo29Kk6CurOXKm700vrz8f0KW0JNfpkRJY/8=
-github.com/antihax/optional v0.0.0-20180407024304-ca021399b1a6/go.mod h1:V8iCPQYkqmusNa815XgQio277wI47sdRh1dUOLdyC6Q=
-github.com/apache/thrift v0.12.0/go.mod h1:cp2SuWMxlEZw2r+iP2GNCdIi4C1qmUzdZFSVb+bacwQ=
+github.com/anmitsu/go-shlex v0.0.0-20161002113705-648efa622239/go.mod h1:2FmKhYUyUczH0OGQWaF5ceTx0UBShxjsH6f8oGKYe2c=
+github.com/antihax/optional v1.0.0/go.mod h1:uupD/76wgC+ih3iEmQUL+0Ugr19nfwCT1kdvxnR2qWY=
+github.com/antlr/antlr4/runtime/Go/antlr v0.0.0-20210826220005-b48c857c3a0e/go.mod h1:F7bn7fEU90QkQ3tnmaTx3LTKLEDqnwWODIYppRQ5hnY=
 github.com/armon/circbuf v0.0.0-20150827004946-bbbad097214e/go.mod h1:3U/XgcO3hCbHZ8TKRvWD2dDTCfh9M9ya+I9JpbB7O8o=
-github.com/armon/consul-api v0.0.0-20180202201655-eb2c6b5be1b6/go.mod h1:grANhF5doyWs3UAsr3K4I6qtAmlQcZDesFNEHPZAzj8=
 github.com/armon/go-metrics v0.0.0-20180917152333-f0300d1749da/go.mod h1:Q73ZrmVTwzkszR9V5SSuryQ31EELlFMUz1kKyl939pY=
-github.com/armon/go-metrics v0.3.0/go.mod h1:zXjbSimjXTd7vOpY8B0/2LpvNvDoXBuplAD+gJD3GYs=
 github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8=
-github.com/armon/go-radix v1.0.0/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8=
-github.com/asaskevich/govalidator v0.0.0-20180720115003-f9ffefc3facf/go.mod h1:lB+ZfQJz7igIIfQNfa7Ml4HSf2uFQQRzpGGRXenZAgY=
+github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5/go.mod h1:wHh0iHkYZB8zMSxRWpUBQtwG5a7fFgvEO+odwuTv2gs=
 github.com/asaskevich/govalidator v0.0.0-20190424111038-f61b66f89f4a/go.mod h1:lB+ZfQJz7igIIfQNfa7Ml4HSf2uFQQRzpGGRXenZAgY=
-github.com/asaskevich/govalidator v0.0.0-20200108200545-475eaeb16496/go.mod h1:oGkLhpf+kjZl6xBf758TQhh5XrAeiJv/7FRz/2spLIg=
-github.com/aws/aws-sdk-go v1.15.11/go.mod h1:mFuSZ37Z9YOHbQEwBWztmVzqXrEkub65tZoCYDt7FT0=
-github.com/aws/aws-sdk-go v1.17.7/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo=
-github.com/aws/aws-sdk-go v1.25.48/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo=
-github.com/baiyubin/aliyun-sts-go-sdk v0.0.0-20180326062324-cfa1a18b161f/go.mod h1:AuiFmCCPBSrqvVMvuqFuk0qogytodnVFVSN5CeJB8Gc=
-github.com/beorn7/perks v0.0.0-20160804104726-4c0e84591b9a/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q=
-github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q=
-github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8=
+github.com/benbjohnson/clock v1.0.3/go.mod h1:bGMdMPoPVvcYyt1gHDf4J2KE153Yf9BuiUKYMaxlTDM=
+github.com/benbjohnson/clock v1.1.0 h1:Q92kusRqC1XV2MjkWETPvjJVqKetz1OzxZB7mHJLju8=
+github.com/benbjohnson/clock v1.1.0/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA=
 github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM=
 github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw=
 github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs=
-github.com/bitly/go-hostpool v0.0.0-20171023180738-a3a6125de932/go.mod h1:NOuUCSz6Q9T7+igc/hlvDOUdtWKryOrtFyIVABv/p7k=
-github.com/bitly/go-simplejson v0.5.0/go.mod h1:cXHtHw4XUPsvGaxgjIAn8PhEWG9NfngEKAMDJEczWVA=
-github.com/blang/semver v3.1.0+incompatible/go.mod h1:kRBLl5iJ+tD4TcOOxsy/0fnwebNt5EWlYSAyrTnjyyk=
-github.com/blang/semver v3.5.0+incompatible/go.mod h1:kRBLl5iJ+tD4TcOOxsy/0fnwebNt5EWlYSAyrTnjyyk=
+github.com/bketelsen/crypt v0.0.3-0.20200106085610-5cbc8cc4026c/go.mod h1:MKsuJmJgSg28kpZDP6UIiPt0e0Oz0kqKNGyRaWEPv84=
+github.com/bketelsen/crypt v0.0.4/go.mod h1:aI6NrJ0pMGgvZKL1iVgXLnfIFJtfV+bKCoqOes/6LfM=
 github.com/blang/semver v3.5.1+incompatible/go.mod h1:kRBLl5iJ+tD4TcOOxsy/0fnwebNt5EWlYSAyrTnjyyk=
-github.com/bmizerany/assert v0.0.0-20160611221934-b7ed37b82869/go.mod h1:Ekp36dRnpXw/yCqJaO+ZrUyxD+3VXMFFr56k5XYrpB4=
-github.com/bradfitz/gomemcache v0.0.0-20190913173617-a41fca850d0b/go.mod h1:H0wQNHz2YrLsuXOZozoeDmnHXkNCRmMW0gwFWDfEZDA=
-github.com/brancz/gojsontoyaml v0.0.0-20191212081931-bf2969bbd742/go.mod h1:IyUJYN1gvWjtLF5ZuygmxbnsAyP3aJS6cHzIuZY50B0=
-github.com/brancz/kube-rbac-proxy v0.5.0/go.mod h1:cL2VjiIFGS90Cjh5ZZ8+It6tMcBt8rwvuw2J6Mamnl0=
-github.com/bshuster-repo/logrus-logstash-hook v0.4.1/go.mod h1:zsTqEiSzDgAa/8GZR7E1qaXrhYNDKBYy5/dWPTIflbk=
-github.com/bugsnag/bugsnag-go v0.0.0-20141110184014-b1d153021fcd/go.mod h1:2oa8nejYd4cQ/b0hMIopN0lCRxU0bueqREvZLWFrtK8=
-github.com/bugsnag/osext v0.0.0-20130617224835-0dd3f918b21b/go.mod h1:obH5gd0BsqsP2LwDJ9aOkm/6J86V6lyAXCoQWGw3K50=
-github.com/bugsnag/panicwrap v0.0.0-20151223152923-e2c28503fcd0/go.mod h1:D/8v3kj0zr8ZAKg1AQ6crr+5VwKN5eIywRkfhyM/+dE=
-github.com/campoy/embedmd v1.0.0/go.mod h1:oxyr9RCiSXg0M3VJ3ks0UGfp98BpSSGr0kpiX3MzVl8=
-github.com/cenkalti/backoff v0.0.0-20181003080854-62661b46c409/go.mod h1:90ReRw6GdpyfrHakVjL/QHaoyV4aDUVVkXQJJJ3NXXM=
 github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
-github.com/cespare/xxhash v0.0.0-20181017004759-096ff4a8a059/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc=
+github.com/certifi/gocertifi v0.0.0-20191021191039-0944d244cd40/go.mod h1:sGbDF6GwGcLpkNXPUTkMRoywsNa/ol15pxFe6ERfguA=
+github.com/certifi/gocertifi v0.0.0-20200922220541-2c3bb06c6054/go.mod h1:sGbDF6GwGcLpkNXPUTkMRoywsNa/ol15pxFe6ERfguA=
 github.com/cespare/xxhash v1.1.0 h1:a6HrQnmkObjyL+Gs60czilIUGqrzKutQD6XZog3p+ko=
 github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc=
-github.com/cespare/xxhash/v2 v2.1.0/go.mod h1:dgIUBU3pDso/gPgZ1osOZ0iQf77oPR28Tjxl5dIMyVM=
 github.com/cespare/xxhash/v2 v2.1.1 h1:6MnRN8NT7+YBpUIWxHtefFZOKTAPgGjpQSxqLNn0+qY=
 github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
-github.com/chai2010/gettext-go v0.0.0-20160711120539-c6fed771bfd5/go.mod h1:/iP1qXHoty45bqomnu2LM+VVyAEdWN+vtSHGlQgyxbw=
 github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI=
 github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI=
 github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU=
-github.com/circonus-labs/circonus-gometrics v2.3.1+incompatible/go.mod h1:nmEj6Dob7S7YxXgwXpfOuvO54S+tGdZdw9fuRZt25Ag=
-github.com/circonus-labs/circonusllhist v0.1.3/go.mod h1:kMXHVDlOchFAehlya5ePtbp5jckzBHf4XRpQvBOLI+I=
 github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
-github.com/cockroachdb/apd v1.1.0/go.mod h1:8Sl8LxpKi29FqWXR16WEFZRNSz3SoPzUzeMeY4+DwBQ=
-github.com/cockroachdb/cockroach-go v0.0.0-20181001143604-e0a95dfd547c/go.mod h1:XGLbWH/ujMcbPbhZq52Nv6UrCghb1yGn//133kEsvDk=
-github.com/cockroachdb/datadriven v0.0.0-20190809214429-80d97fb3cbaa/go.mod h1:zn76sxSg3SzpJ0PPJaLDCu+Bu0Lg3sKTORVIj19EIF8=
-github.com/codahale/hdrhistogram v0.0.0-20161010025455-3a0bb77429bd/go.mod h1:sE/e/2PUdi/liOCUjSTXgM1o87ZssimdTWN964YiIeI=
-github.com/containerd/cgroups v0.0.0-20190919134610-bf292b21730f/go.mod h1:OApqhQ4XNSNC13gXIwDjhOQxjWa/NxkwZXJ1EvqT0ko=
-github.com/containerd/console v0.0.0-20180822173158-c12b1e7919c1/go.mod h1:Tj/on1eG8kiEhd0+fhSDzsPAFESxzBBvdyEgyryXffw=
-github.com/containerd/containerd v1.2.7/go.mod h1:bC6axHOhabU15QhwfG7w5PipXdVtMXFTttgp+kVtyUA=
-github.com/containerd/containerd v1.3.0-beta.2.0.20190828155532-0293cbd26c69/go.mod h1:bC6axHOhabU15QhwfG7w5PipXdVtMXFTttgp+kVtyUA=
-github.com/containerd/containerd v1.3.2/go.mod h1:bC6axHOhabU15QhwfG7w5PipXdVtMXFTttgp+kVtyUA=
-github.com/containerd/continuity v0.0.0-20190426062206-aaeac12a7ffc/go.mod h1:GL3xCUCBDV3CZiTSEKksMWbLE66hEyuu9qyDOOqM47Y=
-github.com/containerd/continuity v0.0.0-20200107194136-26c1120b8d41/go.mod h1:Dq467ZllaHgAtVp4p1xUQWBrFXR9s/wyoTpG8zOJGkY=
-github.com/containerd/continuity v0.0.0-20200413184840-d3ef23f19fbb/go.mod h1:Dq467ZllaHgAtVp4p1xUQWBrFXR9s/wyoTpG8zOJGkY=
-github.com/containerd/fifo v0.0.0-20190226154929-a9fb20d87448/go.mod h1:ODA38xgv3Kuk8dQz2ZQXpnv/UZZUHUCL7pnLehbXgQI=
-github.com/containerd/go-runc v0.0.0-20180907222934-5a6d9f37cfa3/go.mod h1:IV7qH3hrUgRmyYrtgEeGWJfWbgcHL9CSRruz2Vqcph0=
-github.com/containerd/ttrpc v0.0.0-20190828154514-0e0f228740de/go.mod h1:PvCDdDGpgqzQIzDW1TphrGLssLDZp2GuS+X5DkEJB8o=
-github.com/containerd/ttrpc v1.0.1/go.mod h1:UAxOpgT9ziI0gJrmKvgcZivgxOp8iFPSk8httJEt98Y=
-github.com/containerd/typeurl v0.0.0-20180627222232-a93fcdb778cd/go.mod h1:Cm3kwCdlkCfMSHURc+r6fwoGH6/F1hH3S4sg0rLFWPc=
-github.com/coreos/bbolt v1.3.1-coreos.6/go.mod h1:iRUV2dpdMOn7Bo10OQBFzIJO9kkE559Wcmn+qkEiiKk=
+github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc=
+github.com/cncf/udpa/go v0.0.0-20200629203442-efcf912fb354/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk=
+github.com/cncf/udpa/go v0.0.0-20201120205902-5459f2c99403/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk=
+github.com/cncf/xds/go v0.0.0-20210312221358-fbca930ec8ed/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs=
+github.com/cockroachdb/datadriven v0.0.0-20200714090401-bf6692d28da5/go.mod h1:h6jFvWxBdQXxjopDMZyH2UVceIRfR84bdzbkoKrsWNo=
+github.com/cockroachdb/errors v1.2.4/go.mod h1:rQD95gz6FARkaKkQXUksEje/d9a6wBJoCr5oaCLELYA=
+github.com/cockroachdb/logtags v0.0.0-20190617123548-eb05cc24525f/go.mod h1:i/u985jwjWRlyHXQbwatDASoW0RMlZ/3i9yJHE2xLkI=
 github.com/coreos/bbolt v1.3.2/go.mod h1:iRUV2dpdMOn7Bo10OQBFzIJO9kkE559Wcmn+qkEiiKk=
-github.com/coreos/etcd v3.3.10+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE=
-github.com/coreos/etcd v3.3.15+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE=
-github.com/coreos/go-etcd v2.0.0+incompatible/go.mod h1:Jez6KQU2B/sWsbdaef3ED8NzMklzPG4d5KIOhIy30Tk=
+github.com/coreos/etcd v3.3.13+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE=
 github.com/coreos/go-oidc v2.1.0+incompatible/go.mod h1:CgnwVTmzoESiwO9qyAFEMiHoZ1nMCKZlZ9V6mm3/LKc=
-github.com/coreos/go-semver v0.2.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk=
 github.com/coreos/go-semver v0.3.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk=
-github.com/coreos/go-systemd v0.0.0-20180511133405-39ca1b05acc7/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4=
 github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4=
-github.com/coreos/pkg v0.0.0-20160727233714-3ac0863d7acf/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA=
-github.com/coreos/pkg v0.0.0-20180108230652-97fdf19511ea/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA=
+github.com/coreos/go-systemd/v22 v22.3.2/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc=
 github.com/coreos/pkg v0.0.0-20180928190104-399ea9e2e55f/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA=
-github.com/coreos/prometheus-operator v0.38.1-0.20200424145508-7e176fda06cc/go.mod h1:erio69w1R/aC14D5nfvAXSlE8FT8jt2Hnavc50Dp33A=
-github.com/cpuguy83/go-md2man v1.0.10/go.mod h1:SmD6nW6nTyfqj6ABTjUi3V3JVMnlJmwcJI5acqYI6dE=
 github.com/cpuguy83/go-md2man/v2 v2.0.0/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU=
-github.com/creack/pty v1.1.7/go.mod h1:lj5s0c3V2DBrqTV7llrYr5NG6My20zk30Fl46Y7DoTY=
-github.com/cyphar/filepath-securejoin v0.2.2/go.mod h1:FpkQEhXnPnOthhzymB7CGsFk2G9VLXONKD9G7QGMM+4=
-github.com/cznic/b v0.0.0-20180115125044-35e9bbe41f07/go.mod h1:URriBxXwVq5ijiJ12C7iIZqlA69nTlI+LgI6/pwftG8=
-github.com/cznic/fileutil v0.0.0-20180108211300-6a051e75936f/go.mod h1:8S58EK26zhXSxzv7NQFpnliaOQsmDUxvoQO3rt154Vg=
-github.com/cznic/golex v0.0.0-20170803123110-4ab7c5e190e4/go.mod h1:+bmmJDNmKlhWNG+gwWCkaBoTy39Fs+bzRxVBzoTQbIc=
-github.com/cznic/internal v0.0.0-20180608152220-f44710a21d00/go.mod h1:olo7eAdKwJdXxb55TKGLiJ6xt1H0/tiiRCWKVLmtjY4=
-github.com/cznic/lldb v1.1.0/go.mod h1:FIZVUmYUVhPwRiPzL8nD/mpFcJ/G7SSXjjXYG4uRI3A=
-github.com/cznic/mathutil v0.0.0-20180504122225-ca4c9f2c1369/go.mod h1:e6NPNENfs9mPDVNRekM7lKScauxd5kXTr1Mfyig6TDM=
-github.com/cznic/ql v1.2.0/go.mod h1:FbpzhyZrqr0PVlK6ury+PoW3T0ODUV22OeWIxcaOrSE=
-github.com/cznic/sortutil v0.0.0-20150617083342-4c7342852e65/go.mod h1:q2w6Bg5jeox1B+QkJ6Wp/+Vn0G/bo3f1uY7Fn3vivIQ=
-github.com/cznic/strutil v0.0.0-20171016134553-529a34b1c186/go.mod h1:AHHPPPXTw0h6pVabbcbyGRK1DckRn7r/STdZEeIDzZc=
-github.com/cznic/zappy v0.0.0-20160723133515-2533cb5b45cc/go.mod h1:Y1SNZ4dRUOKXshKUbwUapqNncRrho4mkjQebgEHZLj8=
-github.com/davecgh/go-spew v0.0.0-20151105211317-5215b55f46b2/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
+github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
+github.com/creack/pty v1.1.11/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
 github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
 github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
 github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
-github.com/daviddengcn/go-colortext v0.0.0-20160507010035-511bcaf42ccd/go.mod h1:dv4zxwHi5C/8AeI+4gX4dCWOIvNi7I6JCSX0HvlKPgE=
-github.com/deislabs/oras v0.8.1/go.mod h1:Mx0rMSbBNaNfY9hjpccEnxkOqJL6KGjtxNHPLC4G4As=
-github.com/denisenkom/go-mssqldb v0.0.0-20190515213511-eb9f6a1743f3/go.mod h1:zAg7JM8CkOJ43xKXIj7eRO9kmWm/TW578qo+oDO6tuM=
-github.com/denisenkom/go-mssqldb v0.0.0-20191001013358-cfbb681360f0/go.mod h1:xbL0rPBG9cCiLr28tMa8zpbdarY27NDyej4t/EjAShU=
-github.com/denverdino/aliyungo v0.0.0-20190125010748-a747050bb1ba/go.mod h1:dV8lFg6daOBZbT6/BDGIz6Y3WFGn8juu6G+CQ6LHtl0=
-github.com/dgrijalva/jwt-go v0.0.0-20170104182250-a601269ab70c/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ=
 github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ=
-github.com/dgryski/go-sip13 v0.0.0-20181026042036-e10d5fee7954/go.mod h1:vAd38F8PWV+bWy6jNmig1y/TA+kYO4g3RSRF0IAv0no=
-github.com/dgryski/go-sip13 v0.0.0-20190329191031-25c5027a8c7b/go.mod h1:vAd38F8PWV+bWy6jNmig1y/TA+kYO4g3RSRF0IAv0no=
-github.com/dhui/dktest v0.3.0/go.mod h1:cyzIUfGsBEbZ6BT7tnXqAShHSXCZhSNmFl70sZ7c1yc=
-github.com/dnaeon/go-vcr v1.0.1/go.mod h1:aBB1+wY4s93YsC3HHjMBMrwTj2R9FHDzUr9KyGc8n1E=
-github.com/docker/cli v0.0.0-20200130152716-5d0cf8839492/go.mod h1:JLrzqnKDaYBop7H2jaqPtU4hHvMKP+vjCwu2uszcLI8=
-github.com/docker/distribution v0.0.0-20191216044856-a8371794149d/go.mod h1:0+TTO4EOBfRPhZXAeF1Vu+W3hHZ8eLp8PgKVZlcvtFY=
-github.com/docker/distribution v2.7.0+incompatible/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w=
-github.com/docker/distribution v2.7.1+incompatible/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w=
-github.com/docker/docker v0.7.3-0.20190103212154-2b7e084dc98b/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk=
-github.com/docker/docker v0.7.3-0.20190327010347-be7ac8be2ae0/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk=
-github.com/docker/docker v0.7.3-0.20190817195342-4760db040282/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk=
-github.com/docker/docker v1.4.2-0.20200203170920-46ec8731fbce/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk=
-github.com/docker/docker-credential-helpers v0.6.3/go.mod h1:WRaJzqw3CTB9bk10avuGsjVBZsD05qeibJ1/TYlvc0Y=
-github.com/docker/go-connections v0.4.0/go.mod h1:Gbd7IOopHjR8Iph03tsViu4nIes5XhDvyHbTtUxmeec=
-github.com/docker/go-events v0.0.0-20190806004212-e31b211e4f1c/go.mod h1:Uw6UezgYA44ePAFQYUehOuCzmy5zmg/+nl2ZfMWGkpA=
-github.com/docker/go-metrics v0.0.0-20180209012529-399ea8c73916/go.mod h1:/u0gXw0Gay3ceNrsHubL3BtdOL2fHf93USgMTe0W5dI=
-github.com/docker/go-units v0.3.3/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk=
-github.com/docker/go-units v0.4.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk=
-github.com/docker/libtrust v0.0.0-20150114040149-fa567046d9b1/go.mod h1:cyGadeNEkKy96OOhEzfZl+yxihPEzKnqJwvfuSUqbZE=
-github.com/docker/spdystream v0.0.0-20160310174837-449fdfce4d96/go.mod h1:Qh8CwZgvJUkLughtfhJv5dyTYa91l1fOUCrgjqmcifM=
 github.com/docopt/docopt-go v0.0.0-20180111231733-ee0de3bc6815/go.mod h1:WwZ+bS3ebgob9U8Nd0kOddGdZWjyMGR8Wziv+TBNwSE=
-github.com/dustin/go-humanize v0.0.0-20171111073723-bb3d318650d4/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk=
 github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk=
-github.com/eapache/go-resiliency v1.1.0/go.mod h1:kFI+JgMyC7bLPUVY133qvEBtVayf5mFgVsvEsIPBvNs=
-github.com/eapache/go-xerial-snappy v0.0.0-20180814174437-776d5712da21/go.mod h1:+020luEh2TKB4/GOp8oxxtq0Daoen/Cii55CzbTV6DU=
-github.com/eapache/queue v1.1.0/go.mod h1:6eCeP0CKFpHLu8blIFXhExK/dRa7WDZfr6jVFPTqq+I=
-github.com/edsrzf/mmap-go v0.0.0-20170320065105-0bce6a688712/go.mod h1:YO35OhQPt3KJa3ryjFM5Bs14WD66h8eGKpfaBNrHW5M=
-github.com/edsrzf/mmap-go v1.0.0/go.mod h1:YO35OhQPt3KJa3ryjFM5Bs14WD66h8eGKpfaBNrHW5M=
-github.com/elastic/go-sysinfo v1.0.1/go.mod h1:O/D5m1VpYLwGjCYzEt63g3Z1uO3jXfwyzzjiW90t8cY=
-github.com/elastic/go-sysinfo v1.1.1/go.mod h1:i1ZYdU10oLNfRzq4vq62BEwD2fH8KaWh6eh0ikPT9F0=
-github.com/elastic/go-windows v1.0.0/go.mod h1:TsU0Nrp7/y3+VwE82FoZF8gC/XFg/Elz6CcloAxnPgU=
-github.com/elastic/go-windows v1.0.1/go.mod h1:FoVvqWSun28vaDQPbj2Elfc0JahhPB7WQEGa3c814Ss=
 github.com/elazarl/goproxy v0.0.0-20180725130230-947c36da3153/go.mod h1:/Zj4wYkgs4iZTTu3o/KG3Itv/qCCa8VVMlb3i9OVuzc=
 github.com/emicklei/go-restful v0.0.0-20170410110728-ff4f55a20633/go.mod h1:otzb+WCGbkyDHkqmQmT5YD2WR4BBwUdeQoFo8l/7tVs=
-github.com/emicklei/go-restful v2.9.5+incompatible h1:spTtZBk5DYEvbxMVutUuTyh1Ao2r4iyvLdACqsl/Ljk=
 github.com/emicklei/go-restful v2.9.5+incompatible/go.mod h1:otzb+WCGbkyDHkqmQmT5YD2WR4BBwUdeQoFo8l/7tVs=
+github.com/emirpasic/gods v1.12.0/go.mod h1:YfzfFFoVP/catgzJb4IKIqXjX78Ha8FMSDh3ymbK86o=
 github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
 github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
+github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98=
+github.com/envoyproxy/go-control-plane v0.9.7/go.mod h1:cwu0lG7PUMfa9snN8LXBig5ynNVH9qI8YYLbd1fK2po=
+github.com/envoyproxy/go-control-plane v0.9.9-0.20201210154907-fd9021fe5dad/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk=
+github.com/envoyproxy/go-control-plane v0.9.9-0.20210217033140-668b12f5399d/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk=
+github.com/envoyproxy/go-control-plane v0.9.9-0.20210512163311-63b5d3c536b0/go.mod h1:hliV/p42l8fGbc6Y9bQ70uLwIvmJyVE5k4iMKlh8wCQ=
 github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c=
-github.com/evanphx/json-patch v4.1.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk=
-github.com/evanphx/json-patch v4.2.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk=
-github.com/evanphx/json-patch v4.5.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk=
-github.com/evanphx/json-patch v4.9.0+incompatible h1:kLcOMZeuLAJvL2BPWLMIj5oaZQobrkAqrL+WFZwQses=
-github.com/evanphx/json-patch v4.9.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk=
-github.com/exponent-io/jsonpath v0.0.0-20151013193312-d6023ce2651d/go.mod h1:ZZMPRZwes7CROmyNKgQzC3XPs6L/G2EJLHddWejkmf4=
-github.com/facette/natsort v0.0.0-20181210072756-2cd4dd1e2dcb/go.mod h1:bH6Xx7IW64qjjJq8M2u4dxNaBiDfKK+z/3eGDpXEQhc=
-github.com/fatih/camelcase v1.0.0/go.mod h1:yN2Sb0lFhZJUdVvtELVWefmrXpuZESvPmqwoZc+/fpc=
+github.com/evanphx/json-patch v0.5.2/go.mod h1:ZWS5hhDbVDyob71nXKNL0+PWn6ToqBHMikGIFbs31qQ=
+github.com/evanphx/json-patch v4.12.0+incompatible h1:4onqiflcdA9EOZ4RxV643DvftH5pOlLGNtQ5lPWQu84=
+github.com/evanphx/json-patch v4.12.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk=
 github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4=
-github.com/fatih/structtag v1.1.0/go.mod h1:mBJUNpUnHmRKrKlQQlmCrh5PuhftFbNv8Ys4/aAZl94=
-github.com/fortytw2/leaktest v1.3.0/go.mod h1:jDsjWgpAGjm2CA7WthBh/CdZYEPF31XHquHwclZch5g=
+github.com/felixge/httpsnoop v1.0.1/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U=
+github.com/fluxcd/go-git-providers v0.5.4 h1:MnByjsmXa8rMt2hTmhmtbocq7YIsTlwZKrj9lAsob4Q=
+github.com/fluxcd/go-git-providers v0.5.4/go.mod h1:4jTHTmSx3rFGnG78KUVgFYeG6vWFnKwUSr2mi31tvp8=
+github.com/flynn/go-shlex v0.0.0-20150515145356-3f9db97f8568/go.mod h1:xEzjJPgXI435gkrCt3MPfRiAkVrwSbHsst4LCFVfpJc=
+github.com/form3tech-oss/jwt-go v3.2.2+incompatible/go.mod h1:pbq4aXjuKjdthFRnoDwaVPLA+WlJuPGy+QneDUgJi2k=
+github.com/form3tech-oss/jwt-go v3.2.3+incompatible h1:7ZaBxOI7TMoYBfyA3cQHErNNyAWIKUMIwqxEtgHOs5c=
+github.com/form3tech-oss/jwt-go v3.2.3+incompatible/go.mod h1:pbq4aXjuKjdthFRnoDwaVPLA+WlJuPGy+QneDUgJi2k=
 github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
-github.com/fsnotify/fsnotify v1.4.9 h1:hsms1Qyu0jgnwNXIxa+/V/PDsU6CfLf6CNO8H7IWoS4=
 github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ=
-github.com/fsouza/fake-gcs-server v1.7.0/go.mod h1:5XIRs4YvwNbNoz+1JF8j6KLAyDh7RHGAyAK3EP2EsNk=
-github.com/garyburd/redigo v0.0.0-20150301180006-535138d7bcd7/go.mod h1:NR3MbYisc3/PwhQ00EMzDiPmrwpPxAn5GI05/YaO1SY=
-github.com/ghodss/yaml v0.0.0-20150909031657-73d445a93680/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04=
+github.com/fsnotify/fsnotify v1.5.1 h1:mZcQUHVQUQWoPXXtuf9yuEXKudkV2sx1E06UadKWpgI=
+github.com/fsnotify/fsnotify v1.5.1/go.mod h1:T3375wBYaZdLLcVNkcVbzGHY7f1l/uK5T5Ai1i3InKU=
+github.com/getkin/kin-openapi v0.76.0/go.mod h1:660oXbgy5JFMKreazJaQTw7o+X00qeSyhcnluiMv+Xg=
+github.com/getsentry/raven-go v0.2.0/go.mod h1:KungGk8q33+aIAZUIVWZDr2OfAEBsO49PX4NzFV5kcQ=
 github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04=
-github.com/globalsign/mgo v0.0.0-20180905125535-1ca0a4f7cbcb/go.mod h1:xkRDCp4j0OGD1HRkm4kmhM+pmpv3AKq5SU7GMg4oO/Q=
-github.com/globalsign/mgo v0.0.0-20181015135952-eeefdecb41b8/go.mod h1:xkRDCp4j0OGD1HRkm4kmhM+pmpv3AKq5SU7GMg4oO/Q=
-github.com/go-bindata/go-bindata/v3 v3.1.3/go.mod h1:1/zrpXsLD8YDIbhZRqXzm1Ghc7NhEvIN9+Z6R5/xH4I=
+github.com/gliderlabs/ssh v0.2.2/go.mod h1:U7qILu1NlMHj9FlMhZLlkCdDnU1DBEAqr0aevW3Awn0=
+github.com/go-git/gcfg v1.5.0/go.mod h1:5m20vg6GwYabIxaOonVkTdrILxQMpEShl1xiMF4ua+E=
+github.com/go-git/go-billy/v5 v5.2.0/go.mod h1:pmpqyWchKfYfrkb/UVH4otLvyi/5gJlGI4Hb3ZqZ3W0=
+github.com/go-git/go-billy/v5 v5.3.1/go.mod h1:pmpqyWchKfYfrkb/UVH4otLvyi/5gJlGI4Hb3ZqZ3W0=
+github.com/go-git/go-git-fixtures/v4 v4.2.1/go.mod h1:K8zd3kDUAykwTdDCr+I0per6Y6vMiRR/nnVTBtavnB0=
+github.com/go-git/go-git/v5 v5.4.2/go.mod h1:gQ1kArt6d+n+BGd+/B/I74HwRTLhth2+zti4ihgckDc=
 github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU=
 github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8=
-github.com/go-ini/ini v1.25.4/go.mod h1:ByCAeIL28uOIIG0E3PJtZPDL8WnHpFKFOtgjp+3Ies8=
-github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as=
+github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8=
 github.com/go-kit/kit v0.9.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as=
-github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE=
+github.com/go-kit/log v0.1.0/go.mod h1:zbhenjAZHb184qTLMA9ZjW7ThYL0H2mk7Q6pNt4vbaY=
 github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk=
+github.com/go-logfmt/logfmt v0.5.0/go.mod h1:wCYkCAKZfumFQihp8CzCvQ3paCTfi41vtzG1KdI/P7A=
 github.com/go-logr/logr v0.1.0/go.mod h1:ixOQHD9gLJUVQQ2ZOR7zLEifBX6tGkNJF4QyIY7sIas=
 github.com/go-logr/logr v0.2.0/go.mod h1:z6/tIYblkpsD+a4lm/fGIIU9mZ+XfAiaFtq7xTgseGU=
-github.com/go-logr/logr v0.2.1 h1:fV3MLmabKIZ383XifUjFSwcoGee0v9qgPp8wy5svibE=
-github.com/go-logr/logr v0.2.1/go.mod h1:z6/tIYblkpsD+a4lm/fGIIU9mZ+XfAiaFtq7xTgseGU=
-github.com/go-logr/zapr v0.1.0/go.mod h1:tabnROwaDl0UNxkVeFRbY8bwB37GwRv0P8lg6aAiEnk=
-github.com/go-logr/zapr v0.1.1/go.mod h1:tabnROwaDl0UNxkVeFRbY8bwB37GwRv0P8lg6aAiEnk=
-github.com/go-logr/zapr v0.2.0 h1:v6Ji8yBW77pva6NkJKQdHLAJKrIJKRHz0RXwPqCHSR4=
-github.com/go-logr/zapr v0.2.0/go.mod h1:qhKdvif7YF5GI9NWEpyxTSSBdGmzkNguibrdCNVPunU=
-github.com/go-openapi/analysis v0.0.0-20180825180245-b006789cd277/go.mod h1:k70tL6pCuVxPJOHXQ+wIac1FUrvNkHolPie/cLEU6hI=
-github.com/go-openapi/analysis v0.17.0/go.mod h1:IowGgpVeD0vNm45So8nr+IcQ3pxVtpRoBWb8PVZO0ik=
-github.com/go-openapi/analysis v0.17.2/go.mod h1:IowGgpVeD0vNm45So8nr+IcQ3pxVtpRoBWb8PVZO0ik=
-github.com/go-openapi/analysis v0.18.0/go.mod h1:IowGgpVeD0vNm45So8nr+IcQ3pxVtpRoBWb8PVZO0ik=
-github.com/go-openapi/analysis v0.19.2/go.mod h1:3P1osvZa9jKjb8ed2TPng3f0i/UY9snX6gxi44djMjk=
-github.com/go-openapi/analysis v0.19.5/go.mod h1:hkEAkxagaIvIP7VTn8ygJNkd4kAYON2rCu0v0ObL0AU=
-github.com/go-openapi/errors v0.17.0/go.mod h1:LcZQpmvG4wyF5j4IhA73wkLFQg+QJXOQHVjmcZxhka0=
-github.com/go-openapi/errors v0.17.2/go.mod h1:LcZQpmvG4wyF5j4IhA73wkLFQg+QJXOQHVjmcZxhka0=
-github.com/go-openapi/errors v0.18.0/go.mod h1:LcZQpmvG4wyF5j4IhA73wkLFQg+QJXOQHVjmcZxhka0=
-github.com/go-openapi/errors v0.19.2/go.mod h1:qX0BLWsyaKfvhluLejVpVNwNRdXZhEbTA4kxxpKBC94=
-github.com/go-openapi/jsonpointer v0.0.0-20160704185906-46af16f9f7b1/go.mod h1:+35s3my2LFTysnkMfxsJBAMHj/DoqoB9knIWoYG/Vk0=
-github.com/go-openapi/jsonpointer v0.17.0/go.mod h1:cOnomiV+CVVwFLk0A/MExoFMjwdsUdVpsRhURCKh+3M=
-github.com/go-openapi/jsonpointer v0.17.2/go.mod h1:cOnomiV+CVVwFLk0A/MExoFMjwdsUdVpsRhURCKh+3M=
-github.com/go-openapi/jsonpointer v0.18.0/go.mod h1:cOnomiV+CVVwFLk0A/MExoFMjwdsUdVpsRhURCKh+3M=
-github.com/go-openapi/jsonpointer v0.19.2/go.mod h1:3akKfEdA7DF1sugOqz1dVQHBcuDBPKZGEoHC/NkiQRg=
-github.com/go-openapi/jsonpointer v0.19.3 h1:gihV7YNZK1iK6Tgwwsxo2rJbD1GTbdm72325Bq8FI3w=
+github.com/go-logr/logr v1.2.0/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A=
+github.com/go-logr/logr v1.2.2 h1:ahHml/yUpnlb96Rp8HCvtYVPY8ZYpxq3g7UYchIYwbs=
+github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A=
+github.com/go-logr/zapr v1.2.0/go.mod h1:Qa4Bsj2Vb+FAVeAKsLD8RLQ+YRJB8YDmOAKxaBQf7Ro=
+github.com/go-logr/zapr v1.2.2 h1:5YNlIL6oZLydaV4dOFjL8YpgXF/tPeTbnpatnu3cq6o=
+github.com/go-logr/zapr v1.2.2/go.mod h1:eIauM6P8qSvTw5o2ez6UEAfGjQKrxQTl5EoK+Qa2oG4=
 github.com/go-openapi/jsonpointer v0.19.3/go.mod h1:Pl9vOtqEWErmShwVjC8pYs9cog34VGT37dQOVbmoatg=
-github.com/go-openapi/jsonreference v0.0.0-20160704190145-13c6e3589ad9/go.mod h1:W3Z9FmVs9qj+KR4zFKmDPGiLdk1D9Rlm7cyMvf57TTg=
-github.com/go-openapi/jsonreference v0.17.0/go.mod h1:g4xxGn04lDIRh0GJb5QlpE3HfopLOL6uZrK/VgnsK9I=
-github.com/go-openapi/jsonreference v0.17.2/go.mod h1:g4xxGn04lDIRh0GJb5QlpE3HfopLOL6uZrK/VgnsK9I=
-github.com/go-openapi/jsonreference v0.18.0/go.mod h1:g4xxGn04lDIRh0GJb5QlpE3HfopLOL6uZrK/VgnsK9I=
-github.com/go-openapi/jsonreference v0.19.2/go.mod h1:jMjeRr2HHw6nAVajTXJ4eiUwohSTlpa0o73RUL1owJc=
-github.com/go-openapi/jsonreference v0.19.3 h1:5cxNfTy0UVC3X8JL5ymxzyoUZmo8iZb+jeTWn7tUa8o=
+github.com/go-openapi/jsonpointer v0.19.5/go.mod h1:Pl9vOtqEWErmShwVjC8pYs9cog34VGT37dQOVbmoatg=
 github.com/go-openapi/jsonreference v0.19.3/go.mod h1:rjx6GuL8TTa9VaixXglHmQmIL98+wF9xc8zWvFonSJ8=
-github.com/go-openapi/loads v0.17.0/go.mod h1:72tmFy5wsWx89uEVddd0RjRWPZm92WRLhf7AC+0+OOU=
-github.com/go-openapi/loads v0.17.2/go.mod h1:72tmFy5wsWx89uEVddd0RjRWPZm92WRLhf7AC+0+OOU=
-github.com/go-openapi/loads v0.18.0/go.mod h1:72tmFy5wsWx89uEVddd0RjRWPZm92WRLhf7AC+0+OOU=
-github.com/go-openapi/loads v0.19.0/go.mod h1:72tmFy5wsWx89uEVddd0RjRWPZm92WRLhf7AC+0+OOU=
-github.com/go-openapi/loads v0.19.2/go.mod h1:QAskZPMX5V0C2gvfkGZzJlINuP7Hx/4+ix5jWFxsNPs=
-github.com/go-openapi/loads v0.19.4/go.mod h1:zZVHonKd8DXyxyw4yfnVjPzBjIQcLt0CCsn0N0ZrQsk=
-github.com/go-openapi/runtime v0.0.0-20180920151709-4f900dc2ade9/go.mod h1:6v9a6LTXWQCdL8k1AO3cvqx5OtZY/Y9wKTgaoP6YRfA=
-github.com/go-openapi/runtime v0.18.0/go.mod h1:uI6pHuxWYTy94zZxgcwJkUWa9wbIlhteGfloI10GD4U=
-github.com/go-openapi/runtime v0.19.0/go.mod h1:OwNfisksmmaZse4+gpV3Ne9AyMOlP1lt4sK4FXt0O64=
-github.com/go-openapi/runtime v0.19.4/go.mod h1:X277bwSUBxVlCYR3r7xgZZGKVvBd/29gLDlFGtJ8NL4=
-github.com/go-openapi/spec v0.0.0-20160808142527-6aced65f8501/go.mod h1:J8+jY1nAiCcj+friV/PDoE1/3eeccG9LYBs0tYvLOWc=
-github.com/go-openapi/spec v0.17.0/go.mod h1:XkF/MOi14NmjsfZ8VtAKf8pIlbZzyoTvZsdfssdxcBI=
-github.com/go-openapi/spec v0.17.2/go.mod h1:XkF/MOi14NmjsfZ8VtAKf8pIlbZzyoTvZsdfssdxcBI=
-github.com/go-openapi/spec v0.18.0/go.mod h1:XkF/MOi14NmjsfZ8VtAKf8pIlbZzyoTvZsdfssdxcBI=
-github.com/go-openapi/spec v0.19.2/go.mod h1:sCxk3jxKgioEJikev4fgkNmwS+3kuYdJtcsZsD5zxMY=
-github.com/go-openapi/spec v0.19.3/go.mod h1:FpwSN1ksY1eteniUU7X0N/BgJ7a4WvBFVA8Lj9mJglo=
-github.com/go-openapi/spec v0.19.4 h1:ixzUSnHTd6hCemgtAJgluaTSGYpLNpJY4mA2DIkdOAo=
-github.com/go-openapi/spec v0.19.4/go.mod h1:FpwSN1ksY1eteniUU7X0N/BgJ7a4WvBFVA8Lj9mJglo=
-github.com/go-openapi/strfmt v0.17.0/go.mod h1:P82hnJI0CXkErkXi8IKjPbNBM6lV6+5pLP5l494TcyU=
-github.com/go-openapi/strfmt v0.17.2/go.mod h1:P82hnJI0CXkErkXi8IKjPbNBM6lV6+5pLP5l494TcyU=
-github.com/go-openapi/strfmt v0.18.0/go.mod h1:P82hnJI0CXkErkXi8IKjPbNBM6lV6+5pLP5l494TcyU=
-github.com/go-openapi/strfmt v0.19.0/go.mod h1:+uW+93UVvGGq2qGaZxdDeJqSAqBqBdl+ZPMF/cC8nDY=
-github.com/go-openapi/strfmt v0.19.2/go.mod h1:0yX7dbo8mKIvc3XSKp7MNfxw4JytCfCD6+bY1AVL9LU=
-github.com/go-openapi/strfmt v0.19.3/go.mod h1:0yX7dbo8mKIvc3XSKp7MNfxw4JytCfCD6+bY1AVL9LU=
-github.com/go-openapi/swag v0.0.0-20160704191624-1d0bd113de87/go.mod h1:DXUve3Dpr1UfpPtxFw+EFuQ41HhCWZfha5jSVRG7C7I=
-github.com/go-openapi/swag v0.17.0/go.mod h1:AByQ+nYG6gQg71GINrmuDXCPWdL640yX49/kXLo40Tg=
-github.com/go-openapi/swag v0.17.2/go.mod h1:AByQ+nYG6gQg71GINrmuDXCPWdL640yX49/kXLo40Tg=
-github.com/go-openapi/swag v0.18.0/go.mod h1:AByQ+nYG6gQg71GINrmuDXCPWdL640yX49/kXLo40Tg=
-github.com/go-openapi/swag v0.19.2/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh66Z9tfKk=
-github.com/go-openapi/swag v0.19.5 h1:lTz6Ys4CmqqCQmZPBlbQENR1/GucA2bzYTE12Pw4tFY=
+github.com/go-openapi/jsonreference v0.19.5/go.mod h1:RdybgQwPxbL4UEjuAruzK1x3nE69AqPYEJeo/TWfEeg=
 github.com/go-openapi/swag v0.19.5/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh66Z9tfKk=
-github.com/go-openapi/validate v0.17.2/go.mod h1:Uh4HdOzKt19xGIGm1qHf/ofbX1YQ4Y+MYsct2VUrAJ4=
-github.com/go-openapi/validate v0.18.0/go.mod h1:Uh4HdOzKt19xGIGm1qHf/ofbX1YQ4Y+MYsct2VUrAJ4=
-github.com/go-openapi/validate v0.19.2/go.mod h1:1tRCw7m3jtI8eNWEEliiAqUIcBztB2KDnRCRMUi7GTA=
-github.com/go-openapi/validate v0.19.5/go.mod h1:8DJv2CVJQ6kGNpFW6eV9N3JviE1C85nY1c2z52x1Gk4=
-github.com/go-sql-driver/mysql v1.4.0/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w=
-github.com/go-sql-driver/mysql v1.4.1/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w=
+github.com/go-openapi/swag v0.19.14/go.mod h1:QYRuS/SOXUCsnplDa677K7+DxSOj6IPNl/eQntq43wQ=
 github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY=
-github.com/gobuffalo/envy v1.6.5/go.mod h1:N+GkhhZ/93bGZc6ZKhJLP6+m+tCNPKwgSpH9kaifseQ=
-github.com/gobuffalo/envy v1.7.0/go.mod h1:n7DRkBerg/aorDM8kbduw5dN3oXGswK5liaSCx4T5NI=
-github.com/gobuffalo/envy v1.7.1/go.mod h1:FurDp9+EDPE4aIUS3ZLyD+7/9fpx7YRt/ukY6jIHf0w=
-github.com/gobuffalo/flect v0.1.5/go.mod h1:W3K3X9ksuZfir8f/LrfVtWmCDQFfayuylOJ7sz/Fj80=
-github.com/gobuffalo/flect v0.2.0/go.mod h1:W3K3X9ksuZfir8f/LrfVtWmCDQFfayuylOJ7sz/Fj80=
-github.com/gobuffalo/flect v0.2.1 h1:GPoRjEN0QObosV4XwuoWvSd5uSiL0N3e91/xqyY4crQ=
-github.com/gobuffalo/flect v0.2.1/go.mod h1:vmkQwuZYhN5Pc4ljYQZzP+1sq+NEkK+lh20jmEmX3jc=
-github.com/gobuffalo/logger v1.0.1/go.mod h1:2zbswyIUa45I+c+FLXuWl9zSWEiVuthsk8ze5s8JvPs=
-github.com/gobuffalo/packd v0.3.0/go.mod h1:zC7QkmNkYVGKPw4tHpBQ+ml7W/3tIebgeo1b36chA3Q=
-github.com/gobuffalo/packr/v2 v2.7.1/go.mod h1:qYEvAazPaVxy7Y7KR0W8qYEE+RymX74kETFqjFoFlOc=
-github.com/gobwas/glob v0.2.3/go.mod h1:d3Ez4x06l9bZtSvzIay5+Yzi0fmZzPgnTbPcKjJAkT8=
-github.com/gocql/gocql v0.0.0-20190301043612-f6df8288f9b4/go.mod h1:4Fw1eo5iaEhDUs8XyuhSVCVy52Jq3L+/3GJgYkwc+/0=
-github.com/godbus/dbus v0.0.0-20190422162347-ade71ed3457e/go.mod h1:bBOAhwG1umN6/6ZUMtDFBMQR8jRg9O75tm9K00oMsK4=
-github.com/gofrs/flock v0.7.1/go.mod h1:F1TvTiK9OcQqauNUHlbJvyl9Qa1QvF/gOUDKA14jxHU=
-github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=
-github.com/gogo/protobuf v1.2.0/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=
+github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0/go.mod h1:fyg7847qk6SyHyPtNmDHnmrv/HOrqktSC+C9fM+CJOE=
+github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA=
 github.com/gogo/protobuf v1.2.1/go.mod h1:hp+jE20tsWTFYpLwKvXlhS1hjn+gTNwPg2I6zVXpSg4=
-github.com/gogo/protobuf v1.2.2-0.20190723190241-65acae22fc9d/go.mod h1:SlYgWuQ5SjCEi6WLHjHCa1yvBfUnHcTbrrZtXPKa29o=
-github.com/gogo/protobuf v1.2.2-0.20190730201129-28a6bbf47e48/go.mod h1:SlYgWuQ5SjCEi6WLHjHCa1yvBfUnHcTbrrZtXPKa29o=
-github.com/gogo/protobuf v1.3.1 h1:DqDEcV5aeaTmdFBePNpYsp3FlcVH/2ISVVM9Qf8PSls=
 github.com/gogo/protobuf v1.3.1/go.mod h1:SlYgWuQ5SjCEi6WLHjHCa1yvBfUnHcTbrrZtXPKa29o=
-github.com/golang-migrate/migrate/v4 v4.6.2/go.mod h1:JYi6reN3+Z734VZ0akNuyOJNcrg45ZL7LDBMW3WGJL0=
-github.com/golang-sql/civil v0.0.0-20190719163853-cb61b32ac6fe/go.mod h1:8vg3r2VgvsThLBIFL93Qb5yWzgyZWhEmBwUJWevAkK0=
+github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q=
+github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q=
 github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
-github.com/golang/groupcache v0.0.0-20160516000752-02826c3e7903/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
+github.com/golang/glog v1.0.0/go.mod h1:EWib/APOK0SL3dFbYqvxE3UYd8E6s1ouQ7iEp/0LWV4=
 github.com/golang/groupcache v0.0.0-20190129154638-5b532d6fd5ef/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
 github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
-github.com/golang/groupcache v0.0.0-20191027212112-611e8accdfc9/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
-github.com/golang/groupcache v0.0.0-20191227052852-215e87163ea7 h1:5ZkaAPbicIKTF2I64qf5Fh8Aa83Q/dnOafMYV0OMwjA=
 github.com/golang/groupcache v0.0.0-20191227052852-215e87163ea7/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
+github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
+github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da h1:oI5xCqsCo564l8iNU+DwB5epxmsaqB+rhGL0m5jtYqE=
+github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
 github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
 github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
 github.com/golang/mock v1.3.1/go.mod h1:sBzyDLLjw3U8JLTeZvSv8jJB+tU5PVekmnlKIyFUx0Y=
-github.com/golang/protobuf v0.0.0-20161109072736-4bd1920723d7/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
+github.com/golang/mock v1.4.0/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw=
+github.com/golang/mock v1.4.1/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw=
+github.com/golang/mock v1.4.3/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw=
+github.com/golang/mock v1.4.4/go.mod h1:l3mdAwkq5BuhzHwde/uurv3sEJeZMXNpwsxVWU71h+4=
+github.com/golang/mock v1.5.0/go.mod h1:CWnOUgYIOo4TcNZ0wHX3YZCqsaM1I1Jvs6v3mP3KVu8=
+github.com/golang/protobuf v1.0.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
 github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
 github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
 github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
 github.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw=
+github.com/golang/protobuf v1.3.4/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw=
+github.com/golang/protobuf v1.3.5/go.mod h1:6O5/vntMXwX2lRkT1hjjk0nAC1IDOTvTlVgjlRvqsdk=
 github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8=
 github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA=
 github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs=
 github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w=
 github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0=
 github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QDs8UjoX8=
-github.com/golang/protobuf v1.4.2 h1:+Z5KGCizgyZCbGh1KZqA0fcLLkwbsjIzS4aV2v7wJX0=
 github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=
-github.com/golang/snappy v0.0.0-20170215233205-553a64147049/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
-github.com/golang/snappy v0.0.0-20180518054509-2e65f85255db/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
-github.com/golang/snappy v0.0.1/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
-github.com/golangplus/bytes v0.0.0-20160111154220-45c989fe5450/go.mod h1:Bk6SMAONeMXrxql8uvOKuAZSu8aM5RUGv+1C6IJaEho=
-github.com/golangplus/fmt v0.0.0-20150411045040-2a5d6d7d2995/go.mod h1:lJgMEyOkYFkPcDKwRXegd+iM6E7matEszMG5HhwytU8=
-github.com/golangplus/testing v0.0.0-20180327235837-af21d9c3145e/go.mod h1:0AA//k/eakGydO4jKRoRL2j92ZKSzTgj9tclaCrvXHk=
+github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=
+github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk=
+github.com/golang/protobuf v1.5.1/go.mod h1:DopwsBzvsk0Fs44TXzsVbJyPhcCPeIwnvohx4u74HPM=
+github.com/golang/protobuf v1.5.2 h1:ROPKBNFfQgOUMifHyP+KYbvpjbdoFNs+aK7DXlji0Tw=
+github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY=
 github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
 github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
+github.com/google/btree v1.0.1/go.mod h1:xXMiIv4Fb/0kKde4SpL7qlzvu5cMJDRkFDxJfI9uaxA=
+github.com/google/cel-go v0.9.0/go.mod h1:U7ayypeSkw23szu4GaQTPJGx66c20mx8JklMSxrmI1w=
+github.com/google/cel-spec v0.6.0/go.mod h1:Nwjgxy5CbjlPrtCWjeDjUyKMl8w41YBYGjsyDdqk0xA=
 github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M=
 github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
 github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
-github.com/google/go-cmp v0.4.0 h1:xsAVV57WRhGj6kEIi8ReJzQlHHqcBYCElAvkovg3B/4=
 github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
-github.com/google/go-github v17.0.0+incompatible/go.mod h1:zLgOLi98H3fifZn+44m+umXrS52loVEgC2AApnigrVQ=
-github.com/google/go-querystring v1.0.0/go.mod h1:odCYkC5MyYFN7vkCjXpyrEuKhc/BUO6wN/zVPAxq5ck=
-github.com/google/gofuzz v0.0.0-20161122191042-44d81051d367/go.mod h1:HP5RmnzzSNb993RKQDq4+1A4ia9nllfqcQFTQJedwGI=
+github.com/google/go-cmp v0.4.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
+github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
+github.com/google/go-cmp v0.5.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
+github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
+github.com/google/go-cmp v0.5.3/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
+github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
+github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
+github.com/google/go-cmp v0.5.6 h1:BKbKCqvP6I+rmFHt06ZmyQtvB8xAkWdhFyr0ZUNZcxQ=
+github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
+github.com/google/go-github/v41 v41.0.0 h1:HseJrM2JFf2vfiZJ8anY2hqBjdfY1Vlj/K27ueww4gg=
+github.com/google/go-github/v41 v41.0.0/go.mod h1:XgmCA5H323A9rtgExdTcnDkcqp6S30AVACCBDOonIxg=
+github.com/google/go-querystring v1.1.0 h1:AnCroh3fv4ZBgVIf1Iwtovgjaw/GiKJo8M8yD/fhyJ8=
+github.com/google/go-querystring v1.1.0/go.mod h1:Kcdr2DB4koayq7X8pmAG4sNG59So17icRSOU623lUBU=
 github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
 github.com/google/gofuzz v1.1.0 h1:Hsa8mG0dQ46ij8Sl2AYJDUv1oA9/d6Vk+3LG99Oe02g=
 github.com/google/gofuzz v1.1.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
 github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs=
+github.com/google/martian/v3 v3.0.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0=
+github.com/google/martian/v3 v3.1.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0=
 github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc=
 github.com/google/pprof v0.0.0-20190515194954-54271f7e092f/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc=
-github.com/google/pprof v0.0.0-20190723021845-34ac40c74b70/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc=
 github.com/google/pprof v0.0.0-20191218002539-d4f498aebedc/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=
+github.com/google/pprof v0.0.0-20200212024743-f11f1df84d12/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=
+github.com/google/pprof v0.0.0-20200229191704-1ebb73c60ed3/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=
+github.com/google/pprof v0.0.0-20200430221834-fc25d7d30c6d/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=
+github.com/google/pprof v0.0.0-20200708004538-1a94d8640e99/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=
+github.com/google/pprof v0.0.0-20201023163331-3e6fc7fc9c4c/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
+github.com/google/pprof v0.0.0-20201203190320-1bf35d6f28c2/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
+github.com/google/pprof v0.0.0-20210122040257-d980be63207e/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
+github.com/google/pprof v0.0.0-20210226084205-cbba55b83ad5/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
 github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI=
-github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510/go.mod h1:pupxD2MaaD3pAXIBCelhxNneeOaAeabZDe5s4K6zSpQ=
-github.com/google/uuid v1.0.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
-github.com/google/uuid v1.1.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
-github.com/google/uuid v1.1.1 h1:Gkbcsh/GbpXz7lPftLA3P6TYMwjCLYm83jiFQZF/3gY=
-github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
-github.com/googleapis/gax-go v2.0.2+incompatible/go.mod h1:SFVmujtThgffbyetf+mdk2eWhX2bMyUtNHzFKcPA9HY=
+github.com/google/uuid v1.1.2 h1:EVhdT+1Kseyi1/pUmXKaFxYsDNy9RQYkMWRH68J/W7Y=
+github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
 github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg=
 github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk=
-github.com/googleapis/gnostic v0.0.0-20170729233727-0c5108395e2d/go.mod h1:sJBsCZ4ayReDTBIg8b9dl28c5xFWyhBTVRp3pOg5EKY=
-github.com/googleapis/gnostic v0.1.0/go.mod h1:sJBsCZ4ayReDTBIg8b9dl28c5xFWyhBTVRp3pOg5EKY=
-github.com/googleapis/gnostic v0.3.1/go.mod h1:on+2t9HRStVgn95RSsFWFz+6Q0Snyqv1awfrALZdbtU=
-github.com/googleapis/gnostic v0.4.1 h1:DLJCy1n/vrD4HPjOvYcT8aYQXpPIzoRZONaYwyycI+I=
-github.com/googleapis/gnostic v0.4.1/go.mod h1:LRhVm6pbyptWbWbuZ38d1eyptfvIytN3ir6b65WBswg=
-github.com/gophercloud/gophercloud v0.2.0/go.mod h1:vxM41WHh5uqHVBMZHzuwNOHh8XEoIEcSTewFxm1c5g8=
-github.com/gophercloud/gophercloud v0.3.0/go.mod h1:vxM41WHh5uqHVBMZHzuwNOHh8XEoIEcSTewFxm1c5g8=
-github.com/gophercloud/gophercloud v0.6.0/go.mod h1:GICNByuaEBibcjmjvI7QvYJSZEbGkcYwAR7EZK2WMqM=
+github.com/googleapis/gnostic v0.5.1/go.mod h1:6U4PtQXGIEt/Z3h5MAT7FNofLnw9vXk2cUuW7uA/OeU=
+github.com/googleapis/gnostic v0.5.5 h1:9fHAtK0uDfpveeqqo1hkEZJcFvYXAiCN3UutL8F9xHw=
+github.com/googleapis/gnostic v0.5.5/go.mod h1:7+EbHbldMins07ALC74bsA81Ovc97DwqyJO1AENw9kA=
 github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY=
-github.com/gopherjs/gopherjs v0.0.0-20191106031601-ce3c9ade29de/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY=
-github.com/gorilla/context v1.1.1/go.mod h1:kBGZzfjB9CEq2AlWe17Uuf7NDRt0dE0s8S51q0aT7Yg=
-github.com/gorilla/handlers v0.0.0-20150720190736-60c7bfde3e33/go.mod h1:Qkdc/uu4tH4g6mTK6auzZ766c4CA0Ng8+o/OAirnOIQ=
-github.com/gorilla/mux v1.6.2/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs=
-github.com/gorilla/mux v1.7.1/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs=
-github.com/gorilla/mux v1.7.2/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs=
-github.com/gorilla/websocket v0.0.0-20170926233335-4201258b820c/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ=
-github.com/gorilla/websocket v1.4.0/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ=
-github.com/gosuri/uitable v0.0.4/go.mod h1:tKR86bXuXPZazfOTG1FIzvjIdXzd0mo4Vtn16vt0PJo=
+github.com/gorilla/mux v1.8.0/go.mod h1:DVbg23sWSpFRCP0SfiEN6jmj59UnW/n46BH5rLB71So=
+github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
 github.com/gregjones/httpcache v0.0.0-20180305231024-9cad4c3443a7/go.mod h1:FecbI9+v66THATjSRHfNgh1IVFe/9kFxbXtjV0ctIMA=
-github.com/grpc-ecosystem/go-grpc-middleware v0.0.0-20190222133341-cfaf5686ec79/go.mod h1:FiyG127CGDf3tlThmgyCl78X/SZQqEOJBCDaAfeWzPs=
+github.com/gregjones/httpcache v0.0.0-20190611155906-901d90724c79 h1:+ngKgrYPPJrOjhax5N+uePQ0Fh1Z7PheYoUI/0nzkPA=
+github.com/gregjones/httpcache v0.0.0-20190611155906-901d90724c79/go.mod h1:FecbI9+v66THATjSRHfNgh1IVFe/9kFxbXtjV0ctIMA=
 github.com/grpc-ecosystem/go-grpc-middleware v1.0.0/go.mod h1:FiyG127CGDf3tlThmgyCl78X/SZQqEOJBCDaAfeWzPs=
-github.com/grpc-ecosystem/go-grpc-middleware v1.0.1-0.20190118093823-f849b5445de4/go.mod h1:FiyG127CGDf3tlThmgyCl78X/SZQqEOJBCDaAfeWzPs=
-github.com/grpc-ecosystem/go-grpc-middleware v1.1.0/go.mod h1:f5nM7jw/oeRSadq3xCzHAvxcr8HZnzsqU6ILg/0NiiE=
+github.com/grpc-ecosystem/go-grpc-middleware v1.3.0/go.mod h1:z0ButlSOZa5vEBq9m2m2hlwIgKw+rp3sdCBRoJY+30Y=
 github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0/go.mod h1:8NvIoxWQoOIhqOTXgfV/d3M/q6VIi02HzZEHgUlZvzk=
-github.com/grpc-ecosystem/grpc-gateway v1.3.0/go.mod h1:RSKVYQBd5MCa4OVpNdGskqpgL2+G+NZTnrVHpWWfpdw=
 github.com/grpc-ecosystem/grpc-gateway v1.9.0/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY=
-github.com/grpc-ecosystem/grpc-gateway v1.9.4/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY=
-github.com/grpc-ecosystem/grpc-gateway v1.9.5/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY=
-github.com/grpc-ecosystem/grpc-gateway v1.12.1/go.mod h1:8XEsbTttt/W+VvjtQhLACqCisSPWTxCZ7sBRjU6iH9c=
-github.com/grpc-ecosystem/grpc-health-probe v0.2.1-0.20181220223928-2bf0a5b182db/go.mod h1:uBKkC2RbarFsvS5jMJHpVhTLvGlGQj9JJwkaePE3FWI=
-github.com/hailocab/go-hostpool v0.0.0-20160125115350-e80d13ce29ed/go.mod h1:tMWxXQ9wFIaZeTI9F+hmhFiGpFmhOHzyShyFUhRm0H4=
+github.com/grpc-ecosystem/grpc-gateway v1.16.0/go.mod h1:BDjrQk3hbvj6Nolgz8mAMFbcEtjT1g+wF4CSlocrBnw=
 github.com/hashicorp/consul/api v1.1.0/go.mod h1:VmuI/Lkw1nC05EYQWNKwWGbkg+FbDBtguAZLlVdkD9Q=
-github.com/hashicorp/consul/api v1.3.0/go.mod h1:MmDNSzIMUjNpY/mQ398R4bk2FnqQLoPndWW5VkKPlCE=
 github.com/hashicorp/consul/sdk v0.1.1/go.mod h1:VKf9jXwCTEY1QZP2MOLRhb5i/I/ssyNV1vwHyQBF0x8=
-github.com/hashicorp/consul/sdk v0.3.0/go.mod h1:VKf9jXwCTEY1QZP2MOLRhb5i/I/ssyNV1vwHyQBF0x8=
-github.com/hashicorp/errwrap v0.0.0-20141028054710-7554cd9344ce/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4=
 github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4=
-github.com/hashicorp/go-cleanhttp v0.5.0/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80=
 github.com/hashicorp/go-cleanhttp v0.5.1/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80=
+github.com/hashicorp/go-hclog v0.9.2/go.mod h1:5CU+agLiy3J7N7QjHK5d05KxGsuXiQLrjA0H7acj2lQ=
 github.com/hashicorp/go-immutable-radix v1.0.0/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60=
-github.com/hashicorp/go-immutable-radix v1.1.0/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60=
 github.com/hashicorp/go-msgpack v0.5.3/go.mod h1:ahLV/dePpqEmjfWmKiqvPkv/twdG7iPBM1vqhUKIvfM=
-github.com/hashicorp/go-msgpack v0.5.5/go.mod h1:ahLV/dePpqEmjfWmKiqvPkv/twdG7iPBM1vqhUKIvfM=
-github.com/hashicorp/go-multierror v0.0.0-20161216184304-ed905158d874/go.mod h1:JMRHfdO9jKNzS/+BTlxCjKNQHg/jZAft8U7LloJvN7I=
 github.com/hashicorp/go-multierror v1.0.0/go.mod h1:dHtQlpGsu+cZNNAkkCN/P3hoUDHhCYQXV3UM06sGGrk=
-github.com/hashicorp/go-retryablehttp v0.5.3/go.mod h1:9B5zBasrRhHXnJnui7y6sL7es7NDiJgTc6Er0maI1Xs=
+github.com/hashicorp/go-multierror v1.1.1/go.mod h1:iw975J/qwKPdAO1clOe2L8331t/9/fmwbPZ6JB6eMoM=
+github.com/hashicorp/go-retryablehttp v0.6.8/go.mod h1:vAew36LZh98gCBJNLH42IQ1ER/9wtLZZ8meHqQvEYWY=
 github.com/hashicorp/go-rootcerts v1.0.0/go.mod h1:K6zTfqpRlCUIjkwsN4Z+hiSfzSTQa6eBIzfwKfwNnHU=
-github.com/hashicorp/go-rootcerts v1.0.1/go.mod h1:pqUvnprVnM5bf7AOirdbb01K4ccR319Vf4pU3K5EGc8=
 github.com/hashicorp/go-sockaddr v1.0.0/go.mod h1:7Xibr9yA9JjQq1JpNB2Vw7kxv8xerXegt+ozgdvDeDU=
-github.com/hashicorp/go-sockaddr v1.0.2/go.mod h1:rB4wwRAUzs07qva3c5SdrY/NEtAUjGlgmH/UkBUC97A=
 github.com/hashicorp/go-syslog v1.0.0/go.mod h1:qPfqrKkXGihmCqbJM2mZgkZGvKG1dFdvsLplgctolz4=
 github.com/hashicorp/go-uuid v1.0.0/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro=
 github.com/hashicorp/go-uuid v1.0.1/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro=
-github.com/hashicorp/go-version v1.1.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA=
 github.com/hashicorp/go.net v0.0.1/go.mod h1:hjKkEWcCURg++eb33jQU7oqQcI9XDCnUzHA0oac0k90=
 github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
 github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
-github.com/hashicorp/golang-lru v0.5.3/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4=
-github.com/hashicorp/golang-lru v0.5.4 h1:YDjusn29QI/Das2iO9M0BHnIbxPeyuCHsjMW+lJfyTc=
-github.com/hashicorp/golang-lru v0.5.4/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4=
 github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ=
 github.com/hashicorp/logutils v1.0.0/go.mod h1:QIAnNjmIWmVIIkWDTG1z5v++HQmx9WQRO+LraFDTW64=
 github.com/hashicorp/mdns v1.0.0/go.mod h1:tL+uN++7HEJ6SQLQ2/p+z2pH24WQKWjBPkE0mNTz8vQ=
 github.com/hashicorp/memberlist v0.1.3/go.mod h1:ajVTdAv/9Im8oMAAj5G31PhhMCZJV2pPBoIllUwCN7I=
-github.com/hashicorp/memberlist v0.1.4/go.mod h1:ajVTdAv/9Im8oMAAj5G31PhhMCZJV2pPBoIllUwCN7I=
-github.com/hashicorp/memberlist v0.1.5/go.mod h1:ajVTdAv/9Im8oMAAj5G31PhhMCZJV2pPBoIllUwCN7I=
 github.com/hashicorp/serf v0.8.2/go.mod h1:6hOLApaqBFA1NXqRQAsxw9QxuDEvNxSQRwA/JwenrHc=
-github.com/hashicorp/serf v0.8.5/go.mod h1:UpNcs7fFbpKIyZaUuSW6EPiH+eZC7OuyFD+wc1oal+k=
 github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU=
-github.com/huandu/xstrings v1.3.1/go.mod h1:y5/lhBue+AyNmUVz9RLU9xbLR0o4KIIExikq4ovT0aE=
-github.com/iancoleman/strcase v0.0.0-20190422225806-e506e3ef7365/go.mod h1:SK73tn/9oHe+/Y0h39VT4UCxmurVJkR5NA7kMEAOgSE=
 github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc=
+github.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc=
 github.com/imdario/mergo v0.3.5/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJh5FfA=
-github.com/imdario/mergo v0.3.7/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJh5FfA=
-github.com/imdario/mergo v0.3.8/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJh5FfA=
-github.com/imdario/mergo v0.3.9 h1:UauaLniWCFHWd+Jp9oCEkTBj8VO/9DKg3PV3VCNMDIg=
-github.com/imdario/mergo v0.3.9/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJh5FfA=
+github.com/imdario/mergo v0.3.12 h1:b6R2BslTbIEToALKP7LxUvijTsNI9TAe80pLWN2g/HU=
+github.com/imdario/mergo v0.3.12/go.mod h1:jmQim1M+e3UYxmgPu/WyfjB3N3VflVyUjjjwH0dnCYA=
 github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8=
-github.com/influxdata/influxdb v1.7.7/go.mod h1:qZna6X/4elxqT3yI9iZYdZrWWdeFOOprn86kgg4+IzY=
-github.com/jackc/fake v0.0.0-20150926172116-812a484cc733/go.mod h1:WrMFNQdiFJ80sQsxDoMokWK1W5TQtxBFNpzWTD84ibQ=
-github.com/jackc/pgx v3.2.0+incompatible/go.mod h1:0ZGrqGqkRlliWnWB4zKnWtjbSWbGkVEFm4TeybAXq+I=
-github.com/jessevdk/go-flags v0.0.0-20180331124232-1c38ed7ad0cc/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI=
+github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99/go.mod h1:1lJo3i6rXxKeerYnT8Nvf0QmHCRC1n8sfWVwXF2Frvo=
 github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI=
-github.com/jmespath/go-jmespath v0.0.0-20160202185014-0b12d6b521d8/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k=
-github.com/jmespath/go-jmespath v0.0.0-20160803190731-bd40a432e4c7/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k=
-github.com/jmespath/go-jmespath v0.0.0-20180206201540-c2b33e8439af/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k=
-github.com/jmoiron/sqlx v1.2.0/go.mod h1:1FEQNm3xlJgrMD+FBdI9+xvCksHtbpVBBw5dYhBSsks=
-github.com/joefitzgerald/rainbow-reporter v0.1.0/go.mod h1:481CNgqmVHQZzdIbN52CupLJyoVwB10FQ/IQlF1pdL8=
-github.com/joeshaw/multierror v0.0.0-20140124173710-69b34d4ec901/go.mod h1:Z86h9688Y0wesXCyonoVr47MasHilkuLMqGhRZ4Hpak=
-github.com/joho/godotenv v1.3.0/go.mod h1:7hK45KPybAkOC6peb+G5yklZfMxEjkZhHbwpqxOKXbg=
+github.com/jessevdk/go-flags v1.5.0/go.mod h1:Fw0T6WPc1dYxT4mKEZRfG5kJhaTDP9pj1c2EWnYs/m4=
 github.com/jonboulle/clockwork v0.1.0/go.mod h1:Ii8DK3G1RaLaWxj9trq07+26W01tbo22gdxWY5EU2bo=
+github.com/jonboulle/clockwork v0.2.2/go.mod h1:Pkfl5aHPm1nk2H9h0bjmnJD/BcgbGXUBGnn1kMkgxc8=
+github.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFFd8Hwg//Y=
 github.com/jpillora/backoff v1.0.0/go.mod h1:J/6gKK9jxlEcS3zixgDgUAsiuZ7yrSoa/FX5e0EB2j4=
-github.com/json-iterator/go v0.0.0-20180612202835-f2b4162afba3/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU=
 github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU=
-github.com/json-iterator/go v1.1.7/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
-github.com/json-iterator/go v1.1.8/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
-github.com/json-iterator/go v1.1.9/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
-github.com/json-iterator/go v1.1.10 h1:Kz6Cvnvv2wGdaG/V8yMvfkmNiXq9Ya2KUv4rouJJr68=
-github.com/json-iterator/go v1.1.10/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
-github.com/jsonnet-bundler/jsonnet-bundler v0.3.1/go.mod h1:/by7P/OoohkI3q4CgSFqcoFsVY+IaNbzOVDknEsKDeU=
+github.com/json-iterator/go v1.1.11/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
+github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM=
+github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo=
 github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU=
 github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/XSXhF0NWZEnDohbsk=
 github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU=
-github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w=
 github.com/julienschmidt/httprouter v1.3.0/go.mod h1:JR6WtHb+2LUe8TCKY3cZOxFyyO8IZAc4RVcycCCAKdM=
-github.com/kardianos/osext v0.0.0-20190222173326-2bc1f35cddc0/go.mod h1:1NbS8ALrpOvjt0rHPNLyCIeMtbizbir8U//inJ+zuB8=
+github.com/k0kubun/colorstring v0.0.0-20150214042306-9440f1994b88/go.mod h1:3w7q1U84EfirKl04SVQ/s7nPm1ZPhiXd34z40TNz36k=
+github.com/k0kubun/pp v2.3.0+incompatible/go.mod h1:GWse8YhT0p8pT4ir3ZgBbfZild3tgzSScAn6HmfYukg=
+github.com/kevinburke/ssh_config v0.0.0-20201106050909-4977a11b4351/go.mod h1:CT57kijsi8u/K/BOFA39wgDQJ9CxiF4nAY/ojJ6r6mM=
 github.com/kisielk/errcheck v1.1.0/go.mod h1:EZBBE59ingxPouuu3KfxchcWSUPOHkagtvWXihfKN4Q=
 github.com/kisielk/errcheck v1.2.0/go.mod h1:/BMXB+zMLi60iA8Vv6Ksmxu/1UDYcXs4uQLJ+jE2L00=
+github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8=
 github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
 github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
-github.com/konsorten/go-windows-terminal-sequences v1.0.2/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
+github.com/konsorten/go-windows-terminal-sequences v1.0.3/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
+github.com/kr/fs v0.1.0/go.mod h1:FFnZGqtBN9Gxj7eW1uZ42v5BccTP0vu6NEaFoC2HwRg=
 github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc=
 github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
-github.com/kr/pretty v0.2.0 h1:s5hAObm+yFO5uHYt5dYjxi2rXrsnmRpJx4OYvIWUaQs=
 github.com/kr/pretty v0.2.0/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI=
+github.com/kr/pretty v0.2.1 h1:Fmg33tUaq4/8ym9TJN1x7sLJnHVwhP33CNkpYV/7rwI=
+github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI=
 github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
-github.com/kr/pty v1.1.5/go.mod h1:9r2w37qlBe7rQ6e1fg1S/9xpWHSnaqNdHD3WcMdbPDA=
-github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE=
 github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
-github.com/kshvakov/clickhouse v1.3.5/go.mod h1:DMzX7FxRymoNkVgizH0DWAL8Cur7wHLgx3MUnGwJqpE=
-github.com/kylelemons/godebug v0.0.0-20160406211939-eadb3ce320cb/go.mod h1:B69LEHPfb2qLo0BaaOLcbitczOKLWTsrBG9LczfCD4k=
-github.com/kylelemons/godebug v0.0.0-20170820004349-d65d576e9348/go.mod h1:B69LEHPfb2qLo0BaaOLcbitczOKLWTsrBG9LczfCD4k=
-github.com/lann/builder v0.0.0-20180802200727-47ae307949d0/go.mod h1:dXGbAdH5GtBTC4WfIxhKZfyBF/HBFgRZSWwZ9g/He9o=
-github.com/lann/ps v0.0.0-20150810152359-62de8c46ede0/go.mod h1:vmVJ0l/dxyfGW6FmdpVm2joNMFikkuWg0EoCKLGUMNw=
-github.com/leanovate/gopter v0.2.4/go.mod h1:gNcbPWNEWRe4lm+bycKqxUYoH5uoVje5SkOJ3uoLer8=
-github.com/lib/pq v1.0.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo=
-github.com/lib/pq v1.2.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo=
-github.com/lib/pq v1.3.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo=
-github.com/liggitt/tabwriter v0.0.0-20181228230101-89fcab3d43de/go.mod h1:zAbeS9B/r2mtpb6U+EI2rYA5OAXxsYw6wTamcNW+zcE=
-github.com/lightstep/lightstep-tracer-common/golang/gogo v0.0.0-20190605223551-bc2310a04743/go.mod h1:qklhhLq1aX+mtWk9cPHPzaBjWImj5ULL6C7HFJtXQMM=
-github.com/lightstep/lightstep-tracer-go v0.18.0/go.mod h1:jlF1pusYV4pidLvZ+XD0UBX0ZE6WURAspgAczcDHrL4=
-github.com/lithammer/dedent v1.1.0/go.mod h1:jrXYCQtgg0nJiN+StA2KgR7w6CiQNv9Fd/Z9BP0jIOc=
-github.com/lovoo/gcloud-opentracing v0.3.0/go.mod h1:ZFqk2y38kMDDikZPAK7ynTTGuyt17nSPdS3K5e+ZTBY=
-github.com/magiconair/properties v1.8.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ=
-github.com/mailru/easyjson v0.0.0-20160728113105-d5b7844b561a/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc=
-github.com/mailru/easyjson v0.0.0-20180823135443-60711f1a8329/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc=
-github.com/mailru/easyjson v0.0.0-20190312143242-1de009706dbe/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc=
+github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
+github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
+github.com/ktrysmt/go-bitbucket v0.9.34/go.mod h1:FWxy2UK7GlK5b0NSJGc5hPqnssVlkNnsChvyuOf/Xno=
+github.com/magiconair/properties v1.8.1/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ=
+github.com/magiconair/properties v1.8.5/go.mod h1:y3VJvCyxH9uVvJTWEGAELF3aiYNyPKd5NZ3oSwXrF60=
 github.com/mailru/easyjson v0.0.0-20190614124828-94de47d64c63/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc=
 github.com/mailru/easyjson v0.0.0-20190626092158-b2ccc519800e/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc=
-github.com/mailru/easyjson v0.7.0 h1:aizVhC/NAAcKWb+5QsU1iNOZb4Yws5UO2I+aIprQITM=
-github.com/mailru/easyjson v0.7.0/go.mod h1:KAzv3t3aY1NaHWoQz1+4F1ccyAH66Jk7yos7ldAVICs=
-github.com/markbates/inflect v1.0.4/go.mod h1:1fR9+pO2KHEO9ZRtto13gDwwZaAKstQzferVeWqbgNs=
-github.com/marstr/guid v1.1.0/go.mod h1:74gB1z2wpxxInTG6yaqA7KrtM0NZ+RbrcqDvYHefzho=
+github.com/mailru/easyjson v0.7.6/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc=
+github.com/matryer/is v1.2.0/go.mod h1:2fLPjFQM9rhQ15aVEtbuwhJinnOqrmgXPNdZsdwlWXA=
 github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU=
-github.com/mattn/go-colorable v0.1.2/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE=
-github.com/mattn/go-ieproxy v0.0.0-20190610004146-91bb50d98149/go.mod h1:31jz6HNzdxOmlERGGEc4v/dMssOfmp2p5bT/okiKFFc=
-github.com/mattn/go-ieproxy v0.0.0-20190702010315-6dee0af9227d/go.mod h1:31jz6HNzdxOmlERGGEc4v/dMssOfmp2p5bT/okiKFFc=
-github.com/mattn/go-ieproxy v0.0.0-20191113090002-7c0f6868bffe/go.mod h1:pYabZ6IHcRpFh7vIaLfK7rdcWgFEb3SFJ6/gNWuh88E=
 github.com/mattn/go-isatty v0.0.3/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4=
-github.com/mattn/go-isatty v0.0.4/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4=
-github.com/mattn/go-isatty v0.0.6/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s=
-github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s=
-github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU=
-github.com/mattn/go-runewidth v0.0.2/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU=
-github.com/mattn/go-runewidth v0.0.4/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU=
-github.com/mattn/go-runewidth v0.0.6/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI=
-github.com/mattn/go-shellwords v1.0.10/go.mod h1:EZzvwXDESEeg03EKmM+RmDnNOPKG4lLtQsUlTZDWQ8Y=
-github.com/mattn/go-sqlite3 v1.9.0/go.mod h1:FPy6KqzDD04eiIsT53CuJW3U88zkxoIYsOqkbpncsNc=
-github.com/mattn/go-sqlite3 v1.10.0/go.mod h1:FPy6KqzDD04eiIsT53CuJW3U88zkxoIYsOqkbpncsNc=
-github.com/mattn/go-sqlite3 v1.12.0/go.mod h1:FPy6KqzDD04eiIsT53CuJW3U88zkxoIYsOqkbpncsNc=
-github.com/matttproud/golang_protobuf_extensions v1.0.1 h1:4hp9jkHxhMHkqkrB3Ix0jegS5sx/RkqARlsWZ6pIwiU=
 github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0=
-github.com/maxbrunsfeld/counterfeiter/v6 v6.2.2/go.mod h1:eD9eIE7cdwcMi9rYluz88Jz2VyhSmden33/aXg4oVIY=
+github.com/matttproud/golang_protobuf_extensions v1.0.2-0.20181231171920-c182affec369 h1:I0XW9+e1XWDxdcEniV4rQAIOPUGDq67JSCiRCgGCZLI=
+github.com/matttproud/golang_protobuf_extensions v1.0.2-0.20181231171920-c182affec369/go.mod h1:BSXmuO+STAnVfrANrmjBb36TMTDstsz7MSK+HVaYKv4=
 github.com/miekg/dns v1.0.14/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg=
-github.com/miekg/dns v1.1.15/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg=
-github.com/miekg/dns v1.1.22/go.mod h1:bPDLeHnStXmXAq1m/Ch/hvfNHr14JKNPMBo3VZKjuso=
-github.com/mikefarah/yaml/v2 v2.4.0/go.mod h1:ahVqZF4n1W4NqwvVnZzC4es67xsW9uR/RRf2RRxieJU=
-github.com/mikefarah/yq/v2 v2.4.1/go.mod h1:i8SYf1XdgUvY2OFwSqGAtWOOgimD2McJ6iutoxRm4k0=
-github.com/minio/minio-go/v6 v6.0.49/go.mod h1:qD0lajrGW49lKZLtXKtCB4X/qkMf0a5tBvN2PaZg7Gg=
-github.com/minio/sha256-simd v0.1.1/go.mod h1:B5e1o+1/KgNmWrSQK08Y6Z1Vb5pwIktudl0J58iy0KM=
 github.com/mitchellh/cli v1.0.0/go.mod h1:hNIlj7HEI86fIcpObd7a0FcrxTWetlwJDGcceTlRvqc=
-github.com/mitchellh/copystructure v1.0.0/go.mod h1:SNtv71yrdKgLRyLFxmLdkAbkKEFWgYaq1OVrnRcwhnw=
 github.com/mitchellh/go-homedir v1.0.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0=
 github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0=
 github.com/mitchellh/go-testing-interface v1.0.0/go.mod h1:kRemZodwjscx+RGhAo8eIhFbs2+BFgRtFPeD/KE+zxI=
-github.com/mitchellh/go-wordwrap v1.0.0/go.mod h1:ZXFpozHsX6DPmq2I0TCekCxypsnAUbP2oI0UX1GXzOo=
 github.com/mitchellh/gox v0.4.0/go.mod h1:Sd9lOJ0+aimLBi73mGofS1ycjY8lL3uZM3JPS42BGNg=
-github.com/mitchellh/hashstructure v0.0.0-20170609045927-2bca23e0e452/go.mod h1:QjSHrPWS+BGUVBYkbTZWEnOh3G1DutKwClXU/ABz6AQ=
 github.com/mitchellh/iochan v1.0.0/go.mod h1:JwYml1nuB7xOzsp52dPpHFffvOCDupsG0QubkSMEySY=
 github.com/mitchellh/mapstructure v0.0.0-20160808181253-ca63d7c062ee/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y=
+github.com/mitchellh/mapstructure v0.0.0-20180220230111-00c29f56e238/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y=
 github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y=
-github.com/mitchellh/osext v0.0.0-20151018003038-5e2d6d41470f/go.mod h1:OkQIRizQZAeMln+1tSwduZz7+Af5oFlKirV/MSYes2A=
-github.com/mitchellh/reflectwalk v1.0.0/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw=
+github.com/mitchellh/mapstructure v1.4.1/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo=
+github.com/moby/spdystream v0.2.0/go.mod h1:f7i0iNDQJ059oMTcWxx8MA/zKFIuD/lY+0GqbN2Wy8c=
+github.com/moby/term v0.0.0-20210610120745-9d4ed1856297/go.mod h1:vgPCkQMyxTZ7IDy8SXRufE172gr8+K/JE/7hHFxHW3A=
 github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
 github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg=
 github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
-github.com/modern-go/reflect2 v0.0.0-20180320133207-05fbef0ca5da/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
 github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
-github.com/modern-go/reflect2 v1.0.1 h1:9f412s+6RmYXLWZSEzVVgPGK7C2PphHj5RJrvfx9AWI=
 github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
-github.com/morikuni/aec v0.0.0-20170113033406-39771216ff4c/go.mod h1:BbKIizmSmc5MMPqRYbxO4ZU0S0+P200+tUnFx7PXmsc=
-github.com/morikuni/aec v1.0.0/go.mod h1:BbKIizmSmc5MMPqRYbxO4ZU0S0+P200+tUnFx7PXmsc=
-github.com/mozillazg/go-cos v0.13.0/go.mod h1:Zp6DvvXn0RUOXGJ2chmWt2bLEqRAnJnS3DnAZsJsoaE=
-github.com/mozillazg/go-httpheader v0.2.1/go.mod h1:jJ8xECTlalr6ValeXYdOF8fFUISeBAdw6E61aqQma60=
+github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M=
+github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk=
 github.com/munnerz/goautoneg v0.0.0-20120707110453-a547fc61f48d/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ=
 github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ=
-github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U=
 github.com/mwitkow/go-conntrack v0.0.0-20190716064945-2f068394615f/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U=
 github.com/mxk/go-flowrate v0.0.0-20140419014527-cca7078d478f/go.mod h1:ZdcZmHo+o7JKHSa8/e818NopupXU1YMK5fe1lsApnBw=
-github.com/nakagami/firebirdsql v0.0.0-20190310045651-3c02a58cfed8/go.mod h1:86wM1zFnC6/uDBfZGNwB65O+pR2OFi5q/YQaEUid1qA=
-github.com/ncw/swift v1.0.47/go.mod h1:23YIA4yWVnGwv2dQlN4bB7egfYX6YLn0Yo/S6zZO/ZM=
-github.com/nxadm/tail v1.4.4 h1:DQuhQpB1tVlglWS2hLQ5OV6B5r8aGxSrPc5Qo6uTN78=
+github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno=
 github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A=
-github.com/oklog/run v1.0.0/go.mod h1:dlhp/R75TPv97u0XWUtDeV/lRKWPKSdTuV0TZvrmrQA=
-github.com/oklog/ulid v0.0.0-20170117200651-66bb6560562f/go.mod h1:CirwcVhetQ6Lv90oh/F+FBtV6XMibvdAFo93nm5qn4U=
-github.com/oklog/ulid v1.3.1/go.mod h1:CirwcVhetQ6Lv90oh/F+FBtV6XMibvdAFo93nm5qn4U=
-github.com/olekukonko/tablewriter v0.0.0-20170122224234-a0225b3f23b5/go.mod h1:vsDQFd/mU46D+Z4whnwzcISnGGzXWMclvtLoiIKAKIo=
-github.com/olekukonko/tablewriter v0.0.1/go.mod h1:vsDQFd/mU46D+Z4whnwzcISnGGzXWMclvtLoiIKAKIo=
-github.com/olekukonko/tablewriter v0.0.2/go.mod h1:rSAaSIOAGT9odnlyGlUfAJaoc5w2fSBUmeGDbRWPxyQ=
+github.com/nxadm/tail v1.4.8 h1:nPr65rt6Y5JFSKQO7qToXr7pePgD6Gwiw05lkbyAQTE=
+github.com/nxadm/tail v1.4.8/go.mod h1:+ncqLTQzXmGhMZNUePPaPqPvBxHAIsmXswZKocGu+AU=
 github.com/onsi/ginkgo v0.0.0-20170829012221-11459a886d9c/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
 github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
-github.com/onsi/ginkgo v1.7.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
-github.com/onsi/ginkgo v1.8.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
-github.com/onsi/ginkgo v1.10.1/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
-github.com/onsi/ginkgo v1.10.3/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
-github.com/onsi/ginkgo v1.11.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
-github.com/onsi/ginkgo v1.12.0/go.mod h1:oUhWkIvk5aDxtKvDDuw8gItl8pKl42LzjC9KZE0HfGg=
-github.com/onsi/ginkgo v1.12.1 h1:mFwc4LvZ0xpSvDZ3E+k8Yte0hLOMxXUlP+yXtJqkYfQ=
 github.com/onsi/ginkgo v1.12.1/go.mod h1:zj2OWP4+oCPe1qIXoGWkgMRwljMUYCdkwsT2108oapk=
+github.com/onsi/ginkgo v1.14.0/go.mod h1:iSB4RoI2tjJc9BBv4NKIKWKya62Rps+oPG/Lv9klQyY=
+github.com/onsi/ginkgo v1.16.4/go.mod h1:dX+/inL/fNMqNlz0e9LfyB9TswhZpCVdJM/Z6Vvnwo0=
+github.com/onsi/ginkgo v1.16.5 h1:8xi0RTUf59SOSfEtZMvwTvXYMzG4gV23XVHOZiXNtnE=
+github.com/onsi/ginkgo v1.16.5/go.mod h1:+E8gABHa3K6zRBolWtd+ROzc/U5bkGt0FwiG042wbpU=
 github.com/onsi/gomega v0.0.0-20170829124025-dcabb60a477c/go.mod h1:C1qb7wdrVGGVU+Z6iS04AVkA3Q65CEZX59MT0QO5uiA=
-github.com/onsi/gomega v1.4.3/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY=
-github.com/onsi/gomega v1.5.0/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY=
-github.com/onsi/gomega v1.7.0/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY=
 github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY=
-github.com/onsi/gomega v1.8.1/go.mod h1:Ho0h+IUsWyvy1OpqCwxlQ/21gkhVunqlU8fDGcoTdcA=
-github.com/onsi/gomega v1.9.0/go.mod h1:Ho0h+IUsWyvy1OpqCwxlQ/21gkhVunqlU8fDGcoTdcA=
-github.com/onsi/gomega v1.10.1 h1:o0+MgICZLuZ7xjH7Vx6zS/zcu93/BEp1VwkIW1mEXCE=
 github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo=
-github.com/opencontainers/go-digest v0.0.0-20170106003457-a6d0ee40d420/go.mod h1:cMLVZDEM3+U2I4VmLI6N8jQYUd2OVphdqWwCJHrFt2s=
-github.com/opencontainers/go-digest v0.0.0-20180430190053-c9281466c8b2/go.mod h1:cMLVZDEM3+U2I4VmLI6N8jQYUd2OVphdqWwCJHrFt2s=
-github.com/opencontainers/go-digest v1.0.0-rc1/go.mod h1:cMLVZDEM3+U2I4VmLI6N8jQYUd2OVphdqWwCJHrFt2s=
-github.com/opencontainers/image-spec v1.0.0/go.mod h1:BtxoFyWECRxE4U/7sNtV5W15zMzWCbyJoFRP3s7yZA0=
-github.com/opencontainers/image-spec v1.0.1/go.mod h1:BtxoFyWECRxE4U/7sNtV5W15zMzWCbyJoFRP3s7yZA0=
-github.com/opencontainers/image-spec v1.0.2-0.20190823105129-775207bd45b6/go.mod h1:BtxoFyWECRxE4U/7sNtV5W15zMzWCbyJoFRP3s7yZA0=
-github.com/opencontainers/runc v0.0.0-20190115041553-12f6a991201f/go.mod h1:qT5XzbpPznkRYVz/mWwUaVBUv2rmF59PVA73FjuZG0U=
-github.com/opencontainers/runc v0.1.1/go.mod h1:qT5XzbpPznkRYVz/mWwUaVBUv2rmF59PVA73FjuZG0U=
-github.com/opencontainers/runtime-spec v0.1.2-0.20190507144316-5b71a03e2700/go.mod h1:jwyrGlmzljRJv/Fgzds9SsS/C5hL+LL3ko9hs6T5lQ0=
-github.com/opencontainers/runtime-tools v0.0.0-20181011054405-1d69bd0f9c39/go.mod h1:r3f7wjNzSs2extwzU3Y+6pKfobzPh+kKFJ3ofN+3nfs=
-github.com/openshift/origin v0.0.0-20160503220234-8f127d736703/go.mod h1:0Rox5r9C8aQn6j1oAOQ0c1uC86mYbUFObzjBRvUKHII=
-github.com/openshift/prom-label-proxy v0.1.1-0.20191016113035-b8153a7f39f1/go.mod h1:p5MuxzsYP1JPsNGwtjtcgRHHlGziCJJfztff91nNixw=
-github.com/opentracing-contrib/go-stdlib v0.0.0-20190519235532-cf7a6c988dc9/go.mod h1:PLldrQSroqzH70Xl+1DQcGnefIbqsKR7UDaiux3zV+w=
-github.com/opentracing/basictracer-go v1.0.0/go.mod h1:QfBfYuafItcjQuMwinw9GhYKwFXS9KnPs5lxoYwgW74=
-github.com/opentracing/opentracing-go v1.0.2/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o=
+github.com/onsi/gomega v1.17.0 h1:9Luw4uT5HTjHTN8+aNcSThgH1vdXnmdJ8xIfZ4wyTRE=
+github.com/onsi/gomega v1.17.0/go.mod h1:HnhC7FXeEQY45zxNK3PPoIUhzk/80Xly9PcubAlGdZY=
 github.com/opentracing/opentracing-go v1.1.0/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o=
-github.com/openzipkin/zipkin-go v0.1.6/go.mod h1:QgAqvLzwWbR/WpD4A3cGpPtJrZXNIiJc5AZX7/PBEpw=
-github.com/operator-framework/api v0.3.7-0.20200602203552-431198de9fc2/go.mod h1:Xbje9x0SHmh0nihE21kpesB38vk3cyxnE6JdDS8Jo1Q=
-github.com/operator-framework/api v0.3.8/go.mod h1:Xbje9x0SHmh0nihE21kpesB38vk3cyxnE6JdDS8Jo1Q=
-github.com/operator-framework/operator-registry v1.12.6-0.20200611222234-275301b779f8/go.mod h1:loVINznYhgBIkmv83kU4yee88RS0BBk+hqOw9r4bhJk=
-github.com/operator-framework/operator-sdk v0.19.0 h1:pnHx1EjcP20miuBpxFC2s+uuPeItcrmRR6bOFhm4D6c=
-github.com/operator-framework/operator-sdk v0.19.0/go.mod h1:8MR6CguLizat2RGjdSMifGwW6mEMwKqAtZnSUHJ6SxU=
-github.com/otiai10/copy v1.2.0/go.mod h1:rrF5dJ5F0t/EWSYODDu4j9/vEeYHMkc8jt0zJChqQWw=
-github.com/otiai10/curr v0.0.0-20150429015615-9b4961190c95/go.mod h1:9qAhocn7zKJG+0mI8eUu6xqkFDYS2kb2saOteoSB3cE=
-github.com/otiai10/curr v1.0.0/go.mod h1:LskTG5wDwr8Rs+nNQ+1LlxRjAtTZZjtJW4rMXl6j4vs=
-github.com/otiai10/mint v1.3.0/go.mod h1:F5AjcsTsWUqX+Na9fpHb52P8pcRX2CI6A3ctIT91xUo=
-github.com/otiai10/mint v1.3.1/go.mod h1:/yxELlJQ0ufhjUwhshSj+wFjZ78CnZ48/1wtmBH1OTc=
 github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc=
-github.com/pascaldekloe/goe v0.1.0/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc=
-github.com/pborman/uuid v1.2.0/go.mod h1:X/NO0urCmaxf9VXbdlT7C2Yzkj2IKimNn4k+gtPdI/k=
 github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic=
+github.com/pelletier/go-toml v1.9.3/go.mod h1:u1nR/EPcESfeI/szUZKdtJ0xRNbUoANCkoOuaOx1Y+c=
 github.com/peterbourgon/diskv v2.0.1+incompatible/go.mod h1:uqqh8zWWbv1HBMNONnaR/tNboyR3/BZd58JJSHlUSCU=
-github.com/phayes/freeport v0.0.0-20180830031419-95f893ade6f2/go.mod h1:iIss55rKnNBTvrwdmkUpLnDpZoAHvWaiq5+iMmen4AE=
-github.com/pierrec/lz4 v2.0.5+incompatible/go.mod h1:pdkljMzZIN41W+lC3N2tnIh5sFi+IEE17M5jbnwPHcY=
-github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
-github.com/pkg/errors v0.8.1-0.20171018195549-f15c970de5b7/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
 github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
 github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
 github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
-github.com/pmezard/go-difflib v0.0.0-20151028094244-d8ed2627bdf0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
+github.com/pkg/sftp v1.10.1/go.mod h1:lYOWFsE0bwd1+KfKJaKeuokY15vzFx25BLbzYYoAxZI=
 github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
 github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
 github.com/posener/complete v1.1.1/go.mod h1:em0nMJCgc9GFtwrmVmEMR/ZL6WyhyjMBndrE9hABlRI=
 github.com/pquerna/cachecontrol v0.0.0-20171018203845-0dec1b30a021/go.mod h1:prYjPmNq4d1NPVmpShWobRqXY3q7Vp+80DqgxxUrUIA=
-github.com/prometheus/alertmanager v0.18.0/go.mod h1:WcxHBl40VSPuOaqWae6l6HpnEOVRIycEJ7i9iYkadEE=
-github.com/prometheus/alertmanager v0.20.0/go.mod h1:9g2i48FAyZW6BtbsnvHtMHQXl2aVtrORKwKVCQ+nbrg=
-github.com/prometheus/client_golang v0.0.0-20180209125602-c332b6f63c06/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw=
-github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw=
-github.com/prometheus/client_golang v0.9.2/go.mod h1:OsXs2jCmiKlQ1lTBmv21f2mNfw4xf/QclQDMrYNZzcM=
-github.com/prometheus/client_golang v0.9.3-0.20190127221311-3c4408c8b829/go.mod h1:p2iRAGwDERtqlqzRXnrOVns+ignqQo//hLXqYxZYVNs=
-github.com/prometheus/client_golang v0.9.3/go.mod h1:/TN21ttK/J9q6uSwhBd54HahCDft0ttaMvbicHlPoso=
-github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo=
-github.com/prometheus/client_golang v1.1.0/go.mod h1:I1FGZT9+L76gKKOs5djB6ezCbFQP1xR9D75/vuwEF3g=
-github.com/prometheus/client_golang v1.2.0/go.mod h1:XMU6Z2MjaRKVu/dC1qupJI9SiNkDYzz3xecMgSW/F+U=
-github.com/prometheus/client_golang v1.2.1/go.mod h1:XMU6Z2MjaRKVu/dC1qupJI9SiNkDYzz3xecMgSW/F+U=
-github.com/prometheus/client_golang v1.5.1 h1:bdHYieyGlH+6OLEk2YQha8THib30KP0/yD0YH9m6xcA=
-github.com/prometheus/client_golang v1.5.1/go.mod h1:e9GMxYsXl05ICDXkRhurwBS4Q3OK1iX/F2sw+iXX5zU=
-github.com/prometheus/client_model v0.0.0-20171117100541-99fa1f4be8e5/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo=
-github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo=
-github.com/prometheus/client_model v0.0.0-20190115171406-56726106282f/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo=
-github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
+github.com/prometheus/client_golang v1.11.1 h1:+4eQaD7vAZ6DsfsxB15hbE0odUjGI5ARs9yskGu1v4s=
+github.com/prometheus/client_golang v1.11.1/go.mod h1:Z6t4BnS23TR94PD6BsDNk8yVqroYurpAkEiz0P2BEV0=
 github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
 github.com/prometheus/client_model v0.2.0 h1:uq5h0d+GuxiXLJLNABMgp2qUWDPiLvgCzz2dUR+/W/M=
 github.com/prometheus/client_model v0.2.0/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
-github.com/prometheus/common v0.0.0-20180110214958-89604d197083/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro=
-github.com/prometheus/common v0.0.0-20181113130724-41aa239b4cce/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro=
-github.com/prometheus/common v0.0.0-20181126121408-4724e9255275/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro=
-github.com/prometheus/common v0.2.0/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4=
-github.com/prometheus/common v0.4.0/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4=
-github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4=
-github.com/prometheus/common v0.6.0/go.mod h1:eBmuwkDJBwy6iBfxCBob6t6dR6ENT/y+J+Zk0j9GMYc=
-github.com/prometheus/common v0.7.0/go.mod h1:DjGbpBbp5NYNiECxcL/VnbXCCaQpKd3tt26CguLLsqA=
-github.com/prometheus/common v0.9.1 h1:KOMtN28tlbam3/7ZKEYKHhKoJZYYj3gMH4uc62x7X7U=
-github.com/prometheus/common v0.9.1/go.mod h1:yhUN8i9wzaXS3w1O07YhxHEBxD+W35wd8bs7vj7HSQ4=
-github.com/prometheus/procfs v0.0.0-20180125133057-cb4147076ac7/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk=
-github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk=
-github.com/prometheus/procfs v0.0.0-20181204211112-1dc9a6cbc91a/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk=
-github.com/prometheus/procfs v0.0.0-20190117184657-bf6a532e95b1/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk=
-github.com/prometheus/procfs v0.0.0-20190425082905-87a4384529e0/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA=
-github.com/prometheus/procfs v0.0.0-20190507164030-5867b95ac084/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA=
-github.com/prometheus/procfs v0.0.0-20190522114515-bc1a522cf7b1/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA=
-github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA=
-github.com/prometheus/procfs v0.0.3/go.mod h1:4A/X28fw3Fc593LaREMrKMqOKvUAntwMDaekg4FpcdQ=
-github.com/prometheus/procfs v0.0.5/go.mod h1:4A/X28fw3Fc593LaREMrKMqOKvUAntwMDaekg4FpcdQ=
-github.com/prometheus/procfs v0.0.6/go.mod h1:7Qr8sr6344vo1JqZ6HhLceV9o3AJ1Ff+GxbHq6oeK9A=
-github.com/prometheus/procfs v0.0.8/go.mod h1:7Qr8sr6344vo1JqZ6HhLceV9o3AJ1Ff+GxbHq6oeK9A=
-github.com/prometheus/procfs v0.0.11 h1:DhHlBtkHWPYi8O2y31JkK0TF+DGM+51OopZjH/Ia5qI=
-github.com/prometheus/procfs v0.0.11/go.mod h1:lV6e/gmhEcM9IjHGsFOCxxuZ+z1YqCvr4OA4YeYWdaU=
-github.com/prometheus/prometheus v0.0.0-20180315085919-58e2a31db8de/go.mod h1:oAIUtOny2rjMX0OWN5vPR5/q/twIROJvdqnQKDdil/s=
-github.com/prometheus/prometheus v1.8.2-0.20200110114423-1e64d757f711/go.mod h1:7U90zPoLkWjEIQcy/rweQla82OCTUzxVHE51G3OhJbI=
-github.com/prometheus/prometheus v2.3.2+incompatible/go.mod h1:oAIUtOny2rjMX0OWN5vPR5/q/twIROJvdqnQKDdil/s=
-github.com/prometheus/tsdb v0.7.1/go.mod h1:qhTCs0VvXwvX/y3TZrWD7rabWM+ijKTux40TwIPHuXU=
-github.com/rcrowley/go-metrics v0.0.0-20181016184325-3113b8401b8a/go.mod h1:bCqnVzQkZxMG4s8nGwiZ5l3QUCyqpo9Y+/ZMZ9VjZe4=
-github.com/remyoudompheng/bigfft v0.0.0-20170806203942-52369c62f446/go.mod h1:uYEyJGbgTkfkS4+E/PavXkNJcbFIpEtjt2B0KDQ5+9M=
-github.com/robfig/cron v0.0.0-20170526150127-736158dc09e1/go.mod h1:JGuDeoQd7Z6yL4zQhZ3OPEVHB7fL6Ka6skscFHfmt2k=
+github.com/prometheus/common v0.26.0/go.mod h1:M7rCNAaPfAosfx8veZJCuw84e35h3Cfd9VFqTh1DIvc=
+github.com/prometheus/common v0.28.0 h1:vGVfV9KrDTvWt5boZO0I19g2E3CsWfpPPKZM9dt3mEw=
+github.com/prometheus/common v0.28.0/go.mod h1:vu+V0TpY+O6vW9J44gczi3Ap/oXXR10b+M/gUGO4Hls=
+github.com/prometheus/procfs v0.6.0 h1:mxy4L2jP6qMonqmq+aTtOx1ifVWUgG/TAmntgbh3xv4=
+github.com/prometheus/procfs v0.6.0/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1xBZuNvfVA=
 github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6SoW27p1b0cqNHllgS5HIMJraePCO15w5zCzIWYg=
 github.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ=
-github.com/rogpeppe/go-internal v1.1.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
 github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
-github.com/rogpeppe/go-internal v1.3.2/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTEfhy4qGm1nDQc=
-github.com/rogpeppe/go-internal v1.4.0/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTEfhy4qGm1nDQc=
-github.com/rogpeppe/go-internal v1.5.0/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTEfhy4qGm1nDQc=
-github.com/rs/cors v1.6.0/go.mod h1:gFx+x8UowdsKA9AchylcLynDq+nNFfI8FkUZdN/jGCU=
-github.com/rubenv/sql-migrate v0.0.0-20200212082348-64f95ea68aa3/go.mod h1:rtQlpHw+eR6UrqaS3kX1VYeaCxzCVdimDS7g5Ln4pPc=
-github.com/russross/blackfriday v1.5.2/go.mod h1:JO/DiYxRf+HjHt06OyowR9PTA263kcR/rfWxYHBV53g=
 github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
 github.com/ryanuber/columnize v0.0.0-20160712163229-9b3edd62028f/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts=
-github.com/ryanuber/columnize v2.1.0+incompatible/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts=
-github.com/samuel/go-zookeeper v0.0.0-20190810000440-0ceca61e4d75/go.mod h1:gi+0XIa01GRL2eRQVjQkKGqKF3SF9vZR/HnPullcV2E=
-github.com/samuel/go-zookeeper v0.0.0-20190923202752-2cc03de413da/go.mod h1:gi+0XIa01GRL2eRQVjQkKGqKF3SF9vZR/HnPullcV2E=
-github.com/santhosh-tekuri/jsonschema v1.2.4/go.mod h1:TEAUOeZSmIxTTuHatJzrvARHiuO9LYd+cIxzgEHCQI4=
-github.com/satori/go.uuid v0.0.0-20160603004225-b111a074d5ef/go.mod h1:dA0hQrYB0VpLJoorglMZABFdXlWrHn1NEOzdhQKdks0=
-github.com/satori/go.uuid v1.2.0/go.mod h1:dA0hQrYB0VpLJoorglMZABFdXlWrHn1NEOzdhQKdks0=
-github.com/sclevine/spec v1.2.0/go.mod h1:W4J29eT/Kzv7/b9IWLB055Z+qvVC9vt0Arko24q7p+U=
 github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529/go.mod h1:DxrIzT+xaE7yg65j358z/aeFdxmN0P9QXhEzd20vsDc=
-github.com/sergi/go-diff v1.0.0/go.mod h1:0CfEIISq7TuYL3j771MWULgwwjU+GofnZX9QAmXWZgo=
-github.com/shopspring/decimal v0.0.0-20180709203117-cd690d0c9e24/go.mod h1:M+9NzErvs504Cn4c5DxATwIqPbtswREoFCre64PpcG4=
-github.com/shurcooL/httpfs v0.0.0-20171119174359-809beceb2371/go.mod h1:ZY1cvUeJuFPAdZ/B6v7RHavJWZn2YPVFQ1OSXhCGOkg=
-github.com/shurcooL/httpfs v0.0.0-20190707220628-8d4bc4ba7749/go.mod h1:ZY1cvUeJuFPAdZ/B6v7RHavJWZn2YPVFQ1OSXhCGOkg=
+github.com/sergi/go-diff v1.1.0/go.mod h1:STckp+ISIX8hZLjrqAeVduY0gWCT9IjLuqbuNXdaHfM=
 github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc=
-github.com/shurcooL/vfsgen v0.0.0-20180825020608-02ddb050ef6b/go.mod h1:TrYk7fJVaAttu97ZZKrO9UbRa8izdowaMIZcxYMbVaw=
-github.com/shurcooL/vfsgen v0.0.0-20181202132449-6a9ea43bcacd/go.mod h1:TrYk7fJVaAttu97ZZKrO9UbRa8izdowaMIZcxYMbVaw=
-github.com/sirupsen/logrus v1.0.4-0.20170822132746-89742aefa4b2/go.mod h1:pMByvHTf9Beacp5x1UXfOR9xyW/9antXMhjMPG0dEzc=
-github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo=
 github.com/sirupsen/logrus v1.4.1/go.mod h1:ni0Sbl8bgC9z8RoU9G6nDWqqs/fq4eDPysMBDgk/93Q=
 github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE=
-github.com/sirupsen/logrus v1.5.0/go.mod h1:+F7Ogzej0PZc/94MaYx/nvG9jOFMD2osvC3s+Squfpo=
+github.com/sirupsen/logrus v1.6.0/go.mod h1:7uNnSEd1DgxDLC74fIahvMZmmYsHGZGEOFrfsX/uA88=
+github.com/sirupsen/logrus v1.7.0/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0=
+github.com/sirupsen/logrus v1.8.1/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0=
 github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc=
-github.com/smartystreets/assertions v1.0.1/go.mod h1:kHHU4qYBaI3q23Pp3VPrmWhuIUrLW/7eUrw0BU5VaoM=
-github.com/smartystreets/goconvey v0.0.0-20190330032615-68dc04aab96a/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA=
 github.com/smartystreets/goconvey v1.6.4/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA=
-github.com/soheilhy/cmux v0.1.3/go.mod h1:IM3LyeVVIOuxMH7sFAkER9+bJ4dT7Ms6E4xg4kGIyLM=
 github.com/soheilhy/cmux v0.1.4/go.mod h1:IM3LyeVVIOuxMH7sFAkER9+bJ4dT7Ms6E4xg4kGIyLM=
+github.com/soheilhy/cmux v0.1.5/go.mod h1:T7TcVDs9LWfQgPlPsdngu6I6QIoyIFZDDC6sNE1GqG0=
 github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA=
-github.com/spaolacci/murmur3 v1.1.0/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA=
 github.com/spf13/afero v1.1.2/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B0CQ=
 github.com/spf13/afero v1.2.2/go.mod h1:9ZxEEn6pIJ8Rxe320qSDBk6AsU0r9pR7Q4OcevTdifk=
+github.com/spf13/afero v1.6.0/go.mod h1:Ai8FlHk4v/PARR026UzYexafAt9roJ7LcLMAmO6Z93I=
 github.com/spf13/cast v1.3.0/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE=
 github.com/spf13/cast v1.3.1/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE=
-github.com/spf13/cobra v0.0.2-0.20171109065643-2da4a54c5cee/go.mod h1:1l0Ry5zgKvJasoi3XT1TypsSe7PqH0Sj9dhYf7v3XqQ=
-github.com/spf13/cobra v0.0.3/go.mod h1:1l0Ry5zgKvJasoi3XT1TypsSe7PqH0Sj9dhYf7v3XqQ=
-github.com/spf13/cobra v0.0.5/go.mod h1:3K3wKZymM7VvHMDS9+Akkh4K60UwM26emMESw8tLCHU=
-github.com/spf13/cobra v0.0.6/go.mod h1:/6GTrnGXV9HjY+aR4k0oJ5tcvakLuG6EuKReYlHNrgE=
-github.com/spf13/cobra v0.0.7/go.mod h1:/6GTrnGXV9HjY+aR4k0oJ5tcvakLuG6EuKReYlHNrgE=
-github.com/spf13/cobra v1.0.0/go.mod h1:/6GTrnGXV9HjY+aR4k0oJ5tcvakLuG6EuKReYlHNrgE=
+github.com/spf13/cobra v1.1.3/go.mod h1:pGADOWyqRD/YMrPZigI/zbliZ2wVD/23d+is3pSWzOo=
+github.com/spf13/cobra v1.2.1/go.mod h1:ExllRjgxM/piMAM+3tAZvg8fsklGAf3tPfi+i8t68Nk=
 github.com/spf13/jwalterweatherman v1.0.0/go.mod h1:cQK4TGJAtQXfYWX+Ddv3mKDzgVb68N+wFjFa4jdeBTo=
-github.com/spf13/pflag v0.0.0-20170130214245-9ff6c6923cff/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4=
-github.com/spf13/pflag v1.0.1-0.20171106142849-4c012f6dcd95/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4=
-github.com/spf13/pflag v1.0.1/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4=
+github.com/spf13/jwalterweatherman v1.1.0/go.mod h1:aNWZUN0dPAAO/Ljvb5BEdw96iTZ0EXowPYD95IqWIGo=
 github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4=
 github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA=
 github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
-github.com/spf13/viper v1.3.2/go.mod h1:ZiWeW+zYFKm7srdB9IoDzzZXaJaI5eL9QjNiN/DMA2s=
-github.com/spf13/viper v1.4.0/go.mod h1:PTJ7Z/lr49W6bUbkmS1V3by4uWynFiR9p7+dSq/yZzE=
+github.com/spf13/viper v1.7.0/go.mod h1:8WkrPz2fc9jxqZNCJI/76HCieCp4Q8HaLFoCha5qpdg=
+github.com/spf13/viper v1.8.1/go.mod h1:o0Pch8wJ9BVSWGQMbra6iw0oQ5oktSIBaujf1rJH9Ns=
+github.com/stoewer/go-strcase v1.2.0/go.mod h1:IBiWB2sKIp3wVVQ3Y035++gc+knqhUQag1KpM8ahLw8=
 github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
 github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
-github.com/stretchr/objx v0.2.0/go.mod h1:qt09Ya8vawLte6SNmTgCsAVtYtaKzEcn8ATUoHMkEqE=
-github.com/stretchr/testify v0.0.0-20151208002404-e3a8ff8ce365/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
 github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
 github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
 github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
-github.com/stretchr/testify v1.5.1 h1:nOGnQDM7FYENwehXlg/kFVnos3rEvtKTjRvOWSzb6H4=
 github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA=
-github.com/syndtr/gocapability v0.0.0-20170704070218-db04d3cc01c8/go.mod h1:hkRG7XYTFWNJGYcbNJQlaLq0fg1yr4J4t/NcTQtrfww=
-github.com/thanos-io/thanos v0.11.0/go.mod h1:N/Yes7J68KqvmY+xM6J5CJqEvWIvKSR5sqGtmuD6wDc=
-github.com/tidwall/pretty v0.0.0-20180105212114-65a9db5fad51/go.mod h1:XNkn88O1ChpSDQmQeStsy+sBenx6DDtFZJxhVysOjyk=
-github.com/tidwall/pretty v1.0.0/go.mod h1:XNkn88O1ChpSDQmQeStsy+sBenx6DDtFZJxhVysOjyk=
-github.com/tmc/grpc-websocket-proxy v0.0.0-20170815181823-89b8d40f7ca8/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U=
+github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
+github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY=
+github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
+github.com/subosito/gotenv v1.2.0/go.mod h1:N0PQaV/YGNqwC0u51sEeR/aUtSLEXKX9iv69rRypqCw=
 github.com/tmc/grpc-websocket-proxy v0.0.0-20190109142713-0ad062ec5ee5/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U=
-github.com/tv42/httpunix v0.0.0-20150427012821-b75d8614f926/go.mod h1:9ESjWnEqriFuLhtthL60Sar/7RFoluCcXsuvEwTV5KM=
-github.com/uber/jaeger-client-go v2.20.1+incompatible/go.mod h1:WVhlPFC8FDjOFMMWRy2pZqQJSXxYSwNYOkTr/Z6d3Kk=
-github.com/uber/jaeger-lib v2.2.0+incompatible/go.mod h1:ComeNDZlWwrWnDv8aPp0Ba6+uUTzImX/AauajbLI56U=
-github.com/ugorji/go v1.1.4/go.mod h1:uQMGLiO92mf5W77hV/PUCpI3pbzQx3CRekS0kk+RGrc=
-github.com/ugorji/go/codec v0.0.0-20181204163529-d75b2dcb6bc8/go.mod h1:VFNgLljTbGfSG7qAOspJ7OScBnGdDN/yBr0sguwnwf0=
-github.com/urfave/cli v0.0.0-20171014202726-7bc6a0acffa5/go.mod h1:70zkFmudgCuE/ngEzBv17Jvp/497gISqfk5gWijbERA=
-github.com/urfave/cli v1.20.0/go.mod h1:70zkFmudgCuE/ngEzBv17Jvp/497gISqfk5gWijbERA=
-github.com/vektah/gqlparser v1.1.2/go.mod h1:1ycwN7Ij5njmMkPPAOaRFY4rET2Enx7IkVv3vaXspKw=
-github.com/xanzy/go-gitlab v0.15.0/go.mod h1:8zdQa/ri1dfn8eS3Ir1SyfvOKlw7WBJ8DVThkpGiXrs=
-github.com/xdg/scram v0.0.0-20180814205039-7eeb5667e42c/go.mod h1:lB8K/P019DLNhemzwFU4jHLhdvlE6uDZjXFejJXr49I=
-github.com/xdg/stringprep v1.0.0/go.mod h1:Jhud4/sHMO4oL310DaZAKk9ZaJ08SJfe+sJh0HrGL1Y=
-github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f/go.mod h1:N2zxlSyiKSe5eX1tZViRH5QA0qijqEDrYZiPEAiq3wU=
-github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415/go.mod h1:GwrjFmJcFw6At/Gs6z4yjiIwzuJ1/+UwLxMQDVQXShQ=
-github.com/xeipuuv/gojsonschema v0.0.0-20180618132009-1d523034197f/go.mod h1:5yf86TLmAcydyeJq5YvxkGPE2fm/u4myDekKRoLuqhs=
-github.com/xeipuuv/gojsonschema v1.1.0/go.mod h1:5yf86TLmAcydyeJq5YvxkGPE2fm/u4myDekKRoLuqhs=
-github.com/xiang90/probing v0.0.0-20160813154853-07dd2e8dfe18/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU=
+github.com/tmc/grpc-websocket-proxy v0.0.0-20201229170055-e5319fda7802/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U=
+github.com/xanzy/go-gitlab v0.54.3/go.mod h1:F0QEXwmqiBUxCgJm8fE9S+1veX4XC9Z4cfaAbqwk4YM=
+github.com/xanzy/ssh-agent v0.3.0/go.mod h1:3s9xbODqPuuhK9JV1R321M/FlMZSBvE5aY6eAcqrDh0=
 github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU=
-github.com/xlab/handysort v0.0.0-20150421192137-fb3537ed64a1/go.mod h1:QcJo0QPSfTONNIgpN5RA8prR7fF8nkF6cTWTcNerRO8=
-github.com/xlab/treeprint v0.0.0-20180616005107-d6fb6747feb6/go.mod h1:ce1O1j6UtZfjr22oyGxGLbauSBp2YVXpARAosm7dHBg=
-github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77/go.mod h1:aYKd//L2LvnjZzWKhF00oedf4jCCReLcmhLdhm1A27Q=
+github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
 github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
-github.com/yvasiyarov/go-metrics v0.0.0-20140926110328-57bccd1ccd43/go.mod h1:aX5oPXxHm3bOH+xeAttToC8pqch2ScQN/JoXYupl6xs=
-github.com/yvasiyarov/gorelic v0.0.0-20141212073537-a9bba5b9ab50/go.mod h1:NUSPSUX/bi6SeDMUh6brw0nXpxHnc96TguQh0+r/ssA=
-github.com/yvasiyarov/newrelic_platform_go v0.0.0-20140908184405-b21fdbd4370f/go.mod h1:GlGEuHIJweS1mbCqG+7vt2nvWLzLLnRHbXz5JKd/Qbg=
-github.com/ziutek/mymysql v1.5.4/go.mod h1:LMSpPZ6DbqWFxNCHW77HeMg9I646SAhApZ/wKdgO/C0=
-gitlab.com/nyarla/go-crypt v0.0.0-20160106005555-d9a5dc2b789b/go.mod h1:T3BPAOm2cqquPa0MKWeNkmOM5RQsRhkrwMWonFMN7fE=
-go.elastic.co/apm v1.5.0/go.mod h1:OdB9sPtM6Vt7oz3VXt7+KR96i9li74qrxBGHTQygFvk=
-go.elastic.co/apm/module/apmhttp v1.5.0/go.mod h1:1FbmNuyD3ddauwzgVwFB0fqY6KbZt3JkV187tGCYYhY=
-go.elastic.co/apm/module/apmot v1.5.0/go.mod h1:d2KYwhJParTpyw2WnTNy8geNlHKKFX+4oK3YLlsesWE=
-go.elastic.co/fastjson v1.0.0/go.mod h1:PmeUOMMtLHQr9ZS9J9owrAVg0FkaZDRZJEFTTGHtchs=
+github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
+github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
+github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k=
+github.com/yuin/goldmark v1.4.0/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k=
 go.etcd.io/bbolt v1.3.2/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU=
-go.etcd.io/bbolt v1.3.3/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU=
-go.etcd.io/bbolt v1.3.4/go.mod h1:G5EMThwa9y8QZGBClrRx5EY+Yw9kAhnjy3bSjsnlVTQ=
-go.etcd.io/etcd v0.0.0-20191023171146-3cf2f69b5738/go.mod h1:dnLIgRNXwCJa5e+c6mIZCrds/GIG4ncV9HhK5PX7jPg=
-go.mongodb.org/mongo-driver v1.0.3/go.mod h1:u7ryQJ+DOzQmeO7zB6MHyr8jkEQvC8vH7qLUO4lqsUM=
-go.mongodb.org/mongo-driver v1.1.0/go.mod h1:u7ryQJ+DOzQmeO7zB6MHyr8jkEQvC8vH7qLUO4lqsUM=
-go.mongodb.org/mongo-driver v1.1.1/go.mod h1:u7ryQJ+DOzQmeO7zB6MHyr8jkEQvC8vH7qLUO4lqsUM=
-go.mongodb.org/mongo-driver v1.1.2/go.mod h1:u7ryQJ+DOzQmeO7zB6MHyr8jkEQvC8vH7qLUO4lqsUM=
-go.opencensus.io v0.20.1/go.mod h1:6WKK9ahsWS3RSO+PY9ZHZUfv2irvY6gN279GOPZjmmk=
-go.opencensus.io v0.20.2/go.mod h1:6WKK9ahsWS3RSO+PY9ZHZUfv2irvY6gN279GOPZjmmk=
+go.etcd.io/bbolt v1.3.6/go.mod h1:qXsaaIqmgQH0T+OPdb99Bf+PKfBBQVAdyD6TY9G8XM4=
+go.etcd.io/etcd/api/v3 v3.5.0/go.mod h1:cbVKeC6lCfl7j/8jBhAK6aIYO9XOjdptoxU/nLQcPvs=
+go.etcd.io/etcd/client/pkg/v3 v3.5.0/go.mod h1:IJHfcCEKxYu1Os13ZdwCwIUTUVGYTSAM3YSwc9/Ac1g=
+go.etcd.io/etcd/client/v2 v2.305.0/go.mod h1:h9puh54ZTgAKtEbut2oe9P4L/oqKCVB6xsXlzd7alYQ=
+go.etcd.io/etcd/client/v3 v3.5.0/go.mod h1:AIKXXVX/DQXtfTEqBryiLTUXwON+GuvO6Z7lLS/oTh0=
+go.etcd.io/etcd/pkg/v3 v3.5.0/go.mod h1:UzJGatBQ1lXChBkQF0AuAtkRQMYnHubxAEYIrC3MSsE=
+go.etcd.io/etcd/raft/v3 v3.5.0/go.mod h1:UFOHSIvO/nKwd4lhkwabrTD3cqW5yVyYYf/KlD00Szc=
+go.etcd.io/etcd/server/v3 v3.5.0/go.mod h1:3Ah5ruV+M+7RZr0+Y/5mNLwC+eQlni+mQmOVdCRJoS4=
 go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU=
 go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8=
 go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
-go.uber.org/atomic v0.0.0-20181018215023-8dc6146f7569/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE=
-go.uber.org/atomic v1.3.2/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE=
+go.opencensus.io v0.22.3/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
+go.opencensus.io v0.22.4/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
+go.opencensus.io v0.22.5/go.mod h1:5pWMHQbX5EPX2/62yrJeAkowc+lfs/XD7Uxpq3pI6kk=
+go.opencensus.io v0.23.0/go.mod h1:XItmlyltB5F7CS4xOC1DcqMoFqwtC6OG2xF7mCv7P7E=
+go.opentelemetry.io/contrib v0.20.0/go.mod h1:G/EtFaa6qaN7+LxqfIAT3GiZa7Wv5DTBUzl5H4LY0Kc=
+go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.20.0/go.mod h1:oVGt1LRbBOBq1A5BQLlUg9UaU/54aiHw8cgjV3aWZ/E=
+go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.20.0/go.mod h1:2AboqHi0CiIZU0qwhtUfCYD1GeUzvvIXWNkhDt7ZMG4=
+go.opentelemetry.io/otel v0.20.0/go.mod h1:Y3ugLH2oa81t5QO+Lty+zXf8zC9L26ax4Nzoxm/dooo=
+go.opentelemetry.io/otel/exporters/otlp v0.20.0/go.mod h1:YIieizyaN77rtLJra0buKiNBOm9XQfkPEKBeuhoMwAM=
+go.opentelemetry.io/otel/metric v0.20.0/go.mod h1:598I5tYlH1vzBjn+BTuhzTCSb/9debfNp6R3s7Pr1eU=
+go.opentelemetry.io/otel/oteltest v0.20.0/go.mod h1:L7bgKf9ZB7qCwT9Up7i9/pn0PWIa9FqQ2IQ8LoxiGnw=
+go.opentelemetry.io/otel/sdk v0.20.0/go.mod h1:g/IcepuwNsoiX5Byy2nNV0ySUF1em498m7hBWC279Yc=
+go.opentelemetry.io/otel/sdk/export/metric v0.20.0/go.mod h1:h7RBNMsDJ5pmI1zExLi+bJK+Dr8NQCh0qGhm1KDnNlE=
+go.opentelemetry.io/otel/sdk/metric v0.20.0/go.mod h1:knxiS8Xd4E/N+ZqKmUPf3gTTZ4/0TjTXukfxjzSTpHE=
+go.opentelemetry.io/otel/trace v0.20.0/go.mod h1:6GjCW8zgDjwGHGa6GkyeB8+/5vjT16gUEi0Nf1iBdgw=
+go.opentelemetry.io/proto/otlp v0.7.0/go.mod h1:PqfVotwruBrMGOCsRd/89rSnXhoiJIqeYNgFYFoEGnI=
 go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE=
-go.uber.org/atomic v1.5.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ=
-go.uber.org/atomic v1.6.0 h1:Ezj3JGmsOnG1MoRWQkPBsKLe9DwWD9QeXzTRzzldNVk=
-go.uber.org/atomic v1.6.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ=
-go.uber.org/automaxprocs v1.2.0/go.mod h1:YfO3fm683kQpzETxlTGZhGIVmXAhaw3gxeBADbpZtnU=
-go.uber.org/multierr v0.0.0-20180122172545-ddea229ff1df/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0=
+go.uber.org/atomic v1.7.0 h1:ADUqmZGgLDDfbSL9ZmPxKTybcoEYHgpYfELNoN+7hsw=
+go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc=
+go.uber.org/goleak v1.1.10/go.mod h1:8a7PlsEVH3e/a/GLqe5IIrQx6GzcnRmZEufDUTk4A7A=
+go.uber.org/goleak v1.1.11-0.20210813005559-691160354723/go.mod h1:cwTWslyiVhfpKIDGSZEM2HlOvcqm+tG4zioyIeLoqMQ=
+go.uber.org/goleak v1.1.12 h1:gZAh5/EyT/HQwlpkCy6wTpqfH9H8Lz8zbm3dZh+OyzA=
+go.uber.org/goleak v1.1.12/go.mod h1:cwTWslyiVhfpKIDGSZEM2HlOvcqm+tG4zioyIeLoqMQ=
 go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0=
-go.uber.org/multierr v1.5.0 h1:KCa4XfM8CWFCpxXRGok+Q0SS/0XBhMDbHHGABQLvD2A=
-go.uber.org/multierr v1.5.0/go.mod h1:FeouvMocqHpRaaGuG9EjoKcStLC43Zu/fmqdUMPcKYU=
-go.uber.org/tools v0.0.0-20190618225709-2cfd321de3ee h1:0mgffUl7nfd+FpvXMVz4IDEaUSmT1ysygQC7qYo7sG4=
-go.uber.org/tools v0.0.0-20190618225709-2cfd321de3ee/go.mod h1:vJERXedbb3MVM5f9Ejo0C68/HhF8uaILCdgjnY+goOA=
-go.uber.org/zap v0.0.0-20180814183419-67bc79d13d15/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q=
-go.uber.org/zap v1.8.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q=
+go.uber.org/multierr v1.6.0 h1:y6IPFStTAIT5Ytl7/XYmHvzXQ7S3g/IeZW9hyZ5thw4=
+go.uber.org/multierr v1.6.0/go.mod h1:cdWPpRnG4AhwMwsgIHip0KRBQjJy5kYEpYjJxpXp9iU=
 go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q=
-go.uber.org/zap v1.14.1 h1:nYDKopTbvAPq/NrUVZwT15y2lpROBiLLyoRTbXOYWOo=
-go.uber.org/zap v1.14.1/go.mod h1:Mb2vm2krFEG5DV0W9qcHBYFtp/Wku1cvYaqPsS/WYfc=
-golang.org/x/crypto v0.0.0-20171113213409-9f005a07e0d3/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
-golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
+go.uber.org/zap v1.17.0/go.mod h1:MXVU+bhUf/A7Xi2HNOnopQOrmycQ5Ih87HtOu4q5SSo=
+go.uber.org/zap v1.19.0/go.mod h1:xg/QME4nWcxGxrpdeYfq7UvYrLh66cuVKdrbD1XF/NI=
+go.uber.org/zap v1.19.1 h1:ue41HOKd1vGURxrmeKIgELGb3jPW9DMUDGtsinblHwI=
+go.uber.org/zap v1.19.1/go.mod h1:j3DNczoxDZroyBnOT1L/Q79cfUMGZxlv/9dzN7SM1rI=
 golang.org/x/crypto v0.0.0-20181029021203-45a5f77698d3/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
-golang.org/x/crypto v0.0.0-20181203042331-505ab145d0a9/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
-golang.org/x/crypto v0.0.0-20190211182817-74369b46fc67/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
+golang.org/x/crypto v0.0.0-20190219172222-a4c6cb3142f2/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
 golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
-golang.org/x/crypto v0.0.0-20190320223903-b7391e95e576/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
-golang.org/x/crypto v0.0.0-20190325154230-a5d413f7728c/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
-golang.org/x/crypto v0.0.0-20190426145343-a29dc8fdc734/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
 golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
-golang.org/x/crypto v0.0.0-20190513172903-22d7a77e9e5f/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
 golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
-golang.org/x/crypto v0.0.0-20190611184440-5c40567a22f8/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
-golang.org/x/crypto v0.0.0-20190617133340-57b3e21c3d56/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
-golang.org/x/crypto v0.0.0-20190621222207-cc06ce4a13d4/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
 golang.org/x/crypto v0.0.0-20190820162420-60c769a6c586/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
-golang.org/x/crypto v0.0.0-20190923035154-9ee001bba392/go.mod h1:/lpIB1dKB+9EgE3H3cr1v9wB50oz8l4C4h62xy7jSTY=
 golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
-golang.org/x/crypto v0.0.0-20191112222119-e1110fd1c708/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
-golang.org/x/crypto v0.0.0-20191206172530-e9b2fee46413/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
-golang.org/x/crypto v0.0.0-20200128174031-69ecbb4d6d5d/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
-golang.org/x/crypto v0.0.0-20200220183623-bac4c82f6975/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
-golang.org/x/crypto v0.0.0-20200414173820-0848c9571904/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
-golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9 h1:psW17arqaxU48Z5kZ0CQnkZWQJsqcURM6tKiBApRjXI=
 golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
+golang.org/x/crypto v0.0.0-20201002170205-7f63de1d35b0/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
+golang.org/x/crypto v0.0.0-20210322153248-0c34fe9e7dc2/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4=
+golang.org/x/crypto v0.0.0-20210421170649-83a5a9bb288b/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4=
+golang.org/x/crypto v0.0.0-20210817164053-32db794688a5/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
+golang.org/x/crypto v0.0.0-20211215153901-e495a2d5b3d3 h1:0es+/5331RGQPcXlMfP+WrnIIS6dNnNRe0WB02W0F4M=
+golang.org/x/crypto v0.0.0-20211215153901-e495a2d5b3d3/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
 golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
-golang.org/x/exp v0.0.0-20190125153040-c74c464bbbf2/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
 golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
-golang.org/x/exp v0.0.0-20190312203227-4b39c73a6495/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8=
 golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8=
 golang.org/x/exp v0.0.0-20190829153037-c13cbed26979/go.mod h1:86+5VVa7VpoJ4kLfm080zCjGlMRFzhUhsZKEZO7MGek=
 golang.org/x/exp v0.0.0-20191030013958-a1ab85dbe136/go.mod h1:JXzH8nQsPlswgeRAPE3MuO9GYsAcnJvJ4vnMwN/5qkY=
+golang.org/x/exp v0.0.0-20191129062945-2f5052295587/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4=
 golang.org/x/exp v0.0.0-20191227195350-da58074b4299/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4=
+golang.org/x/exp v0.0.0-20200119233911-0405dc783f0a/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4=
+golang.org/x/exp v0.0.0-20200207192155-f17229e696bd/go.mod h1:J/WKrq2StrnmMY6+EHIKF9dgMWnmCNThgcyBT1FY9mM=
+golang.org/x/exp v0.0.0-20200224162631-6cc2880d07d6/go.mod h1:3jZMyOhIsHpP37uCMkUooju7aAi5cS1Q23tOzKc+0MU=
 golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js=
 golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0=
 golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
@@ -901,195 +543,252 @@ golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHl
 golang.org/x/lint v0.0.0-20190409202823-959b441ac422/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
 golang.org/x/lint v0.0.0-20190909230951-414d861bb4ac/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
 golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
-golang.org/x/lint v0.0.0-20191125180803-fdd1cda4f05f h1:J5lckAjkw6qYlOZNj90mLYNTEKDvWeuc1yieZ8qUzUE=
 golang.org/x/lint v0.0.0-20191125180803-fdd1cda4f05f/go.mod h1:5qLYkcX4OjUUV8bRuDixDT3tpyyb+LUpUlRWLxfhWrs=
+golang.org/x/lint v0.0.0-20200130185559-910be7a94367/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY=
+golang.org/x/lint v0.0.0-20200302205851-738671d3881b/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY=
+golang.org/x/lint v0.0.0-20201208152925-83fdc39ff7b5/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY=
+golang.org/x/lint v0.0.0-20210508222113-6edffad5e616/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY=
 golang.org/x/mobile v0.0.0-20190312151609-d3739f865fa6/go.mod h1:z+o9i4GpDbdi3rU15maQ/Ox0txvL9dWGYEHz965HBQE=
 golang.org/x/mobile v0.0.0-20190719004257-d2bd2a29d028/go.mod h1:E/iHnbuqvinMTCcRqshq8CkpyQDoeVncDDYHnLhea+o=
 golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc=
 golang.org/x/mod v0.1.0/go.mod h1:0QHyrYULN0/3qlju5TqG8bIK38QM8yzMo5ekMj3DlcY=
 golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg=
-golang.org/x/mod v0.2.0 h1:KU7oHjnv3XNWfa5COkzUifxZmxp1TyI7ImMXqFxLwvQ=
+golang.org/x/mod v0.1.1-0.20191107180719-034126e5016b/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg=
 golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
-golang.org/x/net v0.0.0-20170114055629-f2499483f923/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
+golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
+golang.org/x/mod v0.4.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
+golang.org/x/mod v0.4.1/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
+golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
+golang.org/x/net v0.0.0-20180218175443-cbe0f9307d01/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
 golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
 golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
 golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
-golang.org/x/net v0.0.0-20181005035420-146acd28ed58/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
 golang.org/x/net v0.0.0-20181023162649-9b4f9f5ad519/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
-golang.org/x/net v0.0.0-20181108082009-03003ca0c849/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
-golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
 golang.org/x/net v0.0.0-20181201002055-351d144fa1fc/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
 golang.org/x/net v0.0.0-20181220203305-927f97764cc3/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
 golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
-golang.org/x/net v0.0.0-20190125091013-d26f9f9a57f3/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
 golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
 golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
-golang.org/x/net v0.0.0-20190320064053-1272bf9dcd53/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
 golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
-golang.org/x/net v0.0.0-20190424112056-4829fb13d2c6/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
 golang.org/x/net v0.0.0-20190501004415-9ce7a6920f09/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
 golang.org/x/net v0.0.0-20190503192946-f4e77d36d62c/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
-golang.org/x/net v0.0.0-20190522155817-f3200d17e092/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks=
 golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks=
-golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
-golang.org/x/net v0.0.0-20190619014844-b5b0513f8c1b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
 golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
 golang.org/x/net v0.0.0-20190628185345-da137c7871d7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
 golang.org/x/net v0.0.0-20190724013045-ca1201d0de80/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
-golang.org/x/net v0.0.0-20190812203447-cdfb69ac37fc/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
-golang.org/x/net v0.0.0-20190813141303-74dc4d7220e7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
 golang.org/x/net v0.0.0-20190827160401-ba9fcec4b297/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
-golang.org/x/net v0.0.0-20190923162816-aa69164e4478/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
-golang.org/x/net v0.0.0-20191002035440-2ec189313ef0/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
-golang.org/x/net v0.0.0-20191004110552-13f9640d40b9/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
-golang.org/x/net v0.0.0-20191028085509-fe3aa8a45271/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
-golang.org/x/net v0.0.0-20191112182307-2180aed22343/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
 golang.org/x/net v0.0.0-20191209160850-c0dbc17a3553/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
+golang.org/x/net v0.0.0-20200114155413-6afb5195e5aa/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
+golang.org/x/net v0.0.0-20200202094626-16171245cfb2/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
+golang.org/x/net v0.0.0-20200222125558-5a598a2470a0/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
 golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
 golang.org/x/net v0.0.0-20200301022130-244492dfa37a/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
 golang.org/x/net v0.0.0-20200324143707-d3edc9973b7e/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
+golang.org/x/net v0.0.0-20200501053045-e0ff5e5a1de5/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
+golang.org/x/net v0.0.0-20200506145744-7e3656a0809f/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
+golang.org/x/net v0.0.0-20200513185701-a91f0712d120/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
 golang.org/x/net v0.0.0-20200520004742-59133d7f0dd7/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
-golang.org/x/net v0.0.0-20200707034311-ab3426394381 h1:VXak5I6aEWmAXeQjA+QSZzlgNrpq9mjcfDemuexIKsU=
+golang.org/x/net v0.0.0-20200520182314-0ba52f642ac2/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
+golang.org/x/net v0.0.0-20200625001655-4c5254603344/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
 golang.org/x/net v0.0.0-20200707034311-ab3426394381/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
+golang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
+golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
+golang.org/x/net v0.0.0-20201031054903-ff519b6c9102/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
+golang.org/x/net v0.0.0-20201110031124-69a78807bb2b/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
+golang.org/x/net v0.0.0-20201202161906-c7110b5ffcbb/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
+golang.org/x/net v0.0.0-20201209123823-ac852fbbde11/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
+golang.org/x/net v0.0.0-20210119194325-5f4716e94777/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
+golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
+golang.org/x/net v0.0.0-20210316092652-d523dce5a7f4/go.mod h1:RBQZq4jEuRlivfhVLdyRGr576XBO4/greRjx4P4O3yc=
+golang.org/x/net v0.0.0-20210326060303-6b1517762897/go.mod h1:uSPa2vr4CLtc/ILN5odXGNXS6mhrKVzTaCXzk9m6W3k=
+golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM=
+golang.org/x/net v0.0.0-20210428140749-89ef3d95e781/go.mod h1:OJAsFXCWl8Ukc7SiCT/9KSuxbyM7479/AVlXFRxuMCk=
+golang.org/x/net v0.0.0-20210525063256-abc453219eb5/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
+golang.org/x/net v0.0.0-20210805182204-aaa1db679c0d/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
+golang.org/x/net v0.0.0-20210825183410-e898025ed96a/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
+golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
+golang.org/x/net v0.0.0-20211209124913-491a49abca63 h1:iocB37TsdFuN6IBRZ+ry36wrkoV51/tl5vOWqkcPGvY=
+golang.org/x/net v0.0.0-20211209124913-491a49abca63/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
+golang.org/x/oauth2 v0.0.0-20180227000427-d7d64896b5ff/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
 golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
 golang.org/x/oauth2 v0.0.0-20181106182150-f42d05182288/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
 golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
-golang.org/x/oauth2 v0.0.0-20190402181905-9f3314589c9a/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
 golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
-golang.org/x/oauth2 v0.0.0-20191202225959-858c2ad4c8b6 h1:pE8b58s1HRDMi8RDc79m0HISf9D4TzseP40cEA6IGfs=
 golang.org/x/oauth2 v0.0.0-20191202225959-858c2ad4c8b6/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
+golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
+golang.org/x/oauth2 v0.0.0-20200902213428-5d25da1a8d43/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
+golang.org/x/oauth2 v0.0.0-20201109201403-9fd604954f58/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
+golang.org/x/oauth2 v0.0.0-20201208152858-08078c50e5b5/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
+golang.org/x/oauth2 v0.0.0-20210218202405-ba52d332ba99/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
+golang.org/x/oauth2 v0.0.0-20210220000619-9bb904979d93/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
+golang.org/x/oauth2 v0.0.0-20210313182246-cd4f82c27b84/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
+golang.org/x/oauth2 v0.0.0-20210402161424-2e8d93401602/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
+golang.org/x/oauth2 v0.0.0-20210514164344-f6687ab2804c/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
+golang.org/x/oauth2 v0.0.0-20210819190943-2bc19b11175f h1:Qmd2pbz05z7z6lm0DrgQVVPuBm92jqujBKMHMOlOQEw=
+golang.org/x/oauth2 v0.0.0-20210819190943-2bc19b11175f/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
 golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
 golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
 golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
 golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
 golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
 golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
-golang.org/x/sys v0.0.0-20170830134202-bb24a47a89ea/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
+golang.org/x/sync v0.0.0-20200317015054-43a5402ce75a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
+golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
+golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
+golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
+golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
+golang.org/x/sys v0.0.0-20180224232135-f6cff0780e54/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
 golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
 golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
 golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
 golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
 golang.org/x/sys v0.0.0-20181026203630-95b1ffbd15a5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
 golang.org/x/sys v0.0.0-20181107165924-66b7b1311ac8/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
-golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
-golang.org/x/sys v0.0.0-20181122145206-62eef0e2fa9b/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
-golang.org/x/sys v0.0.0-20181205085412-a5c9d58dba9a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
-golang.org/x/sys v0.0.0-20190102155601-82a175fd1598/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
-golang.org/x/sys v0.0.0-20190209173611-3b5209105503/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
 golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
-golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
-golang.org/x/sys v0.0.0-20190310054646-10058d7d4faa/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/sys v0.0.0-20190321052220-f7bb7a8bee54/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/sys v0.0.0-20190425145619-16072639606e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/sys v0.0.0-20190426135247-a129542de9ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 golang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/sys v0.0.0-20190514135907-3a4b5fb9f71f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/sys v0.0.0-20190515120540-06a5c4944438/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/sys v0.0.0-20190602015325-4c4f7f33c9ed/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/sys v0.0.0-20190616124812-15dcb6c0061f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/sys v0.0.0-20190626221950-04f50cda93cb/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/sys v0.0.0-20190712062909-fae7ac547cb7/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 golang.org/x/sys v0.0.0-20190726091711-fc99dfbffb4e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/sys v0.0.0-20190801041406-cbf593c0f2f3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/sys v0.0.0-20190813064441-fde4db37ae7a/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/sys v0.0.0-20190826190057-c7b8b68b1456/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 golang.org/x/sys v0.0.0-20190904154756-749cb33beabd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 golang.org/x/sys v0.0.0-20190916202348-b4ddaad3f8a3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/sys v0.0.0-20190922100055-0a153f010e69/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/sys v0.0.0-20190924154521-2837fb4f24fe/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20191001151750-bb3f8db39f24/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/sys v0.0.0-20191010194322-b09406accb47/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/sys v0.0.0-20191022100944-742c48ecaeb7/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/sys v0.0.0-20191025021431-6c3a3bfe00ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/sys v0.0.0-20191112214154-59a1497f0cea/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/sys v0.0.0-20191113165036-4c7a9d0fe056/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 golang.org/x/sys v0.0.0-20191120155948-bd437916bb0e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 golang.org/x/sys v0.0.0-20191228213918-04cbcbbfeed8/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/sys v0.0.0-20200106162015-b016eb3dc98e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/sys v0.0.0-20200120151820-655fe14d7479/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20200113162924-86b910548bc1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 golang.org/x/sys v0.0.0-20200122134326-e047566fdf82/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 golang.org/x/sys v0.0.0-20200202164722-d101bd2416d5/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20200212091648-12a6c2dcc1e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20200302150141-5c8b2ff67527/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/sys v0.0.0-20200622214017-ed371f2e16b4 h1:5/PjkGUjvEU5Gl6BxmvKRPpqo2uNMv4rcHBMwzk/st8=
-golang.org/x/sys v0.0.0-20200622214017-ed371f2e16b4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/text v0.0.0-20160726164857-2910a502d2bf/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
+golang.org/x/sys v0.0.0-20200331124033-c3d80250170d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20200501052902-10377860bb8e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20200511232937-7e40ca221e25/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20200515095857-1151b9dac4a9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20200519105757-fe76b779f299/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20200523222454-059865788121/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20200625212154-ddb9806d33ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20200803210538-64077c9b5642/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20200831180312-196b9ba8737a/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20200905004654-be1d3432aa8f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20200923182605-d9f96fdee20d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20201201145000-ef89a241ccb3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20210104204734-6f8348627aad/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20210112080510-489259a85091/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20210119212857-b64e53b001e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20210220050731-9a76102bfb43/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20210305230114-8fe3ee5dd75b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20210315160823-c6e025ad8005/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20210320140829-1e4c9ba3b0c4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20210324051608-47abb6519492/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20210403161142-5e06dd20ab57/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20210502180810-71e4cd670f79/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.0.0-20210603081109-ebe580a85c40/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.0.0-20210616094352-59db8d763f22/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.0.0-20210809222454-d867a43fc93e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.0.0-20210831042530-f4d43177bf5e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.0.0-20211029165221-6e7872819dc8 h1:M69LAlWZCshgp0QSzyDcSsSIejIEeuaCVpmwcKwyLMk=
+golang.org/x/sys v0.0.0-20211029165221-6e7872819dc8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
+golang.org/x/term v0.0.0-20210615171337-6886f2dfbf5b h1:9zKuko04nR4gjZ4+DNjHqRlAJqbJETHwiNKDqTfOjfE=
+golang.org/x/term v0.0.0-20210615171337-6886f2dfbf5b/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
+golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
 golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
-golang.org/x/text v0.3.1-0.20180805044716-cb6730876b98/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
 golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
 golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
-golang.org/x/text v0.3.3 h1:cokOdA+Jmi5PJGXLlLllQSgYigAEfHXJAERHVMaCc2k=
 golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
-golang.org/x/time v0.0.0-20180412165947-fbb02b2291d2/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
+golang.org/x/text v0.3.4/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
+golang.org/x/text v0.3.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
+golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
+golang.org/x/text v0.3.7 h1:olpwvP2KacW1ZWvsR7uQhoyTYvKAupfQrRGBFM352Gk=
+golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
 golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
 golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
-golang.org/x/time v0.0.0-20191024005414-555d28b269f0 h1:/5xXl8Y5W96D+TtHSlonuFqGHIWVuyCkGJLwGh9JJFs=
 golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
+golang.org/x/time v0.0.0-20210220033141-f8bda1e9f3ba/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
+golang.org/x/time v0.0.0-20210723032227-1f47c861a9ac h1:7zkz7BUtwNFFqcowJ+RIgu2MaV/MapERkDIy+mwPyjs=
+golang.org/x/time v0.0.0-20210723032227-1f47c861a9ac/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
 golang.org/x/tools v0.0.0-20180221164845-07fd8470d635/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
-golang.org/x/tools v0.0.0-20180828015842-6cd1fcedba52/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
 golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
-golang.org/x/tools v0.0.0-20181011042414-1f849cf54d09/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
 golang.org/x/tools v0.0.0-20181030221726-6c7e314b6563/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
 golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
-golang.org/x/tools v0.0.0-20190118193359-16909d206f00/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
-golang.org/x/tools v0.0.0-20190125232054-d66bd3c5d5a6/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
-golang.org/x/tools v0.0.0-20190206041539-40960b6deb8e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
 golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY=
 golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
 golang.org/x/tools v0.0.0-20190312151545-0bb0c0a6e846/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
 golang.org/x/tools v0.0.0-20190312170243-e65039ee4138/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
 golang.org/x/tools v0.0.0-20190328211700-ab21143f2384/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
 golang.org/x/tools v0.0.0-20190425150028-36563e24a262/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
-golang.org/x/tools v0.0.0-20190425222832-ad9eeb80039a/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
 golang.org/x/tools v0.0.0-20190506145303-2d16b83fe98c/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
 golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
 golang.org/x/tools v0.0.0-20190606124116-d0a3d012864b/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
-golang.org/x/tools v0.0.0-20190614205625-5aca471b1d59/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
-golang.org/x/tools v0.0.0-20190617190820-da514acc4774/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
 golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
 golang.org/x/tools v0.0.0-20190624222133-a101b041ded4/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
 golang.org/x/tools v0.0.0-20190628153133-6cdbf07be9d0/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
-golang.org/x/tools v0.0.0-20190706070813-72ffa07ba3db/go.mod h1:jcCCGcm9btYwXyDqrUWc6MKQKKGJCWEQ3AfLSRIbEuI=
-golang.org/x/tools v0.0.0-20190813034749-528a2984e271/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
 golang.org/x/tools v0.0.0-20190816200558-6889da9d5479/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
-golang.org/x/tools v0.0.0-20190907020128-2ca718005c18/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
 golang.org/x/tools v0.0.0-20190911174233-4f2ddba30aff/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
-golang.org/x/tools v0.0.0-20190918214516-5a1a30219888/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
-golang.org/x/tools v0.0.0-20190920225731-5eefd052ad72/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
-golang.org/x/tools v0.0.0-20191004055002-72853e10c5a3/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
 golang.org/x/tools v0.0.0-20191012152004-8de300cfc20a/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
-golang.org/x/tools v0.0.0-20191029041327-9cc4af7d6b2c/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
-golang.org/x/tools v0.0.0-20191029190741-b9c20aec41a5/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
-golang.org/x/tools v0.0.0-20191030203535-5e247c9ad0a0/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
-golang.org/x/tools v0.0.0-20191111182352-50fa39b762bc/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
+golang.org/x/tools v0.0.0-20191108193012-7d206e10da11/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
+golang.org/x/tools v0.0.0-20191112195655-aa38f8e97acc/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
 golang.org/x/tools v0.0.0-20191113191852-77e3bb0ad9e7/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
 golang.org/x/tools v0.0.0-20191115202509-3a792d9c32b2/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
 golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
 golang.org/x/tools v0.0.0-20191125144606-a911d9008d1f/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
+golang.org/x/tools v0.0.0-20191130070609-6e064ea0cf2d/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
+golang.org/x/tools v0.0.0-20191216173652-a0e659d51361/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
 golang.org/x/tools v0.0.0-20191227053925-7b8e75db28f4/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
-golang.org/x/tools v0.0.0-20200403190813-44a64ad78b9b h1:AFZdJUT7jJYXQEC29hYH/WZkoV7+KhwxQGmdZ19yYoY=
-golang.org/x/tools v0.0.0-20200403190813-44a64ad78b9b/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
+golang.org/x/tools v0.0.0-20200117161641-43d50277825c/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
+golang.org/x/tools v0.0.0-20200122220014-bf1340f18c4a/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
+golang.org/x/tools v0.0.0-20200130002326-2f3ba24bd6e7/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
+golang.org/x/tools v0.0.0-20200204074204-1cc6d1ef6c74/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
+golang.org/x/tools v0.0.0-20200207183749-b753a1ba74fa/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
+golang.org/x/tools v0.0.0-20200212150539-ea181f53ac56/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
+golang.org/x/tools v0.0.0-20200224181240-023911ca70b2/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
+golang.org/x/tools v0.0.0-20200227222343-706bc42d1f0d/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
+golang.org/x/tools v0.0.0-20200304193943-95d2e580d8eb/go.mod h1:o4KQGtdN14AW+yjsvvwRTJJuXz8XRtIHtEnmAXLyFUw=
+golang.org/x/tools v0.0.0-20200312045724-11d5b4c81c7d/go.mod h1:o4KQGtdN14AW+yjsvvwRTJJuXz8XRtIHtEnmAXLyFUw=
+golang.org/x/tools v0.0.0-20200331025713-a30bf2db82d4/go.mod h1:Sl4aGygMT6LrqrWclx+PTx3U+LnKx/seiNR+3G19Ar8=
+golang.org/x/tools v0.0.0-20200501065659-ab2804fb9c9d/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
+golang.org/x/tools v0.0.0-20200505023115-26f46d2f7ef8/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
+golang.org/x/tools v0.0.0-20200512131952-2bc93b1c0c88/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
+golang.org/x/tools v0.0.0-20200515010526-7d3b6ebf133d/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
+golang.org/x/tools v0.0.0-20200618134242-20370b0cb4b2/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
+golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
+golang.org/x/tools v0.0.0-20200729194436-6467de6f59a7/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA=
+golang.org/x/tools v0.0.0-20200804011535-6c149bb5ef0d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA=
+golang.org/x/tools v0.0.0-20200825202427-b303f430e36d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA=
+golang.org/x/tools v0.0.0-20200904185747-39188db58858/go.mod h1:Cj7w3i3Rnn0Xh82ur9kSqwfTHTeVxaDqrfMjpcNT6bE=
+golang.org/x/tools v0.0.0-20201110124207-079ba7bd75cd/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
+golang.org/x/tools v0.0.0-20201201161351-ac6f37ff4c2a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
+golang.org/x/tools v0.0.0-20201208233053-a543418bbed2/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
+golang.org/x/tools v0.0.0-20201224043029-2b0845dc783e/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
+golang.org/x/tools v0.0.0-20210105154028-b0ab187a4818/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
+golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
+golang.org/x/tools v0.1.0/go.mod h1:xkSsbof2nBLbhDlRMhhhyNLN/zl3eTqcnHD5viDpcZ0=
+golang.org/x/tools v0.1.2/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
+golang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
+golang.org/x/tools v0.1.6-0.20210820212750-d4cc65f0b2ff/go.mod h1:YD9qOF0M9xpSpdWTBbzEl5e/RnCefISl8E5Noe10jFM=
 golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
 golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
-golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543 h1:E7g+9GITq07hpfrRu66IVDexMakfv52eLZ2CXBWiKr4=
 golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
-gomodules.xyz/jsonpatch/v2 v2.0.1 h1:xyiBuvkD2g5n7cYzx6u2sxQvsAy4QJsZFCzGVdzOXZ0=
-gomodules.xyz/jsonpatch/v2 v2.0.1/go.mod h1:IhYNNY4jnS53ZnfE4PAmpKtDpTCj1JFXc+3mwe7XcUU=
-gomodules.xyz/jsonpatch/v3 v3.0.1/go.mod h1:CBhndykehEwTOlEfnsfJwvkFQbSN8YZFr9M+cIHAJto=
-gomodules.xyz/orderedmap v0.1.0/go.mod h1:g9/TPUCm1t2gwD3j3zfV8uylyYhVdCNSi+xCEIu7yTU=
-gonum.org/v1/gonum v0.0.0-20190331200053-3d26580ed485/go.mod h1:2ltnJ7xHfj0zHS40VVPYEAAMTa3ZGguvHGBSJeRWqE0=
-gonum.org/v1/netlib v0.0.0-20190313105609-8cb42192e0e0/go.mod h1:wa6Ws7BG/ESfp6dHfk7C6KdzKA7wR7u/rKwOGE66zvw=
-gonum.org/v1/netlib v0.0.0-20190331212654-76723241ea4e/go.mod h1:kS+toOQn6AQKjmKJ7gzohV1XkqsFehRA2FbsbkopSuQ=
-google.golang.org/api v0.0.0-20160322025152-9bf6e6e569ff/go.mod h1:4mhQ8q/RsB7i+udVvVy5NUi08OU8ZlA0gRVgrF7VFY0=
-google.golang.org/api v0.3.1/go.mod h1:6wY9I6uQWHQ8EM57III9mq/AjF+i8G65rmVagqKMtkk=
-google.golang.org/api v0.3.2/go.mod h1:6wY9I6uQWHQ8EM57III9mq/AjF+i8G65rmVagqKMtkk=
+golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE=
+golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
+gomodules.xyz/jsonpatch/v2 v2.2.0 h1:4pT439QV83L+G9FkcCriY6EkpcK6r6bK+A5FBUMI7qY=
+gomodules.xyz/jsonpatch/v2 v2.2.0/go.mod h1:WXp+iVDkoLQqPudfQ9GBlwB2eZ5DKOnjQZCYdOS8GPY=
 google.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE=
 google.golang.org/api v0.7.0/go.mod h1:WtwebWUNSVBH/HAw79HIFXZNqEvBhG+Ra+ax0hx3E3M=
 google.golang.org/api v0.8.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg=
@@ -1097,45 +796,98 @@ google.golang.org/api v0.9.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEn
 google.golang.org/api v0.13.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI=
 google.golang.org/api v0.14.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI=
 google.golang.org/api v0.15.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI=
+google.golang.org/api v0.17.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE=
+google.golang.org/api v0.18.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE=
+google.golang.org/api v0.19.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE=
+google.golang.org/api v0.20.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE=
+google.golang.org/api v0.22.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE=
+google.golang.org/api v0.24.0/go.mod h1:lIXQywCXRcnZPGlsd8NbLnOjtAoL6em04bJ9+z0MncE=
+google.golang.org/api v0.28.0/go.mod h1:lIXQywCXRcnZPGlsd8NbLnOjtAoL6em04bJ9+z0MncE=
+google.golang.org/api v0.29.0/go.mod h1:Lcubydp8VUV7KeIHD9z2Bys/sm/vGKnG1UHuDBSrHWM=
+google.golang.org/api v0.30.0/go.mod h1:QGmEvQ87FHZNiUVJkT14jQNYJ4ZJjdRF23ZXz5138Fc=
+google.golang.org/api v0.35.0/go.mod h1:/XrVsuzM0rZmrsbjJutiuftIzeuTQcEeaYcSk/mQ1dg=
+google.golang.org/api v0.36.0/go.mod h1:+z5ficQTmoYpPn8LCUNVpK5I7hwkpjbcgqA7I34qYtE=
+google.golang.org/api v0.40.0/go.mod h1:fYKFpnQN0DsDSKRVRcQSDQNtqWPfM9i+zNPxepjRCQ8=
+google.golang.org/api v0.41.0/go.mod h1:RkxM5lITDfTzmyKFPt+wGrCJbVfniCr2ool8kTBzRTU=
+google.golang.org/api v0.43.0/go.mod h1:nQsDGjRXMo4lvh5hP0TKqF244gqhGcr/YSIykhUk/94=
+google.golang.org/api v0.44.0/go.mod h1:EBOGZqzyhtvMDoxwS97ctnh0zUmYY6CxqXsc1AvkYD8=
+google.golang.org/appengine v1.0.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM=
 google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM=
 google.golang.org/appengine v1.3.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
 google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
 google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
 google.golang.org/appengine v1.6.1/go.mod h1:i06prIuMbXzDqacNJfV5OdTW448YApPu5ww/cMBSeb0=
-google.golang.org/appengine v1.6.5 h1:tycE03LOZYQNhDpS27tcQdAzLCVMaj7QT2SXxebnpCM=
 google.golang.org/appengine v1.6.5/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc=
-google.golang.org/cloud v0.0.0-20151119220103-975617b05ea8/go.mod h1:0H1ncTHf11KCFhTc/+EFRbzSCOZx+VUbRMk55Yv5MYk=
+google.golang.org/appengine v1.6.6/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc=
+google.golang.org/appengine v1.6.7 h1:FZR1q0exgwxzPzp/aF+VccGrSfxfPpkBqjIIEq3ru6c=
+google.golang.org/appengine v1.6.7/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc=
 google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
 google.golang.org/genproto v0.0.0-20190307195333-5fe7a883aa19/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
-google.golang.org/genproto v0.0.0-20190404172233-64821d5d2107/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
 google.golang.org/genproto v0.0.0-20190418145605-e7d98fc518a7/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
 google.golang.org/genproto v0.0.0-20190425155659-357c62f0e4bb/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
 google.golang.org/genproto v0.0.0-20190502173448-54afdca5d873/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
-google.golang.org/genproto v0.0.0-20190530194941-fb225487d101/go.mod h1:z3L6/3dTEVtUr6QSP8miRzeRqwQOioJ9I66odjN4I7s=
-google.golang.org/genproto v0.0.0-20190716160619-c506a9f90610/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc=
 google.golang.org/genproto v0.0.0-20190801165951-fa694d86fc64/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc=
 google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc=
 google.golang.org/genproto v0.0.0-20190911173649-1774047e7e51/go.mod h1:IbNlFCBrqXvoKpeg0TB2l7cyZUmoaFKYIwrEpbDKLA8=
-google.golang.org/genproto v0.0.0-20190927181202-20e1ac93f88c/go.mod h1:IbNlFCBrqXvoKpeg0TB2l7cyZUmoaFKYIwrEpbDKLA8=
 google.golang.org/genproto v0.0.0-20191108220845-16a3f7862a1a/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
 google.golang.org/genproto v0.0.0-20191115194625-c23dd37a84c9/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
+google.golang.org/genproto v0.0.0-20191216164720-4f79533eabd1/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
 google.golang.org/genproto v0.0.0-20191230161307-f3c370f40bfb/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
-google.golang.org/genproto v0.0.0-20200117163144-32f20d992d24/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
+google.golang.org/genproto v0.0.0-20200115191322-ca5a22157cba/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
+google.golang.org/genproto v0.0.0-20200122232147-0452cf42e150/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
+google.golang.org/genproto v0.0.0-20200204135345-fa8e72b47b90/go.mod h1:GmwEX6Z4W5gMy59cAlVYjN9JhxgbQH6Gn+gFDQe2lzA=
+google.golang.org/genproto v0.0.0-20200212174721-66ed5ce911ce/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
+google.golang.org/genproto v0.0.0-20200224152610-e50cd9704f63/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
+google.golang.org/genproto v0.0.0-20200228133532-8c2c7df3a383/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
+google.golang.org/genproto v0.0.0-20200305110556-506484158171/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
+google.golang.org/genproto v0.0.0-20200312145019-da6875a35672/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
+google.golang.org/genproto v0.0.0-20200331122359-1ee6d9798940/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
+google.golang.org/genproto v0.0.0-20200423170343-7949de9c1215/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
+google.golang.org/genproto v0.0.0-20200430143042-b979b6f78d84/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
+google.golang.org/genproto v0.0.0-20200511104702-f5ebc3bea380/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
+google.golang.org/genproto v0.0.0-20200513103714-09dca8ec2884/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
+google.golang.org/genproto v0.0.0-20200515170657-fc4c6c6a6587/go.mod h1:YsZOwe1myG/8QRHRsmBRE1LrgQY60beZKjly0O1fX9U=
 google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo=
-google.golang.org/grpc v0.0.0-20160317175043-d3ddb4469d5a/go.mod h1:yo6s7OP7yaDglbqo1J04qKzAhqBH6lvTonzMVmEdcZw=
-google.golang.org/grpc v1.17.0/go.mod h1:6QZJwpn2B+Zp71q/5VxRsJ6NXXVCE5NRUHRo+f3cWCs=
+google.golang.org/genproto v0.0.0-20200618031413-b414f8b61790/go.mod h1:jDfRM7FcilCzHH/e9qn6dsT145K34l5v+OpcnNgKAAA=
+google.golang.org/genproto v0.0.0-20200729003335-053ba62fc06f/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
+google.golang.org/genproto v0.0.0-20200804131852-c06518451d9c/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
+google.golang.org/genproto v0.0.0-20200825200019-8632dd797987/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
+google.golang.org/genproto v0.0.0-20200904004341-0bd0a958aa1d/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
+google.golang.org/genproto v0.0.0-20201019141844-1ed22bb0c154/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
+google.golang.org/genproto v0.0.0-20201102152239-715cce707fb0/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
+google.golang.org/genproto v0.0.0-20201109203340-2640f1f9cdfb/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
+google.golang.org/genproto v0.0.0-20201201144952-b05cb90ed32e/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
+google.golang.org/genproto v0.0.0-20201210142538-e3217bee35cc/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
+google.golang.org/genproto v0.0.0-20201214200347-8c77b98c765d/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
+google.golang.org/genproto v0.0.0-20210222152913-aa3ee6e6a81c/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
+google.golang.org/genproto v0.0.0-20210303154014-9728d6b83eeb/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
+google.golang.org/genproto v0.0.0-20210310155132-4ce2db91004e/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
+google.golang.org/genproto v0.0.0-20210319143718-93e7006c17a6/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
+google.golang.org/genproto v0.0.0-20210402141018-6c239bbf2bb1/go.mod h1:9lPAdzaEmUacj36I+k7YKbEc5CXzPIeORRgDAUOu28A=
+google.golang.org/genproto v0.0.0-20210602131652-f16073e35f0c/go.mod h1:UODoCrxHCcBojKKwX1terBiRUaqAsFqJiF615XL43r0=
+google.golang.org/genproto v0.0.0-20210831024726-fe130286e0e2/go.mod h1:eFjDcFEctNawg4eG61bRv87N7iHBWyVhJu7u1kqDUXY=
 google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
 google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38=
-google.golang.org/grpc v1.21.0/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM=
 google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM=
-google.golang.org/grpc v1.22.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg=
-google.golang.org/grpc v1.22.1/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg=
 google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg=
-google.golang.org/grpc v1.23.1/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg=
-google.golang.org/grpc v1.24.0/go.mod h1:XDChyiUovWa60DnaeDeZmSW86xtLtjtZbwvSiRnRtcA=
 google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY=
 google.golang.org/grpc v1.26.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk=
 google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk=
+google.golang.org/grpc v1.27.1/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk=
+google.golang.org/grpc v1.28.0/go.mod h1:rpkK4SK4GF4Ach/+MFLZUBavHOvF2JJB5uozKKal+60=
+google.golang.org/grpc v1.29.1/go.mod h1:itym6AZVZYACWQqET3MqgPpjcuV5QH3BxFS3IjizoKk=
+google.golang.org/grpc v1.30.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak=
+google.golang.org/grpc v1.31.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak=
+google.golang.org/grpc v1.31.1/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak=
+google.golang.org/grpc v1.33.1/go.mod h1:fr5YgcSWrqhRRxogOsw7RzIpsmvOZ6IcH4kBYTpR3n0=
+google.golang.org/grpc v1.33.2/go.mod h1:JMHMWHQWaTccqQQlmk3MJZS+GWXOdAesneDmEnv2fbc=
+google.golang.org/grpc v1.34.0/go.mod h1:WotjhfgOW/POjDeRt8vscBtXq+2VjORFy659qA51WJ8=
+google.golang.org/grpc v1.35.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU=
+google.golang.org/grpc v1.36.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU=
+google.golang.org/grpc v1.36.1/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU=
+google.golang.org/grpc v1.37.0/go.mod h1:NREThFqKR1f3iQ6oBuvc5LadQuXVGo9rkm5ZGrQdJfM=
+google.golang.org/grpc v1.38.0/go.mod h1:NREThFqKR1f3iQ6oBuvc5LadQuXVGo9rkm5ZGrQdJfM=
+google.golang.org/grpc v1.40.0/go.mod h1:ogyxbiOoUXAkP+4+xa6PZSE9DZgIHtSpzjDTB9KAK34=
 google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8=
 google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0=
 google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM=
@@ -1144,140 +896,90 @@ google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzi
 google.golang.org/protobuf v1.22.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
 google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
 google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
-google.golang.org/protobuf v1.24.0 h1:UhZDfRO8JRQru4/+LlLE0BRKGF8L+PICnvYZmx/fEGA=
 google.golang.org/protobuf v1.24.0/go.mod h1:r/3tXBNzIEhYS9I1OUVjXDlt8tc493IdKGjtUeSXeh4=
-gopkg.in/airbrake/gobrake.v2 v2.0.9/go.mod h1:/h5ZAUhDkGaJfjzjKLSjv6zCL6O0LLBxU4K+aSYdM/U=
+google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c=
+google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw=
+google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
+google.golang.org/protobuf v1.27.1 h1:SnqbnDw1V7RiZcXPx5MEeqPv2s79L9i7BJUlG/+RurQ=
+google.golang.org/protobuf v1.27.1/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
 gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw=
 gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
-gopkg.in/check.v1 v1.0.0-20141024133853-64131543e789/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
 gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
-gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15 h1:YR8cESwS4TdDjEe65xsg0ogRM/Nc3DYOhEAlW+xobZo=
 gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
-gopkg.in/cheggaaa/pb.v1 v1.0.25/go.mod h1:V/YB90LKu/1FcN3WVnfiiE5oMCibMjukxqG/qStrOgw=
+gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
+gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
+gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=
 gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI=
 gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys=
-gopkg.in/fsnotify/fsnotify.v1 v1.4.7/go.mod h1:Fyux9zXlo4rWoMSIzpn9fDAYjalPqJ/K1qJ27s+7ltE=
-gopkg.in/gemnasium/logrus-airbrake-hook.v2 v2.1.2/go.mod h1:Xk6kEKp8OKb+X14hQBKWaSkCsqBpgog8nAV2xsGOxlo=
-gopkg.in/gorp.v1 v1.7.2/go.mod h1:Wo3h+DBQZIxATwftsglhdD/62zRFPhGhTiu5jUJmCaw=
-gopkg.in/imdario/mergo.v0 v0.3.7/go.mod h1:9qPP6AGrlC1G2PTNXko614FwGZvorN7MiBU0Eppok+U=
 gopkg.in/inf.v0 v0.9.1 h1:73M5CoZyi3ZLMOyDlQh031Cx6N9NDJ2Vvfl76EDAgDc=
 gopkg.in/inf.v0 v0.9.1/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw=
-gopkg.in/ini.v1 v1.42.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
 gopkg.in/ini.v1 v1.51.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
+gopkg.in/ini.v1 v1.62.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
 gopkg.in/natefinch/lumberjack.v2 v2.0.0/go.mod h1:l0ndWWf7gzL7RNwBG7wST/UCcT4T24xpD6X8LsfU/+k=
-gopkg.in/op/go-logging.v1 v1.0.0-20160211212156-b2cb9fa56473/go.mod h1:N1eN2tsCx0Ydtgjl4cqmbRCsY4/+z4cYDeqwZTk6zog=
 gopkg.in/resty.v1 v1.12.0/go.mod h1:mDo4pnntr5jdWRML875a/NmxYqAlA73dVijT2AXvQQo=
 gopkg.in/square/go-jose.v2 v2.2.2/go.mod h1:M9dMgbHiYLoDGQrXy7OpJDJWiKiU//h+vD76mk0e1AI=
 gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ=
 gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw=
+gopkg.in/warnings.v0 v0.1.2/go.mod h1:jksf8JmL6Qr/oQM2OXTHunEvvTAsrWBLb6OOjuVWRNI=
 gopkg.in/yaml.v2 v2.0.0-20170812160011-eb3733d160e7/go.mod h1:JAlM8MvJe8wmxCU4Bli9HhUf9+ttbYbLASfIpnQbh74=
-gopkg.in/yaml.v2 v2.1.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
 gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
 gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
 gopkg.in/yaml.v2 v2.2.3/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
 gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
-gopkg.in/yaml.v2 v2.2.5/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
 gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
-gopkg.in/yaml.v2 v2.3.0 h1:clyUAQHOM3G0M3f5vQj7LuJrETvjVot3Z5el9nffUtU=
 gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
-gopkg.in/yaml.v3 v3.0.0-20190905181640-827449938966/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
-gotest.tools v2.2.0+incompatible/go.mod h1:DsYFclhRJ6vuDpmuTbkuFWG+y2sxOXAzmJt81HFBacw=
+gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY=
+gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
+gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
+gopkg.in/yaml.v3 v3.0.0-20200615113413-eeeca48fe776/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
+gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b h1:h8qDotaEPuJATrMmW04NCwg7v22aHH28wwpauUhK9Oo=
+gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
 gotest.tools/v3 v3.0.2/go.mod h1:3SzNCllyD9/Y+b5r9JIKQ474KzkZyqLqEfYqMsX94Bk=
-helm.sh/helm/v3 v3.2.4/go.mod h1:ZaXz/vzktgwjyGGFbUWtIQkscfE7WYoRGP2szqAFHR0=
-honnef.co/go/tools v0.0.0-20180728063816-88497007e858/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
+gotest.tools/v3 v3.0.3/go.mod h1:Z7Lb0S5l+klDB31fvDQX8ss/FlKDxtlFlw3Oa8Ymbl8=
 honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
 honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
 honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
 honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
-honnef.co/go/tools v0.0.1-2019.2.3 h1:3JgtbtFHMiCmsznwGVTUWbgGov+pVqnlf1dEJTNAXeM=
 honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg=
-howett.net/plist v0.0.0-20181124034731-591f970eefbb/go.mod h1:vMygbs4qMhSZSc4lCUl2OEE+rDiIIJAIdR4m7MiMcm0=
-k8s.io/api v0.19.4 h1:I+1I4cgJYuCDgiLNjKx7SLmIbwgj9w7N7Zr5vSIdwpo=
-k8s.io/api v0.19.4/go.mod h1:SbtJ2aHCItirzdJ36YslycFNzWADYH3tgOhvBEFtZAk=
-k8s.io/apiextensions-apiserver v0.0.0-20190918161926-8f644eb6e783/go.mod h1:xvae1SZB3E17UpV59AWc271W/Ph25N+bjPyR63X6tPY=
-k8s.io/apiextensions-apiserver v0.18.0/go.mod h1:18Cwn1Xws4xnWQNC00FLq1E350b9lUF+aOdIWDOZxgo=
-k8s.io/apiextensions-apiserver v0.18.2/go.mod h1:q3faSnRGmYimiocj6cHQ1I3WpLqmDgJFlKL37fC4ZvY=
-k8s.io/apiextensions-apiserver v0.18.6 h1:vDlk7cyFsDyfwn2rNAO2DbmUbvXy5yT5GE3rrqOzaMo=
-k8s.io/apiextensions-apiserver v0.18.6/go.mod h1:lv89S7fUysXjLZO7ke783xOwVTm6lKizADfvUM/SS/M=
-k8s.io/apimachinery v0.19.4 h1:+ZoddM7nbzrDCp0T3SWnyxqf8cbWPT2fkZImoyvHUG0=
-k8s.io/apimachinery v0.19.4/go.mod h1:DnPGDnARWFvYa3pMHgSxtbZb7gpzzAZ1pTfaUNDVlmA=
-k8s.io/apiserver v0.0.0-20190918160949-bfa5e2e684ad/go.mod h1:XPCXEwhjaFN29a8NldXA901ElnKeKLrLtREO9ZhFyhg=
-k8s.io/apiserver v0.0.0-20191122221311-9d521947b1e1/go.mod h1:RbsZY5zzBIWnz4KbctZsTVjwIuOpTp4Z8oCgFHN4kZQ=
-k8s.io/apiserver v0.18.0/go.mod h1:3S2O6FeBBd6XTo0njUrLxiqk8GNy6wWOftjhJcXYnjw=
-k8s.io/apiserver v0.18.2/go.mod h1:Xbh066NqrZO8cbsoenCwyDJ1OSi8Ag8I2lezeHxzwzw=
-k8s.io/apiserver v0.18.6/go.mod h1:Zt2XvTHuaZjBz6EFYzpp+X4hTmgWGy8AthNVnTdm3Wg=
-k8s.io/autoscaler v0.0.0-20190607113959-1b4f1855cb8e/go.mod h1:QEXezc9uKPT91dwqhSJq3GNI3B1HxFRQHiku9kmrsSA=
-k8s.io/cli-runtime v0.18.0/go.mod h1:1eXfmBsIJosjn9LjEBUd2WVPoPAY9XGTqTFcPMIBsUQ=
-k8s.io/cli-runtime v0.18.2/go.mod h1:yfFR2sQQzDsV0VEKGZtrJwEy4hLZ2oj4ZIfodgxAHWQ=
-k8s.io/client-go v0.19.4 h1:85D3mDNoLF+xqpyE9Dh/OtrJDyJrSRKkHmDXIbEzer8=
-k8s.io/client-go v0.19.4/go.mod h1:ZrEy7+wj9PjH5VMBCuu/BDlvtUAku0oVFk4MmnW9mWA=
-k8s.io/code-generator v0.0.0-20190912054826-cd179ad6a269/go.mod h1:V5BD6M4CyaN5m+VthcclXWsVcT1Hu+glwa1bi3MIsyE=
-k8s.io/code-generator v0.18.0/go.mod h1:+UHX5rSbxmR8kzS+FAv7um6dtYrZokQvjHpDSYRVkTc=
-k8s.io/code-generator v0.18.2/go.mod h1:+UHX5rSbxmR8kzS+FAv7um6dtYrZokQvjHpDSYRVkTc=
-k8s.io/code-generator v0.18.6/go.mod h1:TgNEVx9hCyPGpdtCWA34olQYLkh3ok9ar7XfSsr8b6c=
-k8s.io/component-base v0.0.0-20190918160511-547f6c5d7090/go.mod h1:933PBGtQFJky3TEwYx4aEPZ4IxqhWh3R6DCmzqIn1hA=
-k8s.io/component-base v0.0.0-20191122220729-2684fb322cb9/go.mod h1:NFuUusy/X4Tk21m21tcNUihnmp4OI7lXU7/xA+rYXkc=
-k8s.io/component-base v0.18.0/go.mod h1:u3BCg0z1uskkzrnAKFzulmYaEpZF7XC9Pf/uFyb1v2c=
-k8s.io/component-base v0.18.2/go.mod h1:kqLlMuhJNHQ9lz8Z7V5bxUUtjFZnrypArGl58gmDfUM=
-k8s.io/component-base v0.18.6/go.mod h1:knSVsibPR5K6EW2XOjEHik6sdU5nCvKMrzMt2D4In14=
-k8s.io/gengo v0.0.0-20190128074634-0689ccc1d7d6/go.mod h1:ezvh/TsK7cY6rbqRK0oQQ8IAqLxYwwyPxAX1Pzy0ii0=
-k8s.io/gengo v0.0.0-20190822140433-26a664648505/go.mod h1:ezvh/TsK7cY6rbqRK0oQQ8IAqLxYwwyPxAX1Pzy0ii0=
-k8s.io/gengo v0.0.0-20200114144118-36b2048a9120/go.mod h1:ezvh/TsK7cY6rbqRK0oQQ8IAqLxYwwyPxAX1Pzy0ii0=
-k8s.io/gengo v0.0.0-20200413195148-3a45101e95ac/go.mod h1:ezvh/TsK7cY6rbqRK0oQQ8IAqLxYwwyPxAX1Pzy0ii0=
-k8s.io/klog v0.0.0-20181102134211-b9b56d5dfc92/go.mod h1:Gq+BEi5rUBO/HRz0bTSXDUcqjScdoY3a9IHpCEIOOfk=
-k8s.io/klog v0.3.0/go.mod h1:Gq+BEi5rUBO/HRz0bTSXDUcqjScdoY3a9IHpCEIOOfk=
-k8s.io/klog v0.3.3/go.mod h1:Gq+BEi5rUBO/HRz0bTSXDUcqjScdoY3a9IHpCEIOOfk=
-k8s.io/klog v0.4.0/go.mod h1:4Bi6QPql/J/LkTDqv7R/cd3hPo4k2DG6Ptcz060Ez5I=
-k8s.io/klog v1.0.0 h1:Pt+yjF5aB1xDSVbau4VsWe+dQNzA0qv1LlXdC2dF6Q8=
-k8s.io/klog v1.0.0/go.mod h1:4Bi6QPql/J/LkTDqv7R/cd3hPo4k2DG6Ptcz060Ez5I=
+honnef.co/go/tools v0.0.1-2020.1.3/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k=
+honnef.co/go/tools v0.0.1-2020.1.4/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k=
+k8s.io/api v0.23.0/go.mod h1:8wmDdLBHBNxtOIytwLstXt5E9PddnZb0GaMcqsvDBpg=
+k8s.io/api v0.23.1 h1:ncu/qfBfUoClqwkTGbeRqqOqBCRoUAflMuOaOD7J0c8=
+k8s.io/api v0.23.1/go.mod h1:WfXnOnwSqNtG62Y1CdjoMxh7r7u9QXGCkA1u0na2jgo=
+k8s.io/apiextensions-apiserver v0.23.0 h1:uii8BYmHYiT2ZTAJxmvc3X8UhNYMxl2A0z0Xq3Pm+WY=
+k8s.io/apiextensions-apiserver v0.23.0/go.mod h1:xIFAEEDlAZgpVBl/1VSjGDmLoXAWRG40+GsWhKhAxY4=
+k8s.io/apimachinery v0.23.0/go.mod h1:fFCTTBKvKcwTPFzjlcxp91uPFZr+JA0FubU4fLzzFYc=
+k8s.io/apimachinery v0.23.1 h1:sfBjlDFwj2onG0Ijx5C+SrAoeUscPrmghm7wHP+uXlo=
+k8s.io/apimachinery v0.23.1/go.mod h1:SADt2Kl8/sttJ62RRsi9MIV4o8f5S3coArm0Iu3fBno=
+k8s.io/apiserver v0.23.0/go.mod h1:Cec35u/9zAepDPPFyT+UMrgqOCjgJ5qtfVJDxjZYmt4=
+k8s.io/client-go v0.23.0/go.mod h1:hrDnpnK1mSr65lHHcUuIZIXDgEbzc7/683c6hyG4jTA=
+k8s.io/client-go v0.23.1 h1:Ma4Fhf/p07Nmj9yAB1H7UwbFHEBrSPg8lviR24U2GiQ=
+k8s.io/client-go v0.23.1/go.mod h1:6QSI8fEuqD4zgFK0xbdwfB/PthBsIxCJMa3s17WlcO0=
+k8s.io/code-generator v0.23.0/go.mod h1:vQvOhDXhuzqiVfM/YHp+dmg10WDZCchJVObc9MvowsE=
+k8s.io/component-base v0.23.0 h1:UAnyzjvVZ2ZR1lF35YwtNY6VMN94WtOnArcXBu34es8=
+k8s.io/component-base v0.23.0/go.mod h1:DHH5uiFvLC1edCpvcTDV++NKULdYYU6pR9Tt3HIKMKI=
+k8s.io/gengo v0.0.0-20210813121822-485abfe95c7c/go.mod h1:FiNAH4ZV3gBg2Kwh89tzAEV2be7d5xI0vBa/VySYy3E=
 k8s.io/klog/v2 v2.0.0/go.mod h1:PBfzABfn139FHAV07az/IF9Wp1bkk3vpT2XSJ76fSDE=
-k8s.io/klog/v2 v2.2.0 h1:XRvcwJozkgZ1UQJmfMGpvRthQHOvihEhYtDfAaxMz/A=
 k8s.io/klog/v2 v2.2.0/go.mod h1:Od+F08eJP+W3HUb4pSrPpgp9DGU4GzlpG/TmITuYh/Y=
-k8s.io/kube-openapi v0.0.0-20190320154901-5e45bb682580/go.mod h1:BXM9ceUBTj2QnfH2MK1odQs778ajze1RxcmP6S8RVVc=
-k8s.io/kube-openapi v0.0.0-20190816220812-743ec37842bf/go.mod h1:1TqjTSzOxsLGIKfj0lK8EeCP7K1iUG65v09OM0/WG5E=
-k8s.io/kube-openapi v0.0.0-20191107075043-30be4d16710a/go.mod h1:1TqjTSzOxsLGIKfj0lK8EeCP7K1iUG65v09OM0/WG5E=
-k8s.io/kube-openapi v0.0.0-20200121204235-bf4fb3bd569c/go.mod h1:GRQhZsXIAJ1xR0C9bd8UpWHZ5plfAS9fzPjJuQ6JL3E=
-k8s.io/kube-openapi v0.0.0-20200410145947-61e04a5be9a6/go.mod h1:GRQhZsXIAJ1xR0C9bd8UpWHZ5plfAS9fzPjJuQ6JL3E=
-k8s.io/kube-openapi v0.0.0-20200805222855-6aeccd4b50c6 h1:+WnxoVtG8TMiudHBSEtrVL1egv36TkkJm+bA8AxicmQ=
-k8s.io/kube-openapi v0.0.0-20200805222855-6aeccd4b50c6/go.mod h1:UuqjUnNftUyPE5H64/qeyjQoUZhGpeFDVdxjTeEVN2o=
-k8s.io/kube-state-metrics v1.7.2/go.mod h1:U2Y6DRi07sS85rmVPmBFlmv+2peBcL8IWGjM+IjYA/E=
-k8s.io/kubectl v0.18.0/go.mod h1:LOkWx9Z5DXMEg5KtOjHhRiC1fqJPLyCr3KtQgEolCkU=
-k8s.io/kubectl v0.18.2/go.mod h1:OdgFa3AlsPKRpFFYE7ICTwulXOcMGXHTc+UKhHKvrb4=
-k8s.io/kubernetes v1.13.0/go.mod h1:ocZa8+6APFNC2tX1DZASIbocyYT5jHzqFVsY5aoB7Jk=
-k8s.io/metrics v0.18.0/go.mod h1:8aYTW18koXqjLVKL7Ds05RPMX9ipJZI3mywYvBOxXd4=
-k8s.io/metrics v0.18.2/go.mod h1:qga8E7QfYNR9Q89cSCAjinC9pTZ7yv1XSVGUB0vJypg=
-k8s.io/utils v0.0.0-20190308190857-21c4ce38f2a7/go.mod h1:8k8uAuAQ0rXslZKaEWd0c3oVhZz7sSzSiPnVZayjIX0=
-k8s.io/utils v0.0.0-20190801114015-581e00157fb1/go.mod h1:sZAwmy6armz5eXlNoLmJcl4F1QuKu7sr+mFQ0byX7Ew=
-k8s.io/utils v0.0.0-20191114184206-e782cd3c129f/go.mod h1:sZAwmy6armz5eXlNoLmJcl4F1QuKu7sr+mFQ0byX7Ew=
-k8s.io/utils v0.0.0-20191114200735-6ca3b61696b6/go.mod h1:sZAwmy6armz5eXlNoLmJcl4F1QuKu7sr+mFQ0byX7Ew=
-k8s.io/utils v0.0.0-20200324210504-a9aa75ae1b89/go.mod h1:sZAwmy6armz5eXlNoLmJcl4F1QuKu7sr+mFQ0byX7Ew=
-k8s.io/utils v0.0.0-20200603063816-c1c6865ac451/go.mod h1:jPW/WVKK9YHAvNhRxK0md/EJ228hCsBRufyofKtW8HA=
-k8s.io/utils v0.0.0-20200729134348-d5654de09c73 h1:uJmqzgNWG7XyClnU/mLPBWwfKKF1K8Hf8whTseBgJcg=
-k8s.io/utils v0.0.0-20200729134348-d5654de09c73/go.mod h1:jPW/WVKK9YHAvNhRxK0md/EJ228hCsBRufyofKtW8HA=
-modernc.org/cc v1.0.0/go.mod h1:1Sk4//wdnYJiUIxnW8ddKpaOJCF37yAdqYnkxUpaYxw=
-modernc.org/golex v1.0.0/go.mod h1:b/QX9oBD/LhixY6NDh+IdGv17hgB+51fET1i2kPSmvk=
-modernc.org/mathutil v1.0.0/go.mod h1:wU0vUrJsVWBZ4P6e7xtFJEhFSNsfRLJ8H458uRjg03k=
-modernc.org/strutil v1.0.0/go.mod h1:lstksw84oURvj9y3tn8lGvRxyRC1S2+g5uuIzNfIOBs=
-modernc.org/xc v1.0.0/go.mod h1:mRNCo0bvLjGhHO9WsyuKVU4q0ceiDDDoEeWDJHrNx8I=
+k8s.io/klog/v2 v2.30.0 h1:bUO6drIvCIsvZ/XFgfxoGFQU/a4Qkh0iAlvUR7vlHJw=
+k8s.io/klog/v2 v2.30.0/go.mod h1:y1WjHnz7Dj687irZUWR/WLkLc5N1YHtjLdmgWjndZn0=
+k8s.io/kube-openapi v0.0.0-20211115234752-e816edb12b65 h1:E3J9oCLlaobFUqsjG9DfKbP2BmgwBL2p7pn0A3dG9W4=
+k8s.io/kube-openapi v0.0.0-20211115234752-e816edb12b65/go.mod h1:sX9MT8g7NVZM5lVL/j8QyCCJe8YSMW30QvGZWaCIDIk=
+k8s.io/utils v0.0.0-20210802155522-efc7438f0176/go.mod h1:jPW/WVKK9YHAvNhRxK0md/EJ228hCsBRufyofKtW8HA=
+k8s.io/utils v0.0.0-20210930125809-cb0fa318a74b h1:wxEMGetGMur3J1xuGLQY7GEQYg9bZxKn3tKo5k/eYcs=
+k8s.io/utils v0.0.0-20210930125809-cb0fa318a74b/go.mod h1:jPW/WVKK9YHAvNhRxK0md/EJ228hCsBRufyofKtW8HA=
 rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8=
-rsc.io/letsencrypt v0.0.3/go.mod h1:buyQKZ6IXrRnB7TdkHP0RyEybLx18HHyOSoTyoOLqNY=
-sigs.k8s.io/apiserver-network-proxy/konnectivity-client v0.0.7/go.mod h1:PHgbrJT7lCHcxMU+mDHEm+nx46H4zuuHZkDP6icnhu0=
-sigs.k8s.io/controller-runtime v0.6.3 h1:SBbr+inLPEKhvlJtrvDcwIpm+uhDvp63Bl72xYJtoOE=
-sigs.k8s.io/controller-runtime v0.6.3/go.mod h1:WlZNXcM0++oyaQt4B7C2lEE5JYRs8vJUzRP4N4JpdAY=
-sigs.k8s.io/controller-tools v0.2.4/go.mod h1:m/ztfQNocGYBgTTCmFdnK94uVvgxeZeE3LtJvd/jIzA=
-sigs.k8s.io/controller-tools v0.3.0 h1:y3YD99XOyWaXkiF1kd41uRvfp/64teWcrEZFuHxPhJ4=
-sigs.k8s.io/controller-tools v0.3.0/go.mod h1:enhtKGfxZD1GFEoMgP8Fdbu+uKQ/cq1/WGJhdVChfvI=
-sigs.k8s.io/kubebuilder v1.0.9-0.20200618125005-36aa113dbe99/go.mod h1:FGPx0hvP73+bapzWoy5ePuhAJYgJjrFbPxgvWyortM0=
-sigs.k8s.io/kustomize v2.0.3+incompatible/go.mod h1:MkjgH3RdOWrievjo6c9T245dYlB5QeXV4WCbnt/PEpU=
-sigs.k8s.io/structured-merge-diff v0.0.0-20190525122527-15d366b2352e/go.mod h1:wWxsB5ozmmv/SG7nM11ayaAW51xMvak/t1r0CSlcokI=
-sigs.k8s.io/structured-merge-diff v0.0.0-20190817042607-6149e4549fca/go.mod h1:IIgPezJWb76P0hotTxzDbWsMYB8APh18qZnxkomBpxA=
-sigs.k8s.io/structured-merge-diff v1.0.1-0.20191108220359-b1b620dd3f06 h1:zD2IemQ4LmOcAumeiyDWXKUI2SO0NYDe3H6QGvPOVgU=
-sigs.k8s.io/structured-merge-diff v1.0.1-0.20191108220359-b1b620dd3f06/go.mod h1:/ULNhyfzRopfcjskuui0cTITekDduZ7ycKN3oUT9R18=
-sigs.k8s.io/structured-merge-diff/v3 v3.0.0-20200116222232-67a7b8c61874/go.mod h1:PlARxl6Hbt/+BC80dRLi1qAmnMqwqDg62YvvVkZjemw=
-sigs.k8s.io/structured-merge-diff/v3 v3.0.0/go.mod h1:PlARxl6Hbt/+BC80dRLi1qAmnMqwqDg62YvvVkZjemw=
-sigs.k8s.io/structured-merge-diff/v4 v4.0.1 h1:YXTMot5Qz/X1iBRJhAt+vI+HVttY0WkSqqhKxQ0xVbA=
-sigs.k8s.io/structured-merge-diff/v4 v4.0.1/go.mod h1:bJZC9H9iH24zzfZ/41RGcq60oK1F7G282QMXDPYydCw=
-sigs.k8s.io/yaml v1.1.0/go.mod h1:UJmg0vDUVViEyp3mgSv9WPwZCDxu4rQW1olrI1uml+o=
-sigs.k8s.io/yaml v1.2.0 h1:kr/MCeFWJWTwyaHoR9c8EjH9OumOmoF9YGiZd7lFm/Q=
+rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0=
+rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA=
+sigs.k8s.io/apiserver-network-proxy/konnectivity-client v0.0.25/go.mod h1:Mlj9PNLmG9bZ6BHFwFKDo5afkpWyUISkb9Me0GnK66I=
+sigs.k8s.io/controller-runtime v0.11.0 h1:DqO+c8mywcZLFJWILq4iktoECTyn30Bkj0CwgqMpZWQ=
+sigs.k8s.io/controller-runtime v0.11.0/go.mod h1:KKwLiTooNGu+JmLZGn9Sl3Gjmfj66eMbCQznLP5zcqA=
+sigs.k8s.io/json v0.0.0-20211020170558-c049b76a60c6 h1:fD1pz4yfdADVNfFmcP2aBEtudwUQ1AlLnRBALr33v3s=
+sigs.k8s.io/json v0.0.0-20211020170558-c049b76a60c6/go.mod h1:p4QtZmO4uMYipTQNzagwnNoseA6OxSUutVw05NhYDRs=
+sigs.k8s.io/structured-merge-diff/v4 v4.0.2/go.mod h1:bJZC9H9iH24zzfZ/41RGcq60oK1F7G282QMXDPYydCw=
+sigs.k8s.io/structured-merge-diff/v4 v4.1.2/go.mod h1:j/nl6xW8vLS49O8YvXW1ocPhZawJtm+Yrr7PPRQ0Vg4=
+sigs.k8s.io/structured-merge-diff/v4 v4.2.0 h1:kDvPBbnPk+qYmkHmSo8vKGp438IASWofnbbUKDE/bv0=
+sigs.k8s.io/structured-merge-diff/v4 v4.2.0/go.mod h1:j/nl6xW8vLS49O8YvXW1ocPhZawJtm+Yrr7PPRQ0Vg4=
 sigs.k8s.io/yaml v1.2.0/go.mod h1:yfXDCHCao9+ENCvLSE62v9VSji2MKu5jeNfTrofGhJc=
-vbom.ml/util v0.0.0-20160121211510-db5cfe13f5cc/go.mod h1:so/NYdZXCz+E3ZpW0uAoCj6uzU2+8OWDFv/HxUSs7kI=
+sigs.k8s.io/yaml v1.3.0 h1:a2VclLzOGrwOHDiV8EfBGhvjHvP46CtW5j6POvhYGGo=
+sigs.k8s.io/yaml v1.3.0/go.mod h1:GeOyir5tyXNByN85N/dRIT9es5UQNerPYEKK56eTBm8=
diff --git a/central-controller/src/monitor/hack/boilerplate.go.txt b/central-controller/src/monitor/hack/boilerplate.go.txt
new file mode 100644 (file)
index 0000000..29c55ec
--- /dev/null
@@ -0,0 +1,15 @@
+/*
+Copyright 2022.
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
\ No newline at end of file
diff --git a/central-controller/src/monitor/main.go b/central-controller/src/monitor/main.go
new file mode 100644 (file)
index 0000000..fb47ca4
--- /dev/null
@@ -0,0 +1,80 @@
+// SPDX-License-Identifier: Apache-2.0
+// Copyright (c) 2022 Intel Corporation
+
+package main
+
+import (
+       "flag"
+       "os"
+       // Import all Kubernetes client auth plugins (e.g. Azure, GCP, OIDC, etc.)
+       // to ensure that exec-entrypoint and run can make use of them.
+       _ "k8s.io/client-go/plugin/pkg/client/auth"
+
+       "k8s.io/apimachinery/pkg/runtime"
+       utilruntime "k8s.io/apimachinery/pkg/util/runtime"
+       clientgoscheme "k8s.io/client-go/kubernetes/scheme"
+       ctrl "sigs.k8s.io/controller-runtime"
+
+       "sigs.k8s.io/controller-runtime/pkg/log/zap"
+
+       "gitlab.com/project-emco/core/emco-base/src/monitor/controllers"
+       k8spluginv1alpha1 "gitlab.com/project-emco/core/emco-base/src/monitor/pkg/apis/k8splugin/v1alpha1"
+       //+kubebuilder:scaffold:imports
+)
+
+var (
+       scheme   = runtime.NewScheme()
+       setupLog = ctrl.Log.WithName("setup")
+)
+
+func init() {
+       utilruntime.Must(clientgoscheme.AddToScheme(scheme))
+
+       utilruntime.Must(k8spluginv1alpha1.AddToScheme(scheme))
+       //+kubebuilder:scaffold:scheme
+}
+
+func main() {
+       var metricsAddr string
+       var enableLeaderElection bool
+       var probeAddr string
+
+       flag.StringVar(&metricsAddr, "metrics-bind-address", ":8080", "The address the metric endpoint binds to.")
+       flag.StringVar(&probeAddr, "health-probe-bind-address", ":8081", "The address the probe endpoint binds to.")
+       flag.BoolVar(&enableLeaderElection, "leader-elect", false,
+               "Enable leader election for controller manager. "+
+                       "Enabling this will ensure there is only one active controller manager.")
+
+       flag.Parse()
+       ctrl.SetLogger(zap.New(func(o *zap.Options) {
+               o.Development = true
+       }))
+       mgr, err := ctrl.NewManager(ctrl.GetConfigOrDie(), ctrl.Options{
+               Scheme:                 scheme,
+               MetricsBindAddress:     metricsAddr,
+               Port:                   9443,
+               HealthProbeBindAddress: probeAddr,
+               LeaderElection:         enableLeaderElection,
+               LeaderElectionID:       "leaderelectionid.k8splugin.io",
+       })
+       if err != nil {
+               setupLog.Error(err, "unable to start manager")
+               os.Exit(1)
+       }
+       // Setup Github client, ignore errors. On error Monitor continues to
+       // work normally without updating CR in Github
+       controllers.SetupGitHubClient()
+       if err = (&controllers.ResourceBundleStateReconciler{
+               Client: mgr.GetClient(),
+               Scheme: mgr.GetScheme(),
+       }).SetupWithManager(mgr); err != nil {
+               setupLog.Error(err, "unable to create controller", "controller", "ResourceBundleState")
+               os.Exit(1)
+       }
+       controllers.SetupControllers(mgr)
+       setupLog.Info("starting manager")
+       if err := mgr.Start(ctrl.SetupSignalHandler()); err != nil {
+               setupLog.Error(err, "problem running manager")
+               os.Exit(1)
+       }
+}
diff --git a/central-controller/src/monitor/pkg/apis/addtoscheme_k8splugin_v1alpha1.go b/central-controller/src/monitor/pkg/apis/addtoscheme_k8splugin_v1alpha1.go
deleted file mode 100644 (file)
index 5063653..0000000
+++ /dev/null
@@ -1,10 +0,0 @@
-package apis
-
-import (
-       "github.com/open-ness/EMCO/src/monitor/pkg/apis/k8splugin/v1alpha1"
-)
-
-func init() {
-       // Register the types with the Scheme so the components can map objects to GroupVersionKinds and back
-       AddToSchemes = append(AddToSchemes, v1alpha1.SchemeBuilder.AddToScheme)
-}
diff --git a/central-controller/src/monitor/pkg/apis/apis.go b/central-controller/src/monitor/pkg/apis/apis.go
deleted file mode 100644 (file)
index 07dc961..0000000
+++ /dev/null
@@ -1,13 +0,0 @@
-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/central-controller/src/monitor/pkg/apis/k8splugin/group.go b/central-controller/src/monitor/pkg/apis/k8splugin/group.go
deleted file mode 100644 (file)
index 9696c62..0000000
+++ /dev/null
@@ -1,6 +0,0 @@
-// Package k8splugin contains k8splugin API versions.
-//
-// This file ensures Go source parsers acknowledge the k8splugin package
-// and any child packages. It can be removed if any other Go source files are
-// added to this package.
-package k8splugin
diff --git a/central-controller/src/monitor/pkg/apis/k8splugin/v1alpha1/doc.go b/central-controller/src/monitor/pkg/apis/k8splugin/v1alpha1/doc.go
deleted file mode 100644 (file)
index c2bb090..0000000
+++ /dev/null
@@ -1,4 +0,0 @@
-// Package v1alpha1 contains API Schema definitions for the k8splugin v1alpha1 API group
-// +k8s:deepcopy-gen=package,register
-// +groupName=k8splugin.io
-package v1alpha1
diff --git a/central-controller/src/monitor/pkg/apis/k8splugin/v1alpha1/groupversion_info.go b/central-controller/src/monitor/pkg/apis/k8splugin/v1alpha1/groupversion_info.go
new file mode 100644 (file)
index 0000000..6c42974
--- /dev/null
@@ -0,0 +1,47 @@
+/*
+Copyright 2022.
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES 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 contains API Schema definitions for the k8splugin v1alpha1 API group
+//+kubebuilder:object:generate=true
+//+groupName=k8splugin.io
+package v1alpha1
+
+import (
+       "k8s.io/apimachinery/pkg/runtime/schema"
+       "sigs.k8s.io/controller-runtime/pkg/scheme"
+)
+
+var (
+       // GroupVersion is group version used to register these objects
+       GroupVersion       = schema.GroupVersion{Group: "k8splugin.io", Version: "v1alpha1"}
+       SchemeGroupVersion = schema.GroupVersion{Group: "k8splugin.io", Version: "v1alpha1"}
+
+       // SchemeBuilder is used to add go types to the GroupVersionKind scheme
+       SchemeBuilder = &scheme.Builder{GroupVersion: GroupVersion}
+
+       // AddToScheme adds the types in this group-version to the given scheme.
+       AddToScheme = SchemeBuilder.AddToScheme
+)
+
+// 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()
+}
diff --git a/central-controller/src/monitor/pkg/apis/k8splugin/v1alpha1/register.go b/central-controller/src/monitor/pkg/apis/k8splugin/v1alpha1/register.go
deleted file mode 100644 (file)
index 7d3334a..0000000
+++ /dev/null
@@ -1,32 +0,0 @@
-// NOTE: Boilerplate only.  Ignore this file.
-
-// Package v1alpha1 contains API Schema definitions for the k8splugin v1alpha1 API group
-// +k8s:deepcopy-gen=package,register
-// +groupName=k8splugin.io
-package v1alpha1
-
-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: "k8splugin.io", Version: "v1alpha1"}
-
-       // SchemeBuilder is used to add go types to the GroupVersionKind scheme
-       SchemeBuilder = &scheme.Builder{GroupVersion: SchemeGroupVersion}
-
-       // AddToScheme is a global function variable that registers this API
-       AddToScheme = SchemeBuilder.AddToScheme
-)
-
-// 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()
-}
diff --git a/central-controller/src/monitor/pkg/apis/k8splugin/v1alpha1/resourcebundlestate_types.go b/central-controller/src/monitor/pkg/apis/k8splugin/v1alpha1/resourcebundlestate_types.go
new file mode 100644 (file)
index 0000000..a930cf8
--- /dev/null
@@ -0,0 +1,119 @@
+/*
+Copyright 2022.
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+// +k8s:deepcopy-gen=package,register
+// +groupName=k8splugin.io
+package v1alpha1
+
+// +kubebuilder:validation:Optional
+import (
+       appsv1 "k8s.io/api/apps/v1"
+       v1 "k8s.io/api/batch/v1"
+       certsapi "k8s.io/api/certificates/v1"
+       corev1 "k8s.io/api/core/v1"
+       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.
+
+// ResourceBundleStateSpec defines the desired state of ResourceBundleState
+type ResourceBundleStateSpec struct {
+       // INSERT ADDITIONAL SPEC FIELDS - desired state of cluster
+       // Important: Run "make" to regenerate code after modifying this file
+       Selector *metav1.LabelSelector `json:"selector" protobuf:"bytes,1,opt,name=selector"`
+}
+
+// ResourceBundleStateStatus defines the observed state of ResourceBundleState
+type ResourceBundleStateStatus struct {
+       // INSERT ADDITIONAL STATUS FIELD - define observed state of cluster
+       // Important: Run "make" to regenerate code after modifying this file
+       Ready         bool  `json:"ready" protobuf:"varint,1,opt,name=ready"`
+       ResourceCount int32 `json:"resourceCount" protobuf:"varint,2,opt,name=resourceCount"`
+
+       // +kubebuilder:validation:Optional
+       // +optional
+       PodStatuses []corev1.Pod `json:"podStatuses,omitempty" protobuf:"varint,3,opt,name=podStatuses"`
+
+       // +kubebuilder:validation:Optional
+       // +optional
+       ServiceStatuses []corev1.Service `json:"serviceStatuses,omitempty" protobuf:"varint,4,opt,name=serviceStatuses"`
+
+       // +kubebuilder:validation:Optional
+       // +optional
+       ConfigMapStatuses []corev1.ConfigMap `json:"configMapStatuses,omitempty" protobuf:"varint,5,opt,name=configMapStatuses"`
+
+       // +kubebuilder:validation:Optional
+       // +optional
+       DeploymentStatuses []appsv1.Deployment `json:"deploymentStatuses,omitempty" protobuf:"varint,6,opt,name=deploymentStatuses"`
+
+       // +kubebuilder:validation:Optional
+       // +optional
+       DaemonSetStatuses []appsv1.DaemonSet `json:"daemonSetStatuses,omitempty" protobuf:"varint,8,opt,name=daemonSetStatuses"`
+
+       // +kubebuilder:validation:Optional
+       // +optional
+       CsrStatuses []certsapi.CertificateSigningRequest `json:"csrStatuses,omitempty" protobuf:"varint,9,opt,name=csrStatuses"`
+
+       // +kubebuilder:validation:Optional
+       // +optional
+       JobStatuses []v1.Job `json:"jobStatuses,omitempty" protobuf:"varint,12,opt,name=jobStatuses"`
+
+       // +kubebuilder:validation:Optional
+       // +optional
+       StatefulSetStatuses []appsv1.StatefulSet `json:"statefulSetStatuses,omitempty" protobuf:"varint,13,opt,name=statefulSetStatuses"`
+
+       // +kubebuilder:validation:Optional
+       // +optional
+       ResourceStatuses []ResourceStatus `json:"resourceStatuses,omitempty" protobuf:"varint,14,opt,name=resourceStatuses"`
+}
+
+// Resoureces
+type ResourceStatus struct {
+       Group     string `json:"group"`
+       Version   string `json:"version"`
+       Kind      string `json:"kind"`
+       Name      string `json:"name"`
+       Namespace string `json:"namespace,omitempty"`
+       Res       []byte `json:"res"`
+}
+
+//+kubebuilder:object:root=true
+//+kubebuilder:subresource:status
+// ResourceBundleState is the Schema for the resourcebundlestates API
+// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object
+// +genclient
+
+type ResourceBundleState struct {
+       metav1.TypeMeta   `json:",inline"`
+       metav1.ObjectMeta `json:"metadata,omitempty"`
+
+       Spec   ResourceBundleStateSpec   `json:"spec,omitempty"`
+       Status ResourceBundleStateStatus `json:"status,omitempty"`
+}
+
+//+kubebuilder:object:root=true
+// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object
+
+// ResourceBundleStateList contains a list of ResourceBundleState
+type ResourceBundleStateList struct {
+       metav1.TypeMeta `json:",inline"`
+       metav1.ListMeta `json:"metadata,omitempty"`
+       Items           []ResourceBundleState `json:"items"`
+}
+
+func init() {
+       SchemeBuilder.Register(&ResourceBundleState{}, &ResourceBundleStateList{})
+}
diff --git a/central-controller/src/monitor/pkg/apis/k8splugin/v1alpha1/types.go b/central-controller/src/monitor/pkg/apis/k8splugin/v1alpha1/types.go
deleted file mode 100644 (file)
index fba10bb..0000000
+++ /dev/null
@@ -1,68 +0,0 @@
-package v1alpha1
-
-import (
-       appsv1 "k8s.io/api/apps/v1"
-       v1 "k8s.io/api/batch/v1"
-       certsapi "k8s.io/api/certificates/v1beta1"
-       corev1 "k8s.io/api/core/v1"
-       v1beta1 "k8s.io/api/extensions/v1beta1"
-       metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
-)
-
-// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object
-
-// ResourceBundleState is the Schema for the ResourceBundleStatees API
-// +k8s:openapi-gen=true
-// +kubebuilder:subresource:status
-// +genclient
-type ResourceBundleState struct {
-       metav1.TypeMeta   `json:",inline" yaml:",inline"`
-       metav1.ObjectMeta `json:"metadata,omitempty" protobuf:"bytes,1,opt,name=metadata" yaml:"metadata"`
-
-       Spec   ResourceBundleStateSpec `json:"spec,omitempty" protobuf:"bytes,2,opt,name=spec"`
-       Status ResourceBundleStatus    `json:"status,omitempty" protobuf:"bytes,3,opt,name=status"`
-}
-
-// ResourceBundleStateSpec defines the desired state of ResourceBundleState
-// +k8s:openapi-gen=true
-type ResourceBundleStateSpec struct {
-       Selector *metav1.LabelSelector `json:"selector" protobuf:"bytes,1,opt,name=selector"`
-}
-
-// ResourceBundleStatus defines the observed state of ResourceBundleState
-// +k8s:openapi-gen=true
-type ResourceBundleStatus struct {
-       Ready               bool                                 `json:"ready" protobuf:"varint,1,opt,name=ready"`
-       ResourceCount       int32                                `json:"resourceCount" protobuf:"varint,2,opt,name=resourceCount"`
-       PodStatuses         []corev1.Pod                         `json:"podStatuses" protobuf:"varint,3,opt,name=podStatuses"`
-       ServiceStatuses     []corev1.Service                     `json:"serviceStatuses" protobuf:"varint,4,opt,name=serviceStatuses"`
-       ConfigMapStatuses   []corev1.ConfigMap                   `json:"configMapStatuses" protobuf:"varint,5,opt,name=configMapStatuses"`
-       DeploymentStatuses  []appsv1.Deployment                  `json:"deploymentStatuses" protobuf:"varint,6,opt,name=deploymentStatuses"`
-       SecretStatuses      []corev1.Secret                      `json:"secretStatuses" protobuf:"varint,7,opt,name=secretStatuses"`
-       DaemonSetStatuses   []appsv1.DaemonSet                   `json:"daemonSetStatuses" protobuf:"varint,8,opt,name=daemonSetStatuses"`
-       IngressStatuses     []v1beta1.Ingress                    `json:"ingressStatuses" protobuf:"varint,11,opt,name=ingressStatuses"`
-       JobStatuses         []v1.Job                             `json:"jobStatuses" protobuf:"varint,12,opt,name=jobStatuses"`
-       StatefulSetStatuses []appsv1.StatefulSet                 `json:"statefulSetStatuses" protobuf:"varint,13,opt,name=statefulSetStatuses"`
-       CsrStatuses         []certsapi.CertificateSigningRequest `json:"csrStatuses" protobuf:"varint,3,opt,name=csrStatuses"`
-}
-
-// PodStatus defines the observed state of ResourceBundleState
-// +k8s:openapi-gen=true
-type PodStatus struct {
-       metav1.ObjectMeta `json:"metadata,omitempty" protobuf:"bytes,1,opt,name=metadata"`
-       Ready             bool             `json:"ready" protobuf:"varint,2,opt,name=ready"`
-       Status            corev1.PodStatus `json:"status,omitempty" protobuf:"bytes,3,opt,name=status"`
-}
-
-// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object
-
-// ResourceBundleStateList contains a list of ResourceBundleState
-type ResourceBundleStateList struct {
-       metav1.TypeMeta `json:",inline"`
-       metav1.ListMeta `json:"metadata,omitempty"`
-       Items           []ResourceBundleState `json:"items"`
-}
-
-func init() {
-       SchemeBuilder.Register(&ResourceBundleState{}, &ResourceBundleStateList{})
-}
index ff974aa..bb0d23d 100644 (file)
@@ -1,38 +1,35 @@
+//go:build !ignore_autogenerated
 // +build !ignore_autogenerated
 
-// Code generated by operator-sdk. DO NOT EDIT.
+/*
+Copyright 2022.
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+// Code generated by controller-gen. DO NOT EDIT.
 
 package v1alpha1
 
 import (
        appsv1 "k8s.io/api/apps/v1"
        batchv1 "k8s.io/api/batch/v1"
+       certificatesv1 "k8s.io/api/certificates/v1"
        corev1 "k8s.io/api/core/v1"
-       v1beta1 "k8s.io/api/extensions/v1beta1"
-       v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
+       "k8s.io/apimachinery/pkg/apis/meta/v1"
        runtime "k8s.io/apimachinery/pkg/runtime"
 )
 
-/*
-// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
-func (in *PodStatus) DeepCopyInto(out *PodStatus) {
-       *out = *in
-       in.ObjectMeta.DeepCopyInto(&out.ObjectMeta)
-       in.Status.DeepCopyInto(&out.Status)
-       return
-}
-
-// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new PodStatus.
-func (in *PodStatus) DeepCopy() *PodStatus {
-       if in == nil {
-               return nil
-       }
-       out := new(PodStatus)
-       in.DeepCopyInto(out)
-       return out
-}
-*/
-
 // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
 func (in *ResourceBundleState) DeepCopyInto(out *ResourceBundleState) {
        *out = *in
@@ -40,7 +37,6 @@ func (in *ResourceBundleState) DeepCopyInto(out *ResourceBundleState) {
        in.ObjectMeta.DeepCopyInto(&out.ObjectMeta)
        in.Spec.DeepCopyInto(&out.Spec)
        in.Status.DeepCopyInto(&out.Status)
-       return
 }
 
 // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ResourceBundleState.
@@ -65,7 +61,7 @@ func (in *ResourceBundleState) DeepCopyObject() runtime.Object {
 func (in *ResourceBundleStateList) DeepCopyInto(out *ResourceBundleStateList) {
        *out = *in
        out.TypeMeta = in.TypeMeta
-       out.ListMeta = in.ListMeta
+       in.ListMeta.DeepCopyInto(&out.ListMeta)
        if in.Items != nil {
                in, out := &in.Items, &out.Items
                *out = make([]ResourceBundleState, len(*in))
@@ -73,7 +69,6 @@ func (in *ResourceBundleStateList) DeepCopyInto(out *ResourceBundleStateList) {
                        (*in)[i].DeepCopyInto(&(*out)[i])
                }
        }
-       return
 }
 
 // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ResourceBundleStateList.
@@ -102,7 +97,6 @@ func (in *ResourceBundleStateSpec) DeepCopyInto(out *ResourceBundleStateSpec) {
                *out = new(v1.LabelSelector)
                (*in).DeepCopyInto(*out)
        }
-       return
 }
 
 // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ResourceBundleStateSpec.
@@ -116,7 +110,7 @@ func (in *ResourceBundleStateSpec) DeepCopy() *ResourceBundleStateSpec {
 }
 
 // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
-func (in *ResourceBundleStatus) DeepCopyInto(out *ResourceBundleStatus) {
+func (in *ResourceBundleStateStatus) DeepCopyInto(out *ResourceBundleStateStatus) {
        *out = *in
        if in.PodStatuses != nil {
                in, out := &in.PodStatuses, &out.PodStatuses
@@ -146,13 +140,6 @@ func (in *ResourceBundleStatus) DeepCopyInto(out *ResourceBundleStatus) {
                        (*in)[i].DeepCopyInto(&(*out)[i])
                }
        }
-       if in.SecretStatuses != nil {
-               in, out := &in.SecretStatuses, &out.SecretStatuses
-               *out = make([]corev1.Secret, len(*in))
-               for i := range *in {
-                       (*in)[i].DeepCopyInto(&(*out)[i])
-               }
-       }
        if in.DaemonSetStatuses != nil {
                in, out := &in.DaemonSetStatuses, &out.DaemonSetStatuses
                *out = make([]appsv1.DaemonSet, len(*in))
@@ -160,9 +147,9 @@ func (in *ResourceBundleStatus) DeepCopyInto(out *ResourceBundleStatus) {
                        (*in)[i].DeepCopyInto(&(*out)[i])
                }
        }
-       if in.IngressStatuses != nil {
-               in, out := &in.IngressStatuses, &out.IngressStatuses
-               *out = make([]v1beta1.Ingress, len(*in))
+       if in.CsrStatuses != nil {
+               in, out := &in.CsrStatuses, &out.CsrStatuses
+               *out = make([]certificatesv1.CertificateSigningRequest, len(*in))
                for i := range *in {
                        (*in)[i].DeepCopyInto(&(*out)[i])
                }
@@ -181,15 +168,41 @@ func (in *ResourceBundleStatus) DeepCopyInto(out *ResourceBundleStatus) {
                        (*in)[i].DeepCopyInto(&(*out)[i])
                }
        }
-       return
+       if in.ResourceStatuses != nil {
+               in, out := &in.ResourceStatuses, &out.ResourceStatuses
+               *out = make([]ResourceStatus, len(*in))
+               for i := range *in {
+                       (*in)[i].DeepCopyInto(&(*out)[i])
+               }
+       }
+}
+
+// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ResourceBundleStateStatus.
+func (in *ResourceBundleStateStatus) DeepCopy() *ResourceBundleStateStatus {
+       if in == nil {
+               return nil
+       }
+       out := new(ResourceBundleStateStatus)
+       in.DeepCopyInto(out)
+       return out
+}
+
+// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
+func (in *ResourceStatus) DeepCopyInto(out *ResourceStatus) {
+       *out = *in
+       if in.Res != nil {
+               in, out := &in.Res, &out.Res
+               *out = make([]byte, len(*in))
+               copy(*out, *in)
+       }
 }
 
-// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ResourceBundleStatus.
-func (in *ResourceBundleStatus) DeepCopy() *ResourceBundleStatus {
+// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ResourceStatus.
+func (in *ResourceStatus) DeepCopy() *ResourceStatus {
        if in == nil {
                return nil
        }
-       out := new(ResourceBundleStatus)
+       out := new(ResourceStatus)
        in.DeepCopyInto(out)
        return out
 }
diff --git a/central-controller/src/monitor/pkg/apis/k8splugin/v1alpha1/zz_generated.openapi.go b/central-controller/src/monitor/pkg/apis/k8splugin/v1alpha1/zz_generated.openapi.go
deleted file mode 100644 (file)
index 1d4e81b..0000000
+++ /dev/null
@@ -1,180 +0,0 @@
-// +build !ignore_autogenerated
-
-// This file was autogenerated by openapi-gen. Do not edit it manually!
-
-package v1alpha1
-
-import (
-       spec "github.com/go-openapi/spec"
-       common "k8s.io/kube-openapi/pkg/common"
-)
-
-func GetOpenAPIDefinitions(ref common.ReferenceCallback) map[string]common.OpenAPIDefinition {
-       return map[string]common.OpenAPIDefinition{
-               "./pkg/apis/k8splugin/v1alpha1.PodStatus":               schema_pkg_apis_k8splugin_v1alpha1_PodStatus(ref),
-               "./pkg/apis/k8splugin/v1alpha1.ResourceBundleState":     schema_pkg_apis_k8splugin_v1alpha1_ResourceBundleState(ref),
-               "./pkg/apis/k8splugin/v1alpha1.ResourceBundleStateSpec": schema_pkg_apis_k8splugin_v1alpha1_ResourceBundleStateSpec(ref),
-               "./pkg/apis/k8splugin/v1alpha1.ResourceBundleStatus":    schema_pkg_apis_k8splugin_v1alpha1_ResourceBundleStatus(ref),
-       }
-}
-
-func schema_pkg_apis_k8splugin_v1alpha1_PodStatus(ref common.ReferenceCallback) common.OpenAPIDefinition {
-       return common.OpenAPIDefinition{
-               Schema: spec.Schema{
-                       SchemaProps: spec.SchemaProps{
-                               Description: "PodStatus defines the observed state of ResourceBundleState",
-                               Type:        []string{"object"},
-                               Properties: map[string]spec.Schema{
-                                       "metadata": {
-                                               SchemaProps: spec.SchemaProps{
-                                                       Ref: ref("k8s.io/apimachinery/pkg/apis/meta/v1.ObjectMeta"),
-                                               },
-                                       },
-                                       "ready": {
-                                               SchemaProps: spec.SchemaProps{
-                                                       Type:   []string{"boolean"},
-                                                       Format: "",
-                                               },
-                                       },
-                                       "status": {
-                                               SchemaProps: spec.SchemaProps{
-                                                       Ref: ref("k8s.io/api/core/v1.PodStatus"),
-                                               },
-                                       },
-                               },
-                               Required: []string{"ready"},
-                       },
-               },
-               Dependencies: []string{
-                       "k8s.io/api/core/v1.PodStatus", "k8s.io/apimachinery/pkg/apis/meta/v1.ObjectMeta"},
-       }
-}
-
-func schema_pkg_apis_k8splugin_v1alpha1_ResourceBundleState(ref common.ReferenceCallback) common.OpenAPIDefinition {
-       return common.OpenAPIDefinition{
-               Schema: spec.Schema{
-                       SchemaProps: spec.SchemaProps{
-                               Description: "ResourceBundleState is the Schema for the ResourceBundleStatees API",
-                               Type:        []string{"object"},
-                               Properties: map[string]spec.Schema{
-                                       "kind": {
-                                               SchemaProps: spec.SchemaProps{
-                                                       Description: "Kind is a string value representing the REST resource this object represents. Servers may infer this from the endpoint the client submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/api-conventions.md#types-kinds",
-                                                       Type:        []string{"string"},
-                                                       Format:      "",
-                                               },
-                                       },
-                                       "apiVersion": {
-                                               SchemaProps: spec.SchemaProps{
-                                                       Description: "APIVersion defines the versioned schema of this representation of an object. Servers should convert recognized schemas to the latest internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/api-conventions.md#resources",
-                                                       Type:        []string{"string"},
-                                                       Format:      "",
-                                               },
-                                       },
-                                       "metadata": {
-                                               SchemaProps: spec.SchemaProps{
-                                                       Ref: ref("k8s.io/apimachinery/pkg/apis/meta/v1.ObjectMeta"),
-                                               },
-                                       },
-                                       "spec": {
-                                               SchemaProps: spec.SchemaProps{
-                                                       Ref: ref("./pkg/apis/k8splugin/v1alpha1.ResourceBundleStateSpec"),
-                                               },
-                                       },
-                                       "status": {
-                                               SchemaProps: spec.SchemaProps{
-                                                       Ref: ref("./pkg/apis/k8splugin/v1alpha1.ResourceBundleStatus"),
-                                               },
-                                       },
-                               },
-                       },
-               },
-               Dependencies: []string{
-                       "./pkg/apis/k8splugin/v1alpha1.ResourceBundleStateSpec", "./pkg/apis/k8splugin/v1alpha1.ResourceBundleStatus", "k8s.io/apimachinery/pkg/apis/meta/v1.ObjectMeta"},
-       }
-}
-
-func schema_pkg_apis_k8splugin_v1alpha1_ResourceBundleStateSpec(ref common.ReferenceCallback) common.OpenAPIDefinition {
-       return common.OpenAPIDefinition{
-               Schema: spec.Schema{
-                       SchemaProps: spec.SchemaProps{
-                               Description: "ResourceBundleStateSpec defines the desired state of ResourceBundleState",
-                               Type:        []string{"object"},
-                               Properties: map[string]spec.Schema{
-                                       "selector": {
-                                               SchemaProps: spec.SchemaProps{
-                                                       Ref: ref("k8s.io/apimachinery/pkg/apis/meta/v1.LabelSelector"),
-                                               },
-                                       },
-                               },
-                               Required: []string{"selector"},
-                       },
-               },
-               Dependencies: []string{
-                       "k8s.io/apimachinery/pkg/apis/meta/v1.LabelSelector"},
-       }
-}
-
-func schema_pkg_apis_k8splugin_v1alpha1_ResourceBundleStatus(ref common.ReferenceCallback) common.OpenAPIDefinition {
-       return common.OpenAPIDefinition{
-               Schema: spec.Schema{
-                       SchemaProps: spec.SchemaProps{
-                               Description: "ResourceBundleStatus defines the observed state of ResourceBundleState",
-                               Type:        []string{"object"},
-                               Properties: map[string]spec.Schema{
-                                       "ready": {
-                                               SchemaProps: spec.SchemaProps{
-                                                       Type:   []string{"boolean"},
-                                                       Format: "",
-                                               },
-                                       },
-                                       "resourceCount": {
-                                               SchemaProps: spec.SchemaProps{
-                                                       Type:   []string{"integer"},
-                                                       Format: "int32",
-                                               },
-                                       },
-                                       "podStatuses": {
-                                               SchemaProps: spec.SchemaProps{
-                                                       Type: []string{"array"},
-                                                       Items: &spec.SchemaOrArray{
-                                                               Schema: &spec.Schema{
-                                                                       SchemaProps: spec.SchemaProps{
-                                                                               Ref: ref("./pkg/apis/k8splugin/v1alpha1.PodStatus"),
-                                                                       },
-                                                               },
-                                                       },
-                                               },
-                                       },
-                                       "serviceStatuses": {
-                                               SchemaProps: spec.SchemaProps{
-                                                       Type: []string{"array"},
-                                                       Items: &spec.SchemaOrArray{
-                                                               Schema: &spec.Schema{
-                                                                       SchemaProps: spec.SchemaProps{
-                                                                               Ref: ref("k8s.io/api/core/v1.Service"),
-                                                                       },
-                                                               },
-                                                       },
-                                               },
-                                       },
-                                       "configMapStatuses": {
-                                               SchemaProps: spec.SchemaProps{
-                                                       Type: []string{"array"},
-                                                       Items: &spec.SchemaOrArray{
-                                                               Schema: &spec.Schema{
-                                                                       SchemaProps: spec.SchemaProps{
-                                                                               Ref: ref("k8s.io/api/core/v1.ConfigMap"),
-                                                                       },
-                                                               },
-                                                       },
-                                               },
-                                       },
-                               },
-                               Required: []string{"ready", "resourceCount", "podStatuses", "serviceStatuses"},
-                       },
-               },
-               Dependencies: []string{
-                       "./pkg/apis/k8splugin/v1alpha1.PodStatus", "k8s.io/api/core/v1.ConfigMap", "k8s.io/api/core/v1.Service"},
-       }
-}
@@ -1,12 +1,26 @@
-// SPDX-License-Identifier: Apache-2.0
-// Copyright (c) 2020 Intel Corporation
+/*
+Copyright The Kubernetes Authors.
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
 // Code generated by client-gen. DO NOT EDIT.
 
 package versioned
 
 import (
        "fmt"
-       k8spluginv1alpha1 "github.com/open-ness/EMCO/src/monitor/pkg/generated/clientset/versioned/typed/k8splugin/v1alpha1"
+       k8spluginv1alpha1 "gitlab.com/project-emco/core/emco-base/src/monitor/pkg/client/clientset/versioned/typed/k8splugin/v1alpha1"
 
        discovery "k8s.io/client-go/discovery"
        rest "k8s.io/client-go/rest"
diff --git a/central-controller/src/monitor/pkg/client/clientset/versioned/doc.go b/central-controller/src/monitor/pkg/client/clientset/versioned/doc.go
new file mode 100644 (file)
index 0000000..41721ca
--- /dev/null
@@ -0,0 +1,20 @@
+/*
+Copyright The Kubernetes Authors.
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+// Code generated by client-gen. DO NOT EDIT.
+
+// This package has the automatically generated clientset.
+package versioned
@@ -1,13 +1,27 @@
-// SPDX-License-Identifier: Apache-2.0
-// Copyright (c) 2020 Intel Corporation
+/*
+Copyright The Kubernetes Authors.
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
 // Code generated by client-gen. DO NOT EDIT.
 
 package fake
 
 import (
-       clientset "github.com/open-ness/EMCO/src/monitor/pkg/generated/clientset/versioned"
-       k8spluginv1alpha1 "github.com/open-ness/EMCO/src/monitor/pkg/generated/clientset/versioned/typed/k8splugin/v1alpha1"
-       fakek8spluginv1alpha1 "github.com/open-ness/EMCO/src/monitor/pkg/generated/clientset/versioned/typed/k8splugin/v1alpha1/fake"
+       clientset "gitlab.com/project-emco/core/emco-base/src/monitor/pkg/client/clientset/versioned"
+       k8spluginv1alpha1 "gitlab.com/project-emco/core/emco-base/src/monitor/pkg/client/clientset/versioned/typed/k8splugin/v1alpha1"
+       fakek8spluginv1alpha1 "gitlab.com/project-emco/core/emco-base/src/monitor/pkg/client/clientset/versioned/typed/k8splugin/v1alpha1/fake"
 
        "k8s.io/apimachinery/pkg/runtime"
        "k8s.io/apimachinery/pkg/watch"
diff --git a/central-controller/src/monitor/pkg/client/clientset/versioned/fake/doc.go b/central-controller/src/monitor/pkg/client/clientset/versioned/fake/doc.go
new file mode 100644 (file)
index 0000000..9b99e71
--- /dev/null
@@ -0,0 +1,20 @@
+/*
+Copyright The Kubernetes Authors.
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+// Code generated by client-gen. DO NOT EDIT.
+
+// This package has the automatically generated fake clientset.
+package fake
@@ -1,11 +1,25 @@
-// SPDX-License-Identifier: Apache-2.0
-// Copyright (c) 2020 Intel Corporation
+/*
+Copyright The Kubernetes Authors.
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
 // Code generated by client-gen. DO NOT EDIT.
 
 package fake
 
 import (
-       k8spluginv1alpha1 "github.com/open-ness/EMCO/src/monitor/pkg/apis/k8splugin/v1alpha1"
+       k8spluginv1alpha1 "gitlab.com/project-emco/core/emco-base/src/monitor/pkg/apis/k8splugin/v1alpha1"
 
        v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
        runtime "k8s.io/apimachinery/pkg/runtime"
diff --git a/central-controller/src/monitor/pkg/client/clientset/versioned/scheme/doc.go b/central-controller/src/monitor/pkg/client/clientset/versioned/scheme/doc.go
new file mode 100644 (file)
index 0000000..7dc3756
--- /dev/null
@@ -0,0 +1,20 @@
+/*
+Copyright The Kubernetes Authors.
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+// Code generated by client-gen. DO NOT EDIT.
+
+// This package contains the scheme of the automatically generated clientset.
+package scheme
@@ -1,11 +1,25 @@
-// SPDX-License-Identifier: Apache-2.0
-// Copyright (c) 2020 Intel Corporation
+/*
+Copyright The Kubernetes Authors.
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
 // Code generated by client-gen. DO NOT EDIT.
 
 package scheme
 
 import (
-       k8spluginv1alpha1 "github.com/open-ness/EMCO/src/monitor/pkg/apis/k8splugin/v1alpha1"
+       k8spluginv1alpha1 "gitlab.com/project-emco/core/emco-base/src/monitor/pkg/apis/k8splugin/v1alpha1"
 
        v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
        runtime "k8s.io/apimachinery/pkg/runtime"
diff --git a/central-controller/src/monitor/pkg/client/clientset/versioned/typed/k8splugin/v1alpha1/doc.go b/central-controller/src/monitor/pkg/client/clientset/versioned/typed/k8splugin/v1alpha1/doc.go
new file mode 100644 (file)
index 0000000..df51baa
--- /dev/null
@@ -0,0 +1,20 @@
+/*
+Copyright The Kubernetes Authors.
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+// Code generated by client-gen. DO NOT EDIT.
+
+// This package has the automatically generated typed clients.
+package v1alpha1
diff --git a/central-controller/src/monitor/pkg/client/clientset/versioned/typed/k8splugin/v1alpha1/fake/doc.go b/central-controller/src/monitor/pkg/client/clientset/versioned/typed/k8splugin/v1alpha1/fake/doc.go
new file mode 100644 (file)
index 0000000..16f4439
--- /dev/null
@@ -0,0 +1,20 @@
+/*
+Copyright The Kubernetes Authors.
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+// Code generated by client-gen. DO NOT EDIT.
+
+// Package fake has the automatically generated clients.
+package fake
diff --git a/central-controller/src/monitor/pkg/client/clientset/versioned/typed/k8splugin/v1alpha1/fake/fake_k8splugin_client.go b/central-controller/src/monitor/pkg/client/clientset/versioned/typed/k8splugin/v1alpha1/fake/fake_k8splugin_client.go
new file mode 100644 (file)
index 0000000..3a476cd
--- /dev/null
@@ -0,0 +1,41 @@
+/*
+Copyright The Kubernetes Authors.
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+// Code generated by client-gen. DO NOT EDIT.
+
+package fake
+
+import (
+       v1alpha1 "gitlab.com/project-emco/core/emco-base/src/monitor/pkg/client/clientset/versioned/typed/k8splugin/v1alpha1"
+
+       rest "k8s.io/client-go/rest"
+       testing "k8s.io/client-go/testing"
+)
+
+type FakeK8spluginV1alpha1 struct {
+       *testing.Fake
+}
+
+func (c *FakeK8spluginV1alpha1) ResourceBundleStates(namespace string) v1alpha1.ResourceBundleStateInterface {
+       return &FakeResourceBundleStates{c, namespace}
+}
+
+// RESTClient returns a RESTClient that is used to communicate
+// with API server by this client implementation.
+func (c *FakeK8spluginV1alpha1) RESTClient() rest.Interface {
+       var ret *rest.RESTClient
+       return ret
+}
@@ -1,11 +1,25 @@
-// SPDX-License-Identifier: Apache-2.0
-// Copyright (c) 2020 Intel Corporation
+/*
+Copyright The Kubernetes Authors.
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
 // Code generated by client-gen. DO NOT EDIT.
 
 package fake
 
 import (
-       v1alpha1 "github.com/open-ness/EMCO/src/monitor/pkg/apis/k8splugin/v1alpha1"
+       v1alpha1 "gitlab.com/project-emco/core/emco-base/src/monitor/pkg/apis/k8splugin/v1alpha1"
 
        v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
        labels "k8s.io/apimachinery/pkg/labels"
@@ -21,9 +35,9 @@ type FakeResourceBundleStates struct {
        ns   string
 }
 
-var resourcebundlestatesResource = schema.GroupVersionResource{Group: "k8splugin.io", Version: "v1alpha1", Resource: "resourcebundlestates"}
+var resourcebundlestatesResource = schema.GroupVersionResource{Group: "k8splugin", Version: "v1alpha1", Resource: "resourcebundlestates"}
 
-var resourcebundlestatesKind = schema.GroupVersionKind{Group: "k8splugin.io", Version: "v1alpha1", Kind: "ResourceBundleState"}
+var resourcebundlestatesKind = schema.GroupVersionKind{Group: "k8splugin", Version: "v1alpha1", Kind: "ResourceBundleState"}
 
 // Get takes name of the resourceBundleState, and returns the corresponding resourceBundleState object, and an error if there is any.
 func (c *FakeResourceBundleStates) Get(name string, options v1.GetOptions) (result *v1alpha1.ResourceBundleState, err error) {
diff --git a/central-controller/src/monitor/pkg/client/clientset/versioned/typed/k8splugin/v1alpha1/generated_expansion.go b/central-controller/src/monitor/pkg/client/clientset/versioned/typed/k8splugin/v1alpha1/generated_expansion.go
new file mode 100644 (file)
index 0000000..65d65b9
--- /dev/null
@@ -0,0 +1,21 @@
+/*
+Copyright The Kubernetes Authors.
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+// Code generated by client-gen. DO NOT EDIT.
+
+package v1alpha1
+
+type ResourceBundleStateExpansion interface{}
@@ -1,14 +1,27 @@
-// SPDX-License-Identifier: Apache-2.0
-// Copyright (c) 2020 Intel Corporation
+/*
+Copyright The Kubernetes Authors.
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
 // Code generated by client-gen. DO NOT EDIT.
 
 package v1alpha1
 
 import (
-       v1alpha1 "github.com/open-ness/EMCO/src/monitor/pkg/apis/k8splugin/v1alpha1"
-       "github.com/open-ness/EMCO/src/monitor/pkg/generated/clientset/versioned/scheme"
+       v1alpha1 "gitlab.com/project-emco/core/emco-base/src/monitor/pkg/apis/k8splugin/v1alpha1"
+       "gitlab.com/project-emco/core/emco-base/src/monitor/pkg/client/clientset/versioned/scheme"
 
-       //"k8s.io/apimachinery/pkg/runtime/serializer"
        rest "k8s.io/client-go/rest"
 )
 
@@ -17,7 +30,7 @@ type K8spluginV1alpha1Interface interface {
        ResourceBundleStatesGetter
 }
 
-// K8spluginV1alpha1Client is used to interact with features provided by the k8splugin.io group.
+// K8spluginV1alpha1Client is used to interact with features provided by the k8splugin group.
 type K8spluginV1alpha1Client struct {
        restClient rest.Interface
 }
@@ -58,7 +71,6 @@ func setConfigDefaults(config *rest.Config) error {
        gv := v1alpha1.SchemeGroupVersion
        config.GroupVersion = &gv
        config.APIPath = "/apis"
-       //config.NegotiatedSerializer = serializer.DirectCodecFactory{CodecFactory: scheme.Codecs}
        config.NegotiatedSerializer = scheme.Codecs.WithoutConversion()
 
        if config.UserAgent == "" {
@@ -1,5 +1,19 @@
-// SPDX-License-Identifier: Apache-2.0
-// Copyright (c) 2020 Intel Corporation
+/*
+Copyright The Kubernetes Authors.
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
 // Code generated by client-gen. DO NOT EDIT.
 
 package v1alpha1
@@ -8,8 +22,8 @@ import (
        "context"
        "time"
 
-       v1alpha1 "github.com/open-ness/EMCO/src/monitor/pkg/apis/k8splugin/v1alpha1"
-       scheme "github.com/open-ness/EMCO/src/monitor/pkg/generated/clientset/versioned/scheme"
+       v1alpha1 "gitlab.com/project-emco/core/emco-base/src/monitor/pkg/apis/k8splugin/v1alpha1"
+       scheme "gitlab.com/project-emco/core/emco-base/src/monitor/pkg/client/clientset/versioned/scheme"
 
        v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
        types "k8s.io/apimachinery/pkg/types"
@@ -1,13 +1,27 @@
-// SPDX-License-Identifier: Apache-2.0
-// Copyright (c) 2020 Intel Corporation
+/*
+Copyright The Kubernetes Authors.
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
 // Code generated by informer-gen. DO NOT EDIT.
 
 package externalversions
 
 import (
-       versioned "github.com/open-ness/EMCO/src/monitor/pkg/generated/clientset/versioned"
-       internalinterfaces "github.com/open-ness/EMCO/src/monitor/pkg/generated/informers/externalversions/internalinterfaces"
-       k8splugin "github.com/open-ness/EMCO/src/monitor/pkg/generated/informers/externalversions/k8splugin"
+       versioned "gitlab.com/project-emco/core/emco-base/src/monitor/pkg/client/clientset/versioned"
+       internalinterfaces "gitlab.com/project-emco/core/emco-base/src/monitor/pkg/client/informers/externalversions/internalinterfaces"
+       k8splugin "gitlab.com/project-emco/core/emco-base/src/monitor/pkg/client/informers/externalversions/k8splugin"
        reflect "reflect"
        sync "sync"
        time "time"
@@ -1,12 +1,26 @@
-// SPDX-License-Identifier: Apache-2.0
-// Copyright (c) 2020 Intel Corporation
+/*
+Copyright The Kubernetes Authors.
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
 // Code generated by informer-gen. DO NOT EDIT.
 
 package externalversions
 
 import (
        "fmt"
-       v1alpha1 "github.com/open-ness/EMCO/src/monitor/pkg/apis/k8splugin/v1alpha1"
+       v1alpha1 "gitlab.com/project-emco/core/emco-base/src/monitor/pkg/apis/k8splugin/v1alpha1"
 
        schema "k8s.io/apimachinery/pkg/runtime/schema"
        cache "k8s.io/client-go/tools/cache"
@@ -38,7 +52,7 @@ func (f *genericInformer) Lister() cache.GenericLister {
 // TODO extend this to unknown resources with a client pool
 func (f *sharedInformerFactory) ForResource(resource schema.GroupVersionResource) (GenericInformer, error) {
        switch resource {
-       // Group=k8splugin.io, Version=v1alpha1
+       // Group=k8splugin, Version=v1alpha1
        case v1alpha1.SchemeGroupVersion.WithResource("resourcebundlestates"):
                return &genericInformer{resource: resource.GroupResource(), informer: f.K8splugin().V1alpha1().ResourceBundleStates().Informer()}, nil
 
@@ -1,11 +1,25 @@
-// SPDX-License-Identifier: Apache-2.0
-// Copyright (c) 2020 Intel Corporation
+/*
+Copyright The Kubernetes Authors.
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
 // Code generated by informer-gen. DO NOT EDIT.
 
 package internalinterfaces
 
 import (
-       versioned "github.com/open-ness/EMCO/src/monitor/pkg/generated/clientset/versioned"
+       versioned "gitlab.com/project-emco/core/emco-base/src/monitor/pkg/client/clientset/versioned"
        time "time"
 
        v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
@@ -1,12 +1,26 @@
-// SPDX-License-Identifier: Apache-2.0
-// Copyright (c) 2020 Intel Corporation
+/*
+Copyright The Kubernetes Authors.
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
 // Code generated by informer-gen. DO NOT EDIT.
 
 package k8splugin
 
 import (
-       internalinterfaces "github.com/open-ness/EMCO/src/monitor/pkg/generated/informers/externalversions/internalinterfaces"
-       v1alpha1 "github.com/open-ness/EMCO/src/monitor/pkg/generated/informers/externalversions/k8splugin/v1alpha1"
+       internalinterfaces "gitlab.com/project-emco/core/emco-base/src/monitor/pkg/client/informers/externalversions/internalinterfaces"
+       v1alpha1 "gitlab.com/project-emco/core/emco-base/src/monitor/pkg/client/informers/externalversions/k8splugin/v1alpha1"
 )
 
 // Interface provides access to each of this group's versions.
@@ -1,11 +1,25 @@
-// SPDX-License-Identifier: Apache-2.0
-// Copyright (c) 2020 Intel Corporation
+/*
+Copyright The Kubernetes Authors.
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
 // Code generated by informer-gen. DO NOT EDIT.
 
 package v1alpha1
 
 import (
-       internalinterfaces "github.com/open-ness/EMCO/src/monitor/pkg/generated/informers/externalversions/internalinterfaces"
+       internalinterfaces "gitlab.com/project-emco/core/emco-base/src/monitor/pkg/client/informers/externalversions/internalinterfaces"
 )
 
 // Interface provides access to all the informers in this group version.
@@ -1,14 +1,28 @@
-// SPDX-License-Identifier: Apache-2.0
-// Copyright (c) 2020 Intel Corporation
+/*
+Copyright The Kubernetes Authors.
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
 // Code generated by informer-gen. DO NOT EDIT.
 
 package v1alpha1
 
 import (
-       k8spluginv1alpha1 "github.com/open-ness/EMCO/src/monitor/pkg/apis/k8splugin/v1alpha1"
-       versioned "github.com/open-ness/EMCO/src/monitor/pkg/generated/clientset/versioned"
-       internalinterfaces "github.com/open-ness/EMCO/src/monitor/pkg/generated/informers/externalversions/internalinterfaces"
-       v1alpha1 "github.com/open-ness/EMCO/src/monitor/pkg/generated/listers/k8splugin/v1alpha1"
+       k8spluginv1alpha1 "gitlab.com/project-emco/core/emco-base/src/monitor/pkg/apis/k8splugin/v1alpha1"
+       versioned "gitlab.com/project-emco/core/emco-base/src/monitor/pkg/client/clientset/versioned"
+       internalinterfaces "gitlab.com/project-emco/core/emco-base/src/monitor/pkg/client/informers/externalversions/internalinterfaces"
+       v1alpha1 "gitlab.com/project-emco/core/emco-base/src/monitor/pkg/client/listers/k8splugin/v1alpha1"
        time "time"
 
        v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
diff --git a/central-controller/src/monitor/pkg/client/listers/k8splugin/v1alpha1/expansion_generated.go b/central-controller/src/monitor/pkg/client/listers/k8splugin/v1alpha1/expansion_generated.go
new file mode 100644 (file)
index 0000000..677717a
--- /dev/null
@@ -0,0 +1,27 @@
+/*
+Copyright The Kubernetes Authors.
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+// Code generated by lister-gen. DO NOT EDIT.
+
+package v1alpha1
+
+// ResourceBundleStateListerExpansion allows custom methods to be added to
+// ResourceBundleStateLister.
+type ResourceBundleStateListerExpansion interface{}
+
+// ResourceBundleStateNamespaceListerExpansion allows custom methods to be added to
+// ResourceBundleStateNamespaceLister.
+type ResourceBundleStateNamespaceListerExpansion interface{}
@@ -1,11 +1,25 @@
-// SPDX-License-Identifier: Apache-2.0
-// Copyright (c) 2020 Intel Corporation
+/*
+Copyright The Kubernetes Authors.
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
 // Code generated by lister-gen. DO NOT EDIT.
 
 package v1alpha1
 
 import (
-       v1alpha1 "github.com/open-ness/EMCO/src/monitor/pkg/apis/k8splugin/v1alpha1"
+       v1alpha1 "gitlab.com/project-emco/core/emco-base/src/monitor/pkg/apis/k8splugin/v1alpha1"
 
        "k8s.io/apimachinery/pkg/api/errors"
        "k8s.io/apimachinery/pkg/labels"
diff --git a/central-controller/src/monitor/pkg/controller/add_resourcebundlestate.go b/central-controller/src/monitor/pkg/controller/add_resourcebundlestate.go
deleted file mode 100644 (file)
index 9f9f981..0000000
+++ /dev/null
@@ -1,19 +0,0 @@
-package controller
-
-import (
-       "github.com/open-ness/EMCO/src/monitor/pkg/controller/resourcebundlestate"
-)
-
-func init() {
-       AddToManagerFuncs = append(AddToManagerFuncs, resourcebundlestate.Add)
-       AddToManagerFuncs = append(AddToManagerFuncs, resourcebundlestate.AddPodController)
-       AddToManagerFuncs = append(AddToManagerFuncs, resourcebundlestate.AddServiceController)
-       AddToManagerFuncs = append(AddToManagerFuncs, resourcebundlestate.AddConfigMapController)
-       AddToManagerFuncs = append(AddToManagerFuncs, resourcebundlestate.AddDeploymentController)
-       AddToManagerFuncs = append(AddToManagerFuncs, resourcebundlestate.AddSecretController)
-       AddToManagerFuncs = append(AddToManagerFuncs, resourcebundlestate.AddDaemonSetController)
-       AddToManagerFuncs = append(AddToManagerFuncs, resourcebundlestate.AddIngressController)
-       AddToManagerFuncs = append(AddToManagerFuncs, resourcebundlestate.AddJobController)
-       AddToManagerFuncs = append(AddToManagerFuncs, resourcebundlestate.AddStatefulSetController)
-       AddToManagerFuncs = append(AddToManagerFuncs, resourcebundlestate.AddCsrController)
-}
diff --git a/central-controller/src/monitor/pkg/controller/controller.go b/central-controller/src/monitor/pkg/controller/controller.go
deleted file mode 100644 (file)
index 7c069f3..0000000
+++ /dev/null
@@ -1,18 +0,0 @@
-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/central-controller/src/monitor/pkg/controller/resourcebundlestate/configMap_controller.go b/central-controller/src/monitor/pkg/controller/resourcebundlestate/configMap_controller.go
deleted file mode 100644 (file)
index 6b3a052..0000000
+++ /dev/null
@@ -1,180 +0,0 @@
-package resourcebundlestate
-
-import (
-       "context"
-       "log"
-
-       "github.com/open-ness/EMCO/src/monitor/pkg/apis/k8splugin/v1alpha1"
-
-       corev1 "k8s.io/api/core/v1"
-       k8serrors "k8s.io/apimachinery/pkg/api/errors"
-       "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/handler"
-       "sigs.k8s.io/controller-runtime/pkg/manager"
-       "sigs.k8s.io/controller-runtime/pkg/reconcile"
-       "sigs.k8s.io/controller-runtime/pkg/source"
-)
-
-// AddConfigMapController the new controller to the controller manager
-func AddConfigMapController(mgr manager.Manager) error {
-       return addConfigMapController(mgr, newConfigMapReconciler(mgr))
-}
-
-func addConfigMapController(mgr manager.Manager, r *configMapReconciler) error {
-       // Create a new controller
-       c, err := controller.New("ConfigMap-controller", mgr, controller.Options{Reconciler: r})
-       if err != nil {
-               return err
-       }
-
-       // Watch for changes to secondar resource ConfigMaps
-       // Predicate filters Service which don't have the k8splugin label
-       err = c.Watch(&source.Kind{Type: &corev1.ConfigMap{}}, &handler.EnqueueRequestForObject{}, &configMapPredicate{})
-       if err != nil {
-               return err
-       }
-
-       return nil
-}
-
-func newConfigMapReconciler(m manager.Manager) *configMapReconciler {
-       return &configMapReconciler{client: m.GetClient()}
-}
-
-type configMapReconciler struct {
-       client client.Client
-}
-
-// Reconcile implements the loop that will update the ResourceBundleState CR
-// whenever we get any updates from all the ConfigMaps we watch.
-func (r *configMapReconciler) Reconcile(req reconcile.Request) (reconcile.Result, error) {
-       log.Printf("Updating ResourceBundleState for ConfigMap: %+v\n", req)
-
-       cm := &corev1.ConfigMap{}
-       err := r.client.Get(context.TODO(), req.NamespacedName, cm)
-       if err != nil {
-               if k8serrors.IsNotFound(err) {
-                       log.Printf("ConfigMap not found: %+v. Remove from CR if it is stored there.\n", req.NamespacedName)
-                       // Remove the ConfigMap's status from StatusList
-                       // This can happen if we get the DeletionTimeStamp event
-                       // after the ConfigMap has been deleted.
-                       r.deleteConfigMapFromAllCRs(req.NamespacedName)
-                       return reconcile.Result{}, nil
-               }
-               log.Printf("Failed to get ConfigMap: %+v\n", req.NamespacedName)
-               return reconcile.Result{}, err
-       }
-
-       // Find the CRs which track this ConfigMap via the labelselector
-       crSelector := returnLabel(cm.GetLabels())
-       if crSelector == nil {
-               log.Println("We should not be here. The predicate should have filtered this ConfigMap")
-       }
-
-       // Get the CRs which have this label and update them all
-       // Ideally, we will have only one CR, but there is nothing
-       // preventing the creation of multiple.
-       // TODO: Consider using an admission validating webook to prevent multiple
-       rbStatusList := &v1alpha1.ResourceBundleStateList{}
-       err = listResources(r.client, req.Namespace, crSelector, rbStatusList)
-       if err != nil || len(rbStatusList.Items) == 0 {
-               log.Printf("Did not find any CRs tracking this resource\n")
-               return reconcile.Result{}, nil
-       }
-
-       err = r.updateCRs(rbStatusList, cm)
-       if err != nil {
-               // Requeue the update
-               return reconcile.Result{}, err
-       }
-
-       return reconcile.Result{}, nil
-}
-
-// deleteConfigMapFromAllCRs deletes ConfigMap status from all the CRs when the ConfigMap itself has been deleted
-// and we have not handled the updateCRs yet.
-// Since, we don't have the ConfigMap's labels, we need to look at all the CRs in this namespace
-func (r *configMapReconciler) deleteConfigMapFromAllCRs(namespacedName types.NamespacedName) error {
-
-       rbStatusList := &v1alpha1.ResourceBundleStateList{}
-       err := listResources(r.client, namespacedName.Namespace, nil, rbStatusList)
-       if err != nil || len(rbStatusList.Items) == 0 {
-               log.Printf("Did not find any CRs tracking this resource\n")
-               return nil
-       }
-       for _, cr := range rbStatusList.Items {
-               r.deleteFromSingleCR(&cr, namespacedName.Name)
-       }
-
-       return nil
-}
-
-func (r *configMapReconciler) updateCRs(crl *v1alpha1.ResourceBundleStateList, cm *corev1.ConfigMap) error {
-
-       for _, cr := range crl.Items {
-               // ConfigMap is not scheduled for deletion
-               if cm.DeletionTimestamp == nil {
-                       err := r.updateSingleCR(&cr, cm)
-                       if err != nil {
-                               return err
-                       }
-               } else {
-                       // ConfigMap is scheduled for deletion
-                       r.deleteFromSingleCR(&cr, cm.Name)
-               }
-       }
-
-       return nil
-}
-
-func (r *configMapReconciler) deleteFromSingleCR(cr *v1alpha1.ResourceBundleState, name string) error {
-       cr.Status.ResourceCount--
-       length := len(cr.Status.ConfigMapStatuses)
-       for i, rstatus := range cr.Status.ConfigMapStatuses {
-               if rstatus.Name == name {
-                       //Delete that status from the array
-                       cr.Status.ConfigMapStatuses[i] = cr.Status.ConfigMapStatuses[length-1]
-                       cr.Status.ConfigMapStatuses = cr.Status.ConfigMapStatuses[:length-1]
-                       return nil
-               }
-       }
-
-       log.Println("Did not find a status for ConfigMapStatuses in CR")
-       return nil
-}
-
-func (r *configMapReconciler) updateSingleCR(cr *v1alpha1.ResourceBundleState, cm *corev1.ConfigMap) error {
-
-       // Update status after searching for it in the list of resourceStatuses
-       for _, rstatus := range cr.Status.ConfigMapStatuses {
-               // Look for the status if we already have it in the CR
-               if rstatus.Name == cm.Name {
-                       err := r.client.Status().Update(context.TODO(), cr)
-                       if err != nil {
-                               log.Printf("failed to update rbstate: %v\n", err)
-                               return err
-                       }
-                       return nil
-               }
-       }
-
-       // Exited for loop with no status found
-       // Increment the number of tracked resources
-       cr.Status.ResourceCount++
-
-       // Add it to CR
-       cr.Status.ConfigMapStatuses = append(cr.Status.ConfigMapStatuses, corev1.ConfigMap{
-               TypeMeta:   cm.TypeMeta,
-               ObjectMeta: cm.ObjectMeta,
-       })
-
-       err := r.client.Status().Update(context.TODO(), cr)
-       if err != nil {
-               log.Printf("failed to update rbstate: %v\n", err)
-               return err
-       }
-
-       return nil
-}
diff --git a/central-controller/src/monitor/pkg/controller/resourcebundlestate/configMap_predicate.go b/central-controller/src/monitor/pkg/controller/resourcebundlestate/configMap_predicate.go
deleted file mode 100644 (file)
index b9b1773..0000000
+++ /dev/null
@@ -1,44 +0,0 @@
-package resourcebundlestate
-
-import (
-       "sigs.k8s.io/controller-runtime/pkg/event"
-)
-
-type configMapPredicate struct {
-}
-
-func (c *configMapPredicate) Create(evt event.CreateEvent) bool {
-
-       if evt.Meta == nil {
-               return false
-       }
-
-       labels := evt.Meta.GetLabels()
-       return checkLabel(labels)
-}
-
-func (c *configMapPredicate) Delete(evt event.DeleteEvent) bool {
-
-       if evt.Meta == nil {
-               return false
-       }
-
-       labels := evt.Meta.GetLabels()
-       return checkLabel(labels)
-}
-
-func (c *configMapPredicate) Update(evt event.UpdateEvent) bool {
-
-       if evt.MetaNew == nil {
-               return false
-       }
-
-       labels := evt.MetaNew.GetLabels()
-       return checkLabel(labels)
-}
-
-func (c *configMapPredicate) Generic(evt event.GenericEvent) bool {
-
-       labels := evt.Meta.GetLabels()
-       return checkLabel(labels)
-}
diff --git a/central-controller/src/monitor/pkg/controller/resourcebundlestate/controller.go b/central-controller/src/monitor/pkg/controller/resourcebundlestate/controller.go
deleted file mode 100644 (file)
index b3db098..0000000
+++ /dev/null
@@ -1,386 +0,0 @@
-package resourcebundlestate
-
-import (
-       "context"
-       "log"
-
-       "github.com/open-ness/EMCO/src/monitor/pkg/apis/k8splugin/v1alpha1"
-
-       appsv1 "k8s.io/api/apps/v1"
-       v1 "k8s.io/api/batch/v1"
-       certsapi "k8s.io/api/certificates/v1beta1"
-       corev1 "k8s.io/api/core/v1"
-       v1beta1 "k8s.io/api/extensions/v1beta1"
-       k8serrors "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/manager"
-       "sigs.k8s.io/controller-runtime/pkg/reconcile"
-       "sigs.k8s.io/controller-runtime/pkg/source"
-)
-
-// Add the new controller to the controller manager
-func Add(mgr manager.Manager) error {
-       return add(mgr, newReconciler(mgr))
-}
-
-func add(mgr manager.Manager, r *reconciler) error {
-       // Create a new controller
-       c, err := controller.New("ResourceBundleState-controller", mgr, controller.Options{Reconciler: r})
-       if err != nil {
-               return err
-       }
-
-       // Watch for changes to primary resource ResourceBundleState
-       err = c.Watch(&source.Kind{Type: &v1alpha1.ResourceBundleState{}}, &EventHandler{})
-       if err != nil {
-               return err
-       }
-
-       return nil
-}
-
-func newReconciler(m manager.Manager) *reconciler {
-       return &reconciler{client: m.GetClient()}
-}
-
-type reconciler struct {
-       // Stores an array of all the ResourceBundleState
-       crList []v1alpha1.ResourceBundleState
-       client client.Client
-}
-
-// Reconcile implements the loop that will manage the ResourceBundleState CR
-// We only accept CREATE events here and any subsequent changes are ignored.
-func (r *reconciler) Reconcile(req reconcile.Request) (reconcile.Result, error) {
-       log.Printf("Reconciling ResourceBundleState %+v\n", req)
-
-       rbstate := &v1alpha1.ResourceBundleState{}
-       err := r.client.Get(context.TODO(), req.NamespacedName, rbstate)
-       if err != nil {
-               if k8serrors.IsNotFound(err) {
-                       log.Printf("Object not found: %+v. Ignore as it must have been deleted.\n", req.NamespacedName)
-                       return reconcile.Result{}, nil
-               }
-               log.Printf("Failed to get object: %+v\n", req.NamespacedName)
-               return reconcile.Result{}, err
-       }
-
-       err = r.updatePods(rbstate, rbstate.Spec.Selector.MatchLabels)
-       if err != nil {
-               log.Printf("Error adding podstatuses: %v\n", err)
-               return reconcile.Result{}, err
-       }
-
-       err = r.updateServices(rbstate, rbstate.Spec.Selector.MatchLabels)
-       if err != nil {
-               log.Printf("Error adding servicestatuses: %v\n", err)
-               return reconcile.Result{}, err
-       }
-
-       err = r.updateConfigMaps(rbstate, rbstate.Spec.Selector.MatchLabels)
-       if err != nil {
-               log.Printf("Error adding configmapstatuses: %v\n", err)
-               return reconcile.Result{}, err
-       }
-
-       err = r.updateDeployments(rbstate, rbstate.Spec.Selector.MatchLabels)
-       if err != nil {
-               log.Printf("Error adding deploymentstatuses: %v\n", err)
-               return reconcile.Result{}, err
-       }
-
-       err = r.updateSecrets(rbstate, rbstate.Spec.Selector.MatchLabels)
-       if err != nil {
-               log.Printf("Error adding secretstatuses: %v\n", err)
-               return reconcile.Result{}, err
-       }
-
-       err = r.updateDaemonSets(rbstate, rbstate.Spec.Selector.MatchLabels)
-       if err != nil {
-               log.Printf("Error adding daemonSetstatuses: %v\n", err)
-               return reconcile.Result{}, err
-       }
-
-       err = r.updateIngresses(rbstate, rbstate.Spec.Selector.MatchLabels)
-       if err != nil {
-               log.Printf("Error adding ingressStatuses: %v\n", err)
-               return reconcile.Result{}, err
-       }
-
-       err = r.updateJobs(rbstate, rbstate.Spec.Selector.MatchLabels)
-       if err != nil {
-               log.Printf("Error adding jobstatuses: %v\n", err)
-               return reconcile.Result{}, err
-       }
-
-       err = r.updateStatefulSets(rbstate, rbstate.Spec.Selector.MatchLabels)
-       if err != nil {
-               log.Printf("Error adding statefulSetstatuses: %v\n", err)
-               return reconcile.Result{}, err
-       }
-
-       err = r.updateCsrs(rbstate, rbstate.Spec.Selector.MatchLabels)
-       if err != nil {
-               log.Printf("Error adding csrStatuses: %v\n", err)
-               return reconcile.Result{}, err
-       }
-
-       // TODO: Update this based on the statuses of the lower resources
-       rbstate.Status.Ready = false
-       err = r.client.Status().Update(context.TODO(), rbstate)
-       if err != nil {
-               log.Printf("failed to update rbstate: %v\n", err)
-               return reconcile.Result{}, err
-       }
-
-       return reconcile.Result{}, nil
-}
-
-func (r *reconciler) updateServices(rbstate *v1alpha1.ResourceBundleState,
-       selectors map[string]string) error {
-
-       // Update the CR with the Services created as well
-       serviceList := &corev1.ServiceList{}
-       err := listResources(r.client, rbstate.Namespace, selectors, serviceList)
-       if err != nil {
-               log.Printf("Failed to list services: %v", err)
-               return err
-       }
-
-       rbstate.Status.ServiceStatuses = []corev1.Service{}
-
-       for _, svc := range serviceList.Items {
-               resStatus := corev1.Service{
-                       TypeMeta:   svc.TypeMeta,
-                       ObjectMeta: svc.ObjectMeta,
-                       Status:     svc.Status,
-               }
-               rbstate.Status.ServiceStatuses = append(rbstate.Status.ServiceStatuses, resStatus)
-       }
-
-       return nil
-}
-
-func (r *reconciler) updatePods(rbstate *v1alpha1.ResourceBundleState,
-       selectors map[string]string) error {
-
-       // Update the CR with the pods tracked
-       podList := &corev1.PodList{}
-       err := listResources(r.client, rbstate.Namespace, selectors, podList)
-       if err != nil {
-               log.Printf("Failed to list pods: %v", err)
-               return err
-       }
-
-       rbstate.Status.PodStatuses = []corev1.Pod{}
-
-       for _, pod := range podList.Items {
-               resStatus := corev1.Pod{
-                       TypeMeta:   pod.TypeMeta,
-                       ObjectMeta: pod.ObjectMeta,
-                       Status:     pod.Status,
-               }
-               rbstate.Status.PodStatuses = append(rbstate.Status.PodStatuses, resStatus)
-       }
-
-       return nil
-}
-
-func (r *reconciler) updateConfigMaps(rbstate *v1alpha1.ResourceBundleState,
-       selectors map[string]string) error {
-
-       // Update the CR with the ConfigMaps created as well
-       configMapList := &corev1.ConfigMapList{}
-       err := listResources(r.client, rbstate.Namespace, selectors, configMapList)
-       if err != nil {
-               log.Printf("Failed to list configMaps: %v", err)
-               return err
-       }
-
-       rbstate.Status.ConfigMapStatuses = []corev1.ConfigMap{}
-
-       for _, cm := range configMapList.Items {
-               resStatus := corev1.ConfigMap{
-                       TypeMeta:   cm.TypeMeta,
-                       ObjectMeta: cm.ObjectMeta,
-               }
-               rbstate.Status.ConfigMapStatuses = append(rbstate.Status.ConfigMapStatuses, resStatus)
-       }
-
-       return nil
-}
-
-func (r *reconciler) updateDeployments(rbstate *v1alpha1.ResourceBundleState,
-       selectors map[string]string) error {
-
-       // Update the CR with the Deployments created as well
-       deploymentList := &appsv1.DeploymentList{}
-       err := listResources(r.client, rbstate.Namespace, selectors, deploymentList)
-       if err != nil {
-               log.Printf("Failed to list deployments: %v", err)
-               return err
-       }
-
-       rbstate.Status.DeploymentStatuses = []appsv1.Deployment{}
-
-       for _, dep := range deploymentList.Items {
-               resStatus := appsv1.Deployment{
-                       TypeMeta:   dep.TypeMeta,
-                       ObjectMeta: dep.ObjectMeta,
-                       Status:     dep.Status,
-               }
-               rbstate.Status.DeploymentStatuses = append(rbstate.Status.DeploymentStatuses, resStatus)
-       }
-
-       return nil
-}
-
-func (r *reconciler) updateSecrets(rbstate *v1alpha1.ResourceBundleState,
-       selectors map[string]string) error {
-
-       // Update the CR with the Secrets created as well
-       secretList := &corev1.SecretList{}
-       err := listResources(r.client, rbstate.Namespace, selectors, secretList)
-       if err != nil {
-               log.Printf("Failed to list secrets: %v", err)
-               return err
-       }
-
-       rbstate.Status.SecretStatuses = []corev1.Secret{}
-
-       for _, sec := range secretList.Items {
-               resStatus := corev1.Secret{
-                       TypeMeta:   sec.TypeMeta,
-                       ObjectMeta: sec.ObjectMeta,
-               }
-               rbstate.Status.SecretStatuses = append(rbstate.Status.SecretStatuses, resStatus)
-       }
-
-       return nil
-}
-
-func (r *reconciler) updateDaemonSets(rbstate *v1alpha1.ResourceBundleState,
-       selectors map[string]string) error {
-
-       // Update the CR with the DaemonSets created as well
-       daemonSetList := &appsv1.DaemonSetList{}
-       err := listResources(r.client, rbstate.Namespace, selectors, daemonSetList)
-       if err != nil {
-               log.Printf("Failed to list DaemonSets: %v", err)
-               return err
-       }
-
-       rbstate.Status.DaemonSetStatuses = []appsv1.DaemonSet{}
-
-       for _, ds := range daemonSetList.Items {
-               resStatus := appsv1.DaemonSet{
-                       TypeMeta:   ds.TypeMeta,
-                       ObjectMeta: ds.ObjectMeta,
-                       Status:     ds.Status,
-               }
-               rbstate.Status.DaemonSetStatuses = append(rbstate.Status.DaemonSetStatuses, resStatus)
-       }
-
-       return nil
-}
-
-func (r *reconciler) updateIngresses(rbstate *v1alpha1.ResourceBundleState,
-       selectors map[string]string) error {
-
-       // Update the CR with the Ingresses created as well
-       ingressList := &v1beta1.IngressList{}
-       err := listResources(r.client, rbstate.Namespace, selectors, ingressList)
-       if err != nil {
-               log.Printf("Failed to list ingresses: %v", err)
-               return err
-       }
-
-       rbstate.Status.IngressStatuses = []v1beta1.Ingress{}
-
-       for _, ing := range ingressList.Items {
-               resStatus := v1beta1.Ingress{
-                       TypeMeta:   ing.TypeMeta,
-                       ObjectMeta: ing.ObjectMeta,
-                       Status:     ing.Status,
-               }
-               rbstate.Status.IngressStatuses = append(rbstate.Status.IngressStatuses, resStatus)
-       }
-
-       return nil
-}
-
-func (r *reconciler) updateJobs(rbstate *v1alpha1.ResourceBundleState,
-       selectors map[string]string) error {
-
-       // Update the CR with the Services created as well
-       jobList := &v1.JobList{}
-       err := listResources(r.client, rbstate.Namespace, selectors, jobList)
-       if err != nil {
-               log.Printf("Failed to list jobs: %v", err)
-               return err
-       }
-
-       rbstate.Status.JobStatuses = []v1.Job{}
-
-       for _, job := range jobList.Items {
-               resStatus := v1.Job{
-                       TypeMeta:   job.TypeMeta,
-                       ObjectMeta: job.ObjectMeta,
-                       Status:     job.Status,
-               }
-               rbstate.Status.JobStatuses = append(rbstate.Status.JobStatuses, resStatus)
-       }
-
-       return nil
-}
-
-func (r *reconciler) updateStatefulSets(rbstate *v1alpha1.ResourceBundleState,
-       selectors map[string]string) error {
-
-       // Update the CR with the StatefulSets created as well
-       statefulSetList := &appsv1.StatefulSetList{}
-       err := listResources(r.client, rbstate.Namespace, selectors, statefulSetList)
-       if err != nil {
-               log.Printf("Failed to list statefulSets: %v", err)
-               return err
-       }
-
-       rbstate.Status.StatefulSetStatuses = []appsv1.StatefulSet{}
-
-       for _, sfs := range statefulSetList.Items {
-               resStatus := appsv1.StatefulSet{
-                       TypeMeta:   sfs.TypeMeta,
-                       ObjectMeta: sfs.ObjectMeta,
-                       Status:     sfs.Status,
-               }
-               rbstate.Status.StatefulSetStatuses = append(rbstate.Status.StatefulSetStatuses, resStatus)
-       }
-
-       return nil
-}
-
-func (r *reconciler) updateCsrs(rbstate *v1alpha1.ResourceBundleState,
-       selectors map[string]string) error {
-
-       // Update the CR with the csrs tracked
-       csrList := &certsapi.CertificateSigningRequestList{}
-       err := listResources(r.client, "", selectors, csrList)
-       if err != nil {
-               log.Printf("Failed to list csrs: %v", err)
-               return err
-       }
-
-       rbstate.Status.CsrStatuses = []certsapi.CertificateSigningRequest{}
-
-       for _, csr := range csrList.Items {
-               resStatus := certsapi.CertificateSigningRequest{
-                       TypeMeta:   csr.TypeMeta,
-                       ObjectMeta: csr.ObjectMeta,
-                       Status:     csr.Status,
-               }
-               rbstate.Status.CsrStatuses = append(rbstate.Status.CsrStatuses, resStatus)
-       }
-
-       return nil
-}
diff --git a/central-controller/src/monitor/pkg/controller/resourcebundlestate/csr_controller.go b/central-controller/src/monitor/pkg/controller/resourcebundlestate/csr_controller.go
deleted file mode 100644 (file)
index 0a78896..0000000
+++ /dev/null
@@ -1,183 +0,0 @@
-package resourcebundlestate
-
-import (
-       "context"
-       "log"
-
-       "github.com/open-ness/EMCO/src/monitor/pkg/apis/k8splugin/v1alpha1"
-
-       certsapi "k8s.io/api/certificates/v1beta1"
-       k8serrors "k8s.io/apimachinery/pkg/api/errors"
-       "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/handler"
-       "sigs.k8s.io/controller-runtime/pkg/manager"
-       "sigs.k8s.io/controller-runtime/pkg/reconcile"
-       "sigs.k8s.io/controller-runtime/pkg/source"
-)
-
-// AddCsrController the new controller to the controller manager
-func AddCsrController(mgr manager.Manager) error {
-       return addCsrController(mgr, newCsrReconciler(mgr))
-}
-
-func addCsrController(mgr manager.Manager, r *csrReconciler) error {
-       // Create a new controller
-       c, err := controller.New("Csr-controller", mgr, controller.Options{Reconciler: r})
-       if err != nil {
-               return err
-       }
-
-       // Watch for changes to secondary resource Csrs
-       // Predicate filters csrs which don't have the k8splugin label
-       err = c.Watch(&source.Kind{Type: &certsapi.CertificateSigningRequest{}}, &handler.EnqueueRequestForObject{}, &csrPredicate{})
-       if err != nil {
-               return err
-       }
-
-       return nil
-}
-
-func newCsrReconciler(m manager.Manager) *csrReconciler {
-       return &csrReconciler{client: m.GetClient()}
-}
-
-type csrReconciler struct {
-       client client.Client
-}
-
-// Reconcile implements the loop that will update the ResourceBundleState CR
-// whenever we get any updates from all the csrs we watch.
-func (r *csrReconciler) Reconcile(req reconcile.Request) (reconcile.Result, error) {
-       log.Printf("Updating ResourceBundleState for Csr: %+v\n", req)
-
-       csr := &certsapi.CertificateSigningRequest{}
-       err := r.client.Get(context.TODO(), req.NamespacedName, csr)
-       if err != nil {
-               if k8serrors.IsNotFound(err) {
-                       log.Printf("Csr not found: %+v. Remove from CR if it is stored there.\n", req.NamespacedName)
-                       // Remove the Csr's status from StatusList
-                       // This can happen if we get the DeletionTimeStamp event
-                       // after the POD has been deleted.
-                       r.deleteCsrFromAllCRs(req.NamespacedName)
-                       return reconcile.Result{}, nil
-               }
-               log.Printf("Failed to get csr: %+v\n", req.NamespacedName)
-               return reconcile.Result{}, err
-       }
-
-       // Find the CRs which track this csr via the labelselector
-       crSelector := returnLabel(csr.GetLabels())
-       if crSelector == nil {
-               log.Println("We should not be here. The predicate should have filtered this Csr")
-       }
-
-       // Get the CRs which have this label and update them all
-       // Ideally, we will have only one CR, but there is nothing
-       // preventing the creation of multiple.
-       // TODO: Consider using an admission validating webook to prevent multiple
-       rbStatusList := &v1alpha1.ResourceBundleStateList{}
-       err = listClusterResources(r.client, crSelector, rbStatusList)
-       if err != nil || len(rbStatusList.Items) == 0 {
-               log.Printf("Did not find any CRs tracking this resource\n")
-               return reconcile.Result{}, nil
-       }
-
-       err = r.updateCRs(rbStatusList, csr)
-       if err != nil {
-               // Requeue the update
-               return reconcile.Result{}, err
-       }
-
-       return reconcile.Result{}, nil
-}
-
-// deleteCsrFromAllCRs deletes csr status from all the CRs when the POD itself has been deleted
-// and we have not handled the updateCRs yet.
-// Since, we don't have the csr's labels, we need to look at all the CRs in this namespace
-func (r *csrReconciler) deleteCsrFromAllCRs(namespacedName types.NamespacedName) error {
-
-       rbStatusList := &v1alpha1.ResourceBundleStateList{}
-       err := listClusterResources(r.client, nil, rbStatusList)
-       if err != nil || len(rbStatusList.Items) == 0 {
-               log.Printf("Did not find any CRs tracking this resource\n")
-               return nil
-       }
-       for _, cr := range rbStatusList.Items {
-               r.deleteFromSingleCR(&cr, namespacedName.Name)
-       }
-
-       return nil
-}
-
-func (r *csrReconciler) updateCRs(crl *v1alpha1.ResourceBundleStateList, csr *certsapi.CertificateSigningRequest) error {
-
-       for _, cr := range crl.Items {
-               // Csr is not scheduled for deletion
-               if csr.DeletionTimestamp == nil {
-                       err := r.updateSingleCR(&cr, csr)
-                       if err != nil {
-                               return err
-                       }
-               } else {
-                       // Csr is scheduled for deletion
-                       r.deleteFromSingleCR(&cr, csr.Name)
-               }
-       }
-
-       return nil
-}
-
-func (r *csrReconciler) deleteFromSingleCR(cr *v1alpha1.ResourceBundleState, name string) error {
-       cr.Status.ResourceCount--
-       length := len(cr.Status.CsrStatuses)
-       for i, rstatus := range cr.Status.CsrStatuses {
-               if rstatus.Name == name {
-                       //Delete that status from the array
-                       cr.Status.CsrStatuses[i] = cr.Status.CsrStatuses[length-1]
-                       cr.Status.CsrStatuses[length-1] = certsapi.CertificateSigningRequest{}
-                       cr.Status.CsrStatuses = cr.Status.CsrStatuses[:length-1]
-                       return nil
-               }
-       }
-
-       log.Println("Did not find a status for POD in CR")
-       return nil
-}
-
-func (r *csrReconciler) updateSingleCR(cr *v1alpha1.ResourceBundleState, csr *certsapi.CertificateSigningRequest) error {
-
-       // Update status after searching for it in the list of resourceStatuses
-       for i, rstatus := range cr.Status.CsrStatuses {
-               // Look for the status if we already have it in the CR
-               if rstatus.Name == csr.Name {
-                       csr.Status.DeepCopyInto(&cr.Status.CsrStatuses[i].Status)
-                       err := r.client.Status().Update(context.TODO(), cr)
-                       if err != nil {
-                               log.Printf("failed to update rbstate: %v\n", err)
-                               return err
-                       }
-                       return nil
-               }
-       }
-
-       // Exited for loop with no status found
-       // Increment the number of tracked resources
-       cr.Status.ResourceCount++
-
-       // Add it to CR
-       cr.Status.CsrStatuses = append(cr.Status.CsrStatuses, certsapi.CertificateSigningRequest{
-               TypeMeta:   csr.TypeMeta,
-               ObjectMeta: csr.ObjectMeta,
-               Status:     csr.Status,
-       })
-
-       err := r.client.Status().Update(context.TODO(), cr)
-       if err != nil {
-               log.Printf("failed to update rbstate: %v\n", err)
-               return err
-       }
-
-       return nil
-}
diff --git a/central-controller/src/monitor/pkg/controller/resourcebundlestate/csr_predicate.go b/central-controller/src/monitor/pkg/controller/resourcebundlestate/csr_predicate.go
deleted file mode 100644 (file)
index cb83eec..0000000
+++ /dev/null
@@ -1,44 +0,0 @@
-package resourcebundlestate
-
-import (
-       "sigs.k8s.io/controller-runtime/pkg/event"
-)
-
-type csrPredicate struct {
-}
-
-func (p *csrPredicate) Create(evt event.CreateEvent) bool {
-
-       if evt.Meta == nil {
-               return false
-       }
-
-       labels := evt.Meta.GetLabels()
-       return checkLabel(labels)
-}
-
-func (p *csrPredicate) Delete(evt event.DeleteEvent) bool {
-
-       if evt.Meta == nil {
-               return false
-       }
-
-       labels := evt.Meta.GetLabels()
-       return checkLabel(labels)
-}
-
-func (p *csrPredicate) Update(evt event.UpdateEvent) bool {
-
-       if evt.MetaNew == nil {
-               return false
-       }
-
-       labels := evt.MetaNew.GetLabels()
-       return checkLabel(labels)
-}
-
-func (p *csrPredicate) Generic(evt event.GenericEvent) bool {
-
-       labels := evt.Meta.GetLabels()
-       return checkLabel(labels)
-}
diff --git a/central-controller/src/monitor/pkg/controller/resourcebundlestate/daemonSet_controller.go b/central-controller/src/monitor/pkg/controller/resourcebundlestate/daemonSet_controller.go
deleted file mode 100644 (file)
index ec45469..0000000
+++ /dev/null
@@ -1,183 +0,0 @@
-package resourcebundlestate
-
-import (
-       "context"
-       "log"
-
-       "github.com/open-ness/EMCO/src/monitor/pkg/apis/k8splugin/v1alpha1"
-
-       appsv1 "k8s.io/api/apps/v1"
-       k8serrors "k8s.io/apimachinery/pkg/api/errors"
-       "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/handler"
-       "sigs.k8s.io/controller-runtime/pkg/manager"
-       "sigs.k8s.io/controller-runtime/pkg/reconcile"
-       "sigs.k8s.io/controller-runtime/pkg/source"
-)
-
-// AddDaemonSetController the new controller to the controller manager
-func AddDaemonSetController(mgr manager.Manager) error {
-       return addDaemonSetController(mgr, newDaemonSetReconciler(mgr))
-}
-
-func addDaemonSetController(mgr manager.Manager, r *daemonSetReconciler) error {
-       // Create a new controller
-       c, err := controller.New("Daemonset-controller", mgr, controller.Options{Reconciler: r})
-       if err != nil {
-               return err
-       }
-
-       // Watch for changes to secondar resource DaemonSets
-       // Predicate filters DaemonSets which don't have the k8splugin label
-       err = c.Watch(&source.Kind{Type: &appsv1.DaemonSet{}}, &handler.EnqueueRequestForObject{}, &daemonSetPredicate{})
-       if err != nil {
-               return err
-       }
-
-       return nil
-}
-
-func newDaemonSetReconciler(m manager.Manager) *daemonSetReconciler {
-       return &daemonSetReconciler{client: m.GetClient()}
-}
-
-type daemonSetReconciler struct {
-       client client.Client
-}
-
-// Reconcile implements the loop that will update the ResourceBundleState CR
-// whenever we get any updates from all the daemonSets we watch.
-func (r *daemonSetReconciler) Reconcile(req reconcile.Request) (reconcile.Result, error) {
-       log.Printf("Updating ResourceBundleState for DaemonSet: %+v\n", req)
-
-       ds := &appsv1.DaemonSet{}
-       err := r.client.Get(context.TODO(), req.NamespacedName, ds)
-       if err != nil {
-               if k8serrors.IsNotFound(err) {
-                       log.Printf("DaemonSet not found: %+v. Remove from CR if it is stored there.\n", req.NamespacedName)
-                       // Remove the DaemonSet's status from StatusList
-                       // This can happen if we get the DeletionTimeStamp event
-                       // after the DaemonSet has been deleted.
-                       r.deleteDaemonSetFromAllCRs(req.NamespacedName)
-                       return reconcile.Result{}, nil
-               }
-               log.Printf("Failed to get daemonSet: %+v\n", req.NamespacedName)
-               return reconcile.Result{}, err
-       }
-
-       // Find the CRs which track this daemonSet via the labelselector
-       crSelector := returnLabel(ds.GetLabels())
-       if crSelector == nil {
-               log.Println("We should not be here. The predicate should have filtered this DaemonSet")
-       }
-
-       // Get the CRs which have this label and update them all
-       // Ideally, we will have only one CR, but there is nothing
-       // preventing the creation of multiple.
-       // TODO: Consider using an admission validating webook to prevent multiple
-       rbStatusList := &v1alpha1.ResourceBundleStateList{}
-       err = listResources(r.client, req.Namespace, crSelector, rbStatusList)
-       if err != nil || len(rbStatusList.Items) == 0 {
-               log.Printf("Did not find any CRs tracking this resource\n")
-               return reconcile.Result{}, nil
-       }
-
-       err = r.updateCRs(rbStatusList, ds)
-       if err != nil {
-               // Requeue the update
-               return reconcile.Result{}, err
-       }
-
-       return reconcile.Result{}, nil
-}
-
-// deleteDaemonSetFromAllCRs deletes daemonSet status from all the CRs when the DaemonSet itself has been deleted
-// and we have not handled the updateCRs yet.
-// Since, we don't have the daemonSet's labels, we need to look at all the CRs in this namespace
-func (r *daemonSetReconciler) deleteDaemonSetFromAllCRs(namespacedName types.NamespacedName) error {
-
-       rbStatusList := &v1alpha1.ResourceBundleStateList{}
-       err := listResources(r.client, namespacedName.Namespace, nil, rbStatusList)
-       if err != nil || len(rbStatusList.Items) == 0 {
-               log.Printf("Did not find any CRs tracking this resource\n")
-               return nil
-       }
-       for _, cr := range rbStatusList.Items {
-               r.deleteFromSingleCR(&cr, namespacedName.Name)
-       }
-
-       return nil
-}
-
-func (r *daemonSetReconciler) updateCRs(crl *v1alpha1.ResourceBundleStateList, ds *appsv1.DaemonSet) error {
-
-       for _, cr := range crl.Items {
-               // DaemonSet is not scheduled for deletion
-               if ds.DeletionTimestamp == nil {
-                       err := r.updateSingleCR(&cr, ds)
-                       if err != nil {
-                               return err
-                       }
-               } else {
-                       // DaemonSet is scheduled for deletion
-                       r.deleteFromSingleCR(&cr, ds.Name)
-               }
-       }
-
-       return nil
-}
-
-func (r *daemonSetReconciler) deleteFromSingleCR(cr *v1alpha1.ResourceBundleState, name string) error {
-       cr.Status.ResourceCount--
-       length := len(cr.Status.DaemonSetStatuses)
-       for i, rstatus := range cr.Status.DaemonSetStatuses {
-               if rstatus.Name == name {
-                       //Delete that status from the array
-                       cr.Status.DaemonSetStatuses[i] = cr.Status.DaemonSetStatuses[length-1]
-                       cr.Status.DaemonSetStatuses[length-1].Status = appsv1.DaemonSetStatus{}
-                       cr.Status.DaemonSetStatuses = cr.Status.DaemonSetStatuses[:length-1]
-                       return nil
-               }
-       }
-
-       log.Println("Did not find a status for DaemonSet in CR")
-       return nil
-}
-
-func (r *daemonSetReconciler) updateSingleCR(cr *v1alpha1.ResourceBundleState, ds *appsv1.DaemonSet) error {
-
-       // Update status after searching for it in the list of resourceStatuses
-       for i, rstatus := range cr.Status.DaemonSetStatuses {
-               // Look for the status if we already have it in the CR
-               if rstatus.Name == ds.Name {
-                       ds.Status.DeepCopyInto(&cr.Status.DaemonSetStatuses[i].Status)
-                       err := r.client.Status().Update(context.TODO(), cr)
-                       if err != nil {
-                               log.Printf("failed to update rbstate: %v\n", err)
-                               return err
-                       }
-                       return nil
-               }
-       }
-
-       // Exited for loop with no status found
-       // Increment the number of tracked resources
-       cr.Status.ResourceCount++
-
-       // Add it to CR
-       cr.Status.DaemonSetStatuses = append(cr.Status.DaemonSetStatuses, appsv1.DaemonSet{
-               TypeMeta:   ds.TypeMeta,
-               ObjectMeta: ds.ObjectMeta,
-               Status:     ds.Status,
-       })
-
-       err := r.client.Status().Update(context.TODO(), cr)
-       if err != nil {
-               log.Printf("failed to update rbstate: %v\n", err)
-               return err
-       }
-
-       return nil
-}
diff --git a/central-controller/src/monitor/pkg/controller/resourcebundlestate/daemonSet_predicate.go b/central-controller/src/monitor/pkg/controller/resourcebundlestate/daemonSet_predicate.go
deleted file mode 100644 (file)
index 16a8bc5..0000000
+++ /dev/null
@@ -1,44 +0,0 @@
-package resourcebundlestate
-
-import (
-       "sigs.k8s.io/controller-runtime/pkg/event"
-)
-
-type daemonSetPredicate struct {
-}
-
-func (d *daemonSetPredicate) Create(evt event.CreateEvent) bool {
-
-       if evt.Meta == nil {
-               return false
-       }
-
-       labels := evt.Meta.GetLabels()
-       return checkLabel(labels)
-}
-
-func (d *daemonSetPredicate) Delete(evt event.DeleteEvent) bool {
-
-       if evt.Meta == nil {
-               return false
-       }
-
-       labels := evt.Meta.GetLabels()
-       return checkLabel(labels)
-}
-
-func (d *daemonSetPredicate) Update(evt event.UpdateEvent) bool {
-
-       if evt.MetaNew == nil {
-               return false
-       }
-
-       labels := evt.MetaNew.GetLabels()
-       return checkLabel(labels)
-}
-
-func (d *daemonSetPredicate) Generic(evt event.GenericEvent) bool {
-
-       labels := evt.Meta.GetLabels()
-       return checkLabel(labels)
-}
diff --git a/central-controller/src/monitor/pkg/controller/resourcebundlestate/deployment_controller.go b/central-controller/src/monitor/pkg/controller/resourcebundlestate/deployment_controller.go
deleted file mode 100644 (file)
index f5d0862..0000000
+++ /dev/null
@@ -1,183 +0,0 @@
-package resourcebundlestate
-
-import (
-       "context"
-       "log"
-
-       "github.com/open-ness/EMCO/src/monitor/pkg/apis/k8splugin/v1alpha1"
-
-       appsv1 "k8s.io/api/apps/v1"
-       k8serrors "k8s.io/apimachinery/pkg/api/errors"
-       "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/handler"
-       "sigs.k8s.io/controller-runtime/pkg/manager"
-       "sigs.k8s.io/controller-runtime/pkg/reconcile"
-       "sigs.k8s.io/controller-runtime/pkg/source"
-)
-
-// AddDeploymentController the new controller to the controller manager
-func AddDeploymentController(mgr manager.Manager) error {
-       return addDeploymentController(mgr, newDeploymentReconciler(mgr))
-}
-
-func addDeploymentController(mgr manager.Manager, r *deploymentReconciler) error {
-       // Create a new controller
-       c, err := controller.New("Deployment-controller", mgr, controller.Options{Reconciler: r})
-       if err != nil {
-               return err
-       }
-
-       // Watch for changes to secondar resource Deployments
-       // Predicate filters Deployment which don't have the k8splugin label
-       err = c.Watch(&source.Kind{Type: &appsv1.Deployment{}}, &handler.EnqueueRequestForObject{}, &deploymentPredicate{})
-       if err != nil {
-               return err
-       }
-
-       return nil
-}
-
-func newDeploymentReconciler(m manager.Manager) *deploymentReconciler {
-       return &deploymentReconciler{client: m.GetClient()}
-}
-
-type deploymentReconciler struct {
-       client client.Client
-}
-
-// Reconcile implements the loop that will update the ResourceBundleState CR
-// whenever we get any updates from all the deployments we watch.
-func (r *deploymentReconciler) Reconcile(req reconcile.Request) (reconcile.Result, error) {
-       log.Printf("Updating ResourceBundleState for Deployment: %+v\n", req)
-
-       dep := &appsv1.Deployment{}
-       err := r.client.Get(context.TODO(), req.NamespacedName, dep)
-       if err != nil {
-               if k8serrors.IsNotFound(err) {
-                       log.Printf("Deployment not found: %+v. Remove from CR if it is stored there.\n", req.NamespacedName)
-                       // Remove the Deployment's status from StatusList
-                       // This can happen if we get the DeletionTimeStamp event
-                       // after the Deployment has been deleted.
-                       r.deleteDeploymentFromAllCRs(req.NamespacedName)
-                       return reconcile.Result{}, nil
-               }
-               log.Printf("Failed to get deployment: %+v\n", req.NamespacedName)
-               return reconcile.Result{}, err
-       }
-
-       // Find the CRs which track this deployment via the labelselector
-       crSelector := returnLabel(dep.GetLabels())
-       if crSelector == nil {
-               log.Println("We should not be here. The predicate should have filtered this Deployment")
-       }
-
-       // Get the CRs which have this label and update them all
-       // Ideally, we will have only one CR, but there is nothing
-       // preventing the creation of multiple.
-       // TODO: Consider using an admission validating webook to prevent multiple
-       rbStatusList := &v1alpha1.ResourceBundleStateList{}
-       err = listResources(r.client, req.Namespace, crSelector, rbStatusList)
-       if err != nil || len(rbStatusList.Items) == 0 {
-               log.Printf("Did not find any CRs tracking this resource\n")
-               return reconcile.Result{}, nil
-       }
-
-       err = r.updateCRs(rbStatusList, dep)
-       if err != nil {
-               // Requeue the update
-               return reconcile.Result{}, err
-       }
-
-       return reconcile.Result{}, nil
-}
-
-// deleteDeploymentFromAllCRs deletes deployment status from all the CRs when the Deployment itself has been deleted
-// and we have not handled the updateCRs yet.
-// Since, we don't have the deployment's labels, we need to look at all the CRs in this namespace
-func (r *deploymentReconciler) deleteDeploymentFromAllCRs(namespacedName types.NamespacedName) error {
-
-       rbStatusList := &v1alpha1.ResourceBundleStateList{}
-       err := listResources(r.client, namespacedName.Namespace, nil, rbStatusList)
-       if err != nil || len(rbStatusList.Items) == 0 {
-               log.Printf("Did not find any CRs tracking this resource\n")
-               return nil
-       }
-       for _, cr := range rbStatusList.Items {
-               r.deleteFromSingleCR(&cr, namespacedName.Name)
-       }
-
-       return nil
-}
-
-func (r *deploymentReconciler) updateCRs(crl *v1alpha1.ResourceBundleStateList, dep *appsv1.Deployment) error {
-
-       for _, cr := range crl.Items {
-               // Deployment is not scheduled for deletion
-               if dep.DeletionTimestamp == nil {
-                       err := r.updateSingleCR(&cr, dep)
-                       if err != nil {
-                               return err
-                       }
-               } else {
-                       // Deployment is scheduled for deletion
-                       r.deleteFromSingleCR(&cr, dep.Name)
-               }
-       }
-
-       return nil
-}
-
-func (r *deploymentReconciler) deleteFromSingleCR(cr *v1alpha1.ResourceBundleState, name string) error {
-       cr.Status.ResourceCount--
-       length := len(cr.Status.DeploymentStatuses)
-       for i, rstatus := range cr.Status.DeploymentStatuses {
-               if rstatus.Name == name {
-                       //Delete that status from the array
-                       cr.Status.DeploymentStatuses[i] = cr.Status.DeploymentStatuses[length-1]
-                       cr.Status.DeploymentStatuses[length-1].Status = appsv1.DeploymentStatus{}
-                       cr.Status.DeploymentStatuses = cr.Status.DeploymentStatuses[:length-1]
-                       return nil
-               }
-       }
-
-       log.Println("Did not find a status for Deployment in CR")
-       return nil
-}
-
-func (r *deploymentReconciler) updateSingleCR(cr *v1alpha1.ResourceBundleState, dep *appsv1.Deployment) error {
-
-       // Update status after searching for it in the list of resourceStatuses
-       for i, rstatus := range cr.Status.DeploymentStatuses {
-               // Look for the status if we already have it in the CR
-               if rstatus.Name == dep.Name {
-                       dep.Status.DeepCopyInto(&cr.Status.DeploymentStatuses[i].Status)
-                       err := r.client.Status().Update(context.TODO(), cr)
-                       if err != nil {
-                               log.Printf("failed to update rbstate: %v\n", err)
-                               return err
-                       }
-                       return nil
-               }
-       }
-
-       // Exited for loop with no status found
-       // Increment the number of tracked resources
-       cr.Status.ResourceCount++
-
-       // Add it to CR
-       cr.Status.DeploymentStatuses = append(cr.Status.DeploymentStatuses, appsv1.Deployment{
-               TypeMeta:   dep.TypeMeta,
-               ObjectMeta: dep.ObjectMeta,
-               Status:     dep.Status,
-       })
-
-       err := r.client.Status().Update(context.TODO(), cr)
-       if err != nil {
-               log.Printf("failed to update rbstate: %v\n", err)
-               return err
-       }
-
-       return nil
-}
diff --git a/central-controller/src/monitor/pkg/controller/resourcebundlestate/deployment_predicate.go b/central-controller/src/monitor/pkg/controller/resourcebundlestate/deployment_predicate.go
deleted file mode 100644 (file)
index 6061e93..0000000
+++ /dev/null
@@ -1,44 +0,0 @@
-package resourcebundlestate
-
-import (
-       "sigs.k8s.io/controller-runtime/pkg/event"
-)
-
-type deploymentPredicate struct {
-}
-
-func (d *deploymentPredicate) Create(evt event.CreateEvent) bool {
-
-       if evt.Meta == nil {
-               return false
-       }
-
-       labels := evt.Meta.GetLabels()
-       return checkLabel(labels)
-}
-
-func (d *deploymentPredicate) Delete(evt event.DeleteEvent) bool {
-
-       if evt.Meta == nil {
-               return false
-       }
-
-       labels := evt.Meta.GetLabels()
-       return checkLabel(labels)
-}
-
-func (d *deploymentPredicate) Update(evt event.UpdateEvent) bool {
-
-       if evt.MetaNew == nil {
-               return false
-       }
-
-       labels := evt.MetaNew.GetLabels()
-       return checkLabel(labels)
-}
-
-func (d *deploymentPredicate) Generic(evt event.GenericEvent) bool {
-
-       labels := evt.Meta.GetLabels()
-       return checkLabel(labels)
-}
diff --git a/central-controller/src/monitor/pkg/controller/resourcebundlestate/handler.go b/central-controller/src/monitor/pkg/controller/resourcebundlestate/handler.go
deleted file mode 100644 (file)
index b84af69..0000000
+++ /dev/null
@@ -1,28 +0,0 @@
-package resourcebundlestate
-
-import (
-       "k8s.io/client-go/util/workqueue"
-       "sigs.k8s.io/controller-runtime/pkg/event"
-       "sigs.k8s.io/controller-runtime/pkg/handler"
-)
-
-// EventHandler adds some specific handling for certain types of events
-// related to the ResourceBundleState CR.
-type EventHandler struct {
-       handler.EnqueueRequestForObject
-}
-
-// Delete ignores any delete operations on a ResourceBundleState CR
-func (p *EventHandler) Delete(evt event.DeleteEvent, q workqueue.RateLimitingInterface) {
-       return
-}
-
-// Update ignores any update operations on a ResourceBundleState CR
-func (p *EventHandler) Update(evt event.UpdateEvent, q workqueue.RateLimitingInterface) {
-       return
-}
-
-// Generic ignores any generic operations on a ResourceBundleState CR
-func (p *EventHandler) Generic(evt event.GenericEvent, q workqueue.RateLimitingInterface) {
-       return
-}
diff --git a/central-controller/src/monitor/pkg/controller/resourcebundlestate/helpers.go b/central-controller/src/monitor/pkg/controller/resourcebundlestate/helpers.go
deleted file mode 100644 (file)
index 4d6be37..0000000
+++ /dev/null
@@ -1,63 +0,0 @@
-package resourcebundlestate
-
-import (
-       "context"
-       "log"
-
-       "k8s.io/apimachinery/pkg/labels"
-       "k8s.io/apimachinery/pkg/runtime"
-       "sigs.k8s.io/controller-runtime/pkg/client"
-)
-
-// checkLabel verifies if the expected label exists and returns bool
-func checkLabel(labels map[string]string) bool {
-
-       _, ok := labels["emco/deployment-id"]
-       if !ok {
-               log.Printf("Pod does not have label. Filter it.")
-               return false
-       }
-       return true
-}
-
-// returnLabel verifies if the expected label exists and returns a map
-func returnLabel(labels map[string]string) map[string]string {
-
-       l, ok := labels["emco/deployment-id"]
-       if !ok {
-               log.Printf("Pod does not have label. Filter it.")
-               return nil
-       }
-       return map[string]string{
-               "emco/deployment-id": l,
-       }
-}
-
-// listResources lists resources based on the selectors provided
-// The data is returned in the pointer to the runtime.Object
-// provided as argument.
-func listResources(cli client.Client, namespace string,
-       labelSelector map[string]string, returnData runtime.Object) error {
-
-       listOptions := &client.ListOptions{
-               Namespace:     namespace,
-               LabelSelector: labels.SelectorFromSet(labelSelector),
-       }
-
-       err := cli.List(context.TODO(), returnData, listOptions)
-       if err != nil {
-               log.Printf("Failed to list CRs: %v", err)
-               return err
-       }
-
-       return nil
-}
-
-// listClusterResources lists non-namespace resources based
-// on the selectors provided.
-// The data is returned in the pointer to the runtime.Object
-// provided as argument.
-func listClusterResources(cli client.Client,
-       labelSelector map[string]string, returnData runtime.Object) error {
-       return listResources(cli, "", labelSelector, returnData)
-}
diff --git a/central-controller/src/monitor/pkg/controller/resourcebundlestate/ingress_controller.go b/central-controller/src/monitor/pkg/controller/resourcebundlestate/ingress_controller.go
deleted file mode 100644 (file)
index ee0497b..0000000
+++ /dev/null
@@ -1,183 +0,0 @@
-package resourcebundlestate
-
-import (
-       "context"
-       "log"
-
-       "github.com/open-ness/EMCO/src/monitor/pkg/apis/k8splugin/v1alpha1"
-
-       v1beta1 "k8s.io/api/extensions/v1beta1"
-       k8serrors "k8s.io/apimachinery/pkg/api/errors"
-       "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/handler"
-       "sigs.k8s.io/controller-runtime/pkg/manager"
-       "sigs.k8s.io/controller-runtime/pkg/reconcile"
-       "sigs.k8s.io/controller-runtime/pkg/source"
-)
-
-// AddIngressController the new controller to the controller manager
-func AddIngressController(mgr manager.Manager) error {
-       return addIngressController(mgr, newIngressReconciler(mgr))
-}
-
-func addIngressController(mgr manager.Manager, r *ingressReconciler) error {
-       // Create a new controller
-       c, err := controller.New("Ingress-controller", mgr, controller.Options{Reconciler: r})
-       if err != nil {
-               return err
-       }
-
-       // Watch for changes to secondar resource Ingress
-       // Predicate filters Ingress which don't have the k8splugin label
-       err = c.Watch(&source.Kind{Type: &v1beta1.Ingress{}}, &handler.EnqueueRequestForObject{}, &ingressPredicate{})
-       if err != nil {
-               return err
-       }
-
-       return nil
-}
-
-func newIngressReconciler(m manager.Manager) *ingressReconciler {
-       return &ingressReconciler{client: m.GetClient()}
-}
-
-type ingressReconciler struct {
-       client client.Client
-}
-
-// Reconcile implements the loop that will update the ResourceBundleState CR
-// whenever we get any updates from all the ingress we watch.
-func (r *ingressReconciler) Reconcile(req reconcile.Request) (reconcile.Result, error) {
-       log.Printf("Updating ResourceBundleState for Ingress: %+v\n", req)
-
-       ing := &v1beta1.Ingress{}
-       err := r.client.Get(context.TODO(), req.NamespacedName, ing)
-       if err != nil {
-               if k8serrors.IsNotFound(err) {
-                       log.Printf("Ingress not found: %+v. Remove from CR if it is stored there.\n", req.NamespacedName)
-                       // Remove the Ingress's status from StatusList
-                       // This can happen if we get the DeletionTimeStamp event
-                       // after the Ingress has been deleted.
-                       r.deleteIngressFromAllCRs(req.NamespacedName)
-                       return reconcile.Result{}, nil
-               }
-               log.Printf("Failed to get ingress: %+v\n", req.NamespacedName)
-               return reconcile.Result{}, err
-       }
-
-       // Find the CRs which track this Ingress via the labelselector
-       crSelector := returnLabel(ing.GetLabels())
-       if crSelector == nil {
-               log.Println("We should not be here. The predicate should have filtered this Ingress")
-       }
-
-       // Get the CRs which have this label and update them all
-       // Ideally, we will have only one CR, but there is nothing
-       // preventing the creation of multiple.
-       // TODO: Consider using an admission validating webook to prevent multiple
-       rbStatusList := &v1alpha1.ResourceBundleStateList{}
-       err = listResources(r.client, req.Namespace, crSelector, rbStatusList)
-       if err != nil || len(rbStatusList.Items) == 0 {
-               log.Printf("Did not find any CRs tracking this resource\n")
-               return reconcile.Result{}, nil
-       }
-
-       err = r.updateCRs(rbStatusList, ing)
-       if err != nil {
-               // Requeue the update
-               return reconcile.Result{}, err
-       }
-
-       return reconcile.Result{}, nil
-}
-
-// deleteIngressFromAllCRs deletes ingress status from all the CRs when the Ingress itself has been deleted
-// and we have not handled the updateCRs yet.
-// Since, we don't have the Ingress's labels, we need to look at all the CRs in this namespace
-func (r *ingressReconciler) deleteIngressFromAllCRs(namespacedName types.NamespacedName) error {
-
-       rbStatusList := &v1alpha1.ResourceBundleStateList{}
-       err := listResources(r.client, namespacedName.Namespace, nil, rbStatusList)
-       if err != nil || len(rbStatusList.Items) == 0 {
-               log.Printf("Did not find any CRs tracking this resource\n")
-               return nil
-       }
-       for _, cr := range rbStatusList.Items {
-               r.deleteFromSingleCR(&cr, namespacedName.Name)
-       }
-
-       return nil
-}
-
-func (r *ingressReconciler) updateCRs(crl *v1alpha1.ResourceBundleStateList, ing *v1beta1.Ingress) error {
-
-       for _, cr := range crl.Items {
-               // Ingress is not scheduled for deletion
-               if ing.DeletionTimestamp == nil {
-                       err := r.updateSingleCR(&cr, ing)
-                       if err != nil {
-                               return err
-                       }
-               } else {
-                       // Ingress is scheduled for deletion
-                       r.deleteFromSingleCR(&cr, ing.Name)
-               }
-       }
-
-       return nil
-}
-
-func (r *ingressReconciler) deleteFromSingleCR(cr *v1alpha1.ResourceBundleState, name string) error {
-       cr.Status.ResourceCount--
-       length := len(cr.Status.IngressStatuses)
-       for i, rstatus := range cr.Status.IngressStatuses {
-               if rstatus.Name == name {
-                       //Delete that status from the array
-                       cr.Status.IngressStatuses[i] = cr.Status.IngressStatuses[length-1]
-                       cr.Status.IngressStatuses[length-1].Status = v1beta1.IngressStatus{}
-                       cr.Status.IngressStatuses = cr.Status.IngressStatuses[:length-1]
-                       return nil
-               }
-       }
-
-       log.Println("Did not find a status for Ingress in CR")
-       return nil
-}
-
-func (r *ingressReconciler) updateSingleCR(cr *v1alpha1.ResourceBundleState, ing *v1beta1.Ingress) error {
-
-       // Update status after searching for it in the list of resourceStatuses
-       for i, rstatus := range cr.Status.IngressStatuses {
-               // Look for the status if we already have it in the CR
-               if rstatus.Name == ing.Name {
-                       ing.Status.DeepCopyInto(&cr.Status.IngressStatuses[i].Status)
-                       err := r.client.Status().Update(context.TODO(), cr)
-                       if err != nil {
-                               log.Printf("failed to update rbstate: %v\n", err)
-                               return err
-                       }
-                       return nil
-               }
-       }
-
-       // Exited for loop with no status found
-       // Increment the number of tracked resources
-       cr.Status.ResourceCount++
-
-       // Add it to CR
-       cr.Status.IngressStatuses = append(cr.Status.IngressStatuses, v1beta1.Ingress{
-               TypeMeta:   ing.TypeMeta,
-               ObjectMeta: ing.ObjectMeta,
-               Status:     ing.Status,
-       })
-
-       err := r.client.Status().Update(context.TODO(), cr)
-       if err != nil {
-               log.Printf("failed to update rbstate: %v\n", err)
-               return err
-       }
-
-       return nil
-}
diff --git a/central-controller/src/monitor/pkg/controller/resourcebundlestate/ingress_predicate.go b/central-controller/src/monitor/pkg/controller/resourcebundlestate/ingress_predicate.go
deleted file mode 100644 (file)
index 9a41c84..0000000
+++ /dev/null
@@ -1,44 +0,0 @@
-package resourcebundlestate
-
-import (
-       "sigs.k8s.io/controller-runtime/pkg/event"
-)
-
-type ingressPredicate struct {
-}
-
-func (i *ingressPredicate) Create(evt event.CreateEvent) bool {
-
-       if evt.Meta == nil {
-               return false
-       }
-
-       labels := evt.Meta.GetLabels()
-       return checkLabel(labels)
-}
-
-func (i *ingressPredicate) Delete(evt event.DeleteEvent) bool {
-
-       if evt.Meta == nil {
-               return false
-       }
-
-       labels := evt.Meta.GetLabels()
-       return checkLabel(labels)
-}
-
-func (i *ingressPredicate) Update(evt event.UpdateEvent) bool {
-
-       if evt.MetaNew == nil {
-               return false
-       }
-
-       labels := evt.MetaNew.GetLabels()
-       return checkLabel(labels)
-}
-
-func (i *ingressPredicate) Generic(evt event.GenericEvent) bool {
-
-       labels := evt.Meta.GetLabels()
-       return checkLabel(labels)
-}
diff --git a/central-controller/src/monitor/pkg/controller/resourcebundlestate/job_controller.go b/central-controller/src/monitor/pkg/controller/resourcebundlestate/job_controller.go
deleted file mode 100644 (file)
index 533810c..0000000
+++ /dev/null
@@ -1,183 +0,0 @@
-package resourcebundlestate
-
-import (
-       "context"
-       "log"
-
-       "github.com/open-ness/EMCO/src/monitor/pkg/apis/k8splugin/v1alpha1"
-
-       v1 "k8s.io/api/batch/v1"
-       k8serrors "k8s.io/apimachinery/pkg/api/errors"
-       "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/handler"
-       "sigs.k8s.io/controller-runtime/pkg/manager"
-       "sigs.k8s.io/controller-runtime/pkg/reconcile"
-       "sigs.k8s.io/controller-runtime/pkg/source"
-)
-
-// AddJobController the new controller to the controller manager
-func AddJobController(mgr manager.Manager) error {
-       return addJobController(mgr, newJobReconciler(mgr))
-}
-
-func addJobController(mgr manager.Manager, r *jobReconciler) error {
-       // Create a new controller
-       c, err := controller.New("Job-controller", mgr, controller.Options{Reconciler: r})
-       if err != nil {
-               return err
-       }
-
-       // Watch for changes to secondar resource Jobs
-       // Predicate filters Job which don't have the k8splugin label
-       err = c.Watch(&source.Kind{Type: &v1.Job{}}, &handler.EnqueueRequestForObject{}, &jobPredicate{})
-       if err != nil {
-               return err
-       }
-
-       return nil
-}
-
-func newJobReconciler(m manager.Manager) *jobReconciler {
-       return &jobReconciler{client: m.GetClient()}
-}
-
-type jobReconciler struct {
-       client client.Client
-}
-
-// Reconcile implements the loop that will update the ResourceBundleState CR
-// whenever we get any updates from all the jobs we watch.
-func (r *jobReconciler) Reconcile(req reconcile.Request) (reconcile.Result, error) {
-       log.Printf("Updating ResourceBundleState for Job: %+v\n", req)
-
-       job := &v1.Job{}
-       err := r.client.Get(context.TODO(), req.NamespacedName, job)
-       if err != nil {
-               if k8serrors.IsNotFound(err) {
-                       log.Printf("Job not found: %+v. Remove from CR if it is stored there.\n", req.NamespacedName)
-                       // Remove the Job's status from StatusList
-                       // This can happen if we get the DeletionTimeStamp event
-                       // after the Job has been deleted.
-                       r.deleteJobFromAllCRs(req.NamespacedName)
-                       return reconcile.Result{}, nil
-               }
-               log.Printf("Failed to get Job: %+v\n", req.NamespacedName)
-               return reconcile.Result{}, err
-       }
-
-       // Find the CRs which track this Job via the labelselector
-       crSelector := returnLabel(job.GetLabels())
-       if crSelector == nil {
-               log.Println("We should not be here. The predicate should have filtered this Job")
-       }
-
-       // Get the CRs which have this label and update them all
-       // Ideally, we will have only one CR, but there is nothing
-       // preventing the creation of multiple.
-       // TODO: Consider using an admission validating webook to prevent multiple
-       rbStatusList := &v1alpha1.ResourceBundleStateList{}
-       err = listResources(r.client, req.Namespace, crSelector, rbStatusList)
-       if err != nil || len(rbStatusList.Items) == 0 {
-               log.Printf("Did not find any CRs tracking this resource\n")
-               return reconcile.Result{}, nil
-       }
-
-       err = r.updateCRs(rbStatusList, job)
-       if err != nil {
-               // Requeue the update
-               return reconcile.Result{}, err
-       }
-
-       return reconcile.Result{}, nil
-}
-
-// deleteJobFromAllCRs deletes job status from all the CRs when the Job itself has been deleted
-// and we have not handled the updateCRs yet.
-// Since, we don't have the job's labels, we need to look at all the CRs in this namespace
-func (r *jobReconciler) deleteJobFromAllCRs(namespacedName types.NamespacedName) error {
-
-       rbStatusList := &v1alpha1.ResourceBundleStateList{}
-       err := listResources(r.client, namespacedName.Namespace, nil, rbStatusList)
-       if err != nil || len(rbStatusList.Items) == 0 {
-               log.Printf("Did not find any CRs tracking this resource\n")
-               return nil
-       }
-       for _, cr := range rbStatusList.Items {
-               r.deleteFromSingleCR(&cr, namespacedName.Name)
-       }
-
-       return nil
-}
-
-func (r *jobReconciler) updateCRs(crl *v1alpha1.ResourceBundleStateList, job *v1.Job) error {
-
-       for _, cr := range crl.Items {
-               // Job is not scheduled for deletion
-               if job.DeletionTimestamp == nil {
-                       err := r.updateSingleCR(&cr, job)
-                       if err != nil {
-                               return err
-                       }
-               } else {
-                       // Job is scheduled for deletion
-                       r.deleteFromSingleCR(&cr, job.Name)
-               }
-       }
-
-       return nil
-}
-
-func (r *jobReconciler) deleteFromSingleCR(cr *v1alpha1.ResourceBundleState, name string) error {
-       cr.Status.ResourceCount--
-       length := len(cr.Status.JobStatuses)
-       for i, rstatus := range cr.Status.JobStatuses {
-               if rstatus.Name == name {
-                       //Delete that status from the array
-                       cr.Status.JobStatuses[i] = cr.Status.JobStatuses[length-1]
-                       cr.Status.JobStatuses[length-1].Status = v1.JobStatus{}
-                       cr.Status.JobStatuses = cr.Status.JobStatuses[:length-1]
-                       return nil
-               }
-       }
-
-       log.Println("Did not find a status for Job in CR")
-       return nil
-}
-
-func (r *jobReconciler) updateSingleCR(cr *v1alpha1.ResourceBundleState, job *v1.Job) error {
-
-       // Update status after searching for it in the list of resourceStatuses
-       for i, rstatus := range cr.Status.JobStatuses {
-               // Look for the status if we already have it in the CR
-               if rstatus.Name == job.Name {
-                       job.Status.DeepCopyInto(&cr.Status.JobStatuses[i].Status)
-                       err := r.client.Status().Update(context.TODO(), cr)
-                       if err != nil {
-                               log.Printf("failed to update rbstate: %v\n", err)
-                               return err
-                       }
-                       return nil
-               }
-       }
-
-       // Exited for loop with no status found
-       // Increment the number of tracked resources
-       cr.Status.ResourceCount++
-
-       // Add it to CR
-       cr.Status.JobStatuses = append(cr.Status.JobStatuses, v1.Job{
-               TypeMeta:   job.TypeMeta,
-               ObjectMeta: job.ObjectMeta,
-               Status:     job.Status,
-       })
-
-       err := r.client.Status().Update(context.TODO(), cr)
-       if err != nil {
-               log.Printf("failed to update rbstate: %v\n", err)
-               return err
-       }
-
-       return nil
-}
diff --git a/central-controller/src/monitor/pkg/controller/resourcebundlestate/job_predicate.go b/central-controller/src/monitor/pkg/controller/resourcebundlestate/job_predicate.go
deleted file mode 100644 (file)
index 1484153..0000000
+++ /dev/null
@@ -1,44 +0,0 @@
-package resourcebundlestate
-
-import (
-       "sigs.k8s.io/controller-runtime/pkg/event"
-)
-
-type jobPredicate struct {
-}
-
-func (j *jobPredicate) Create(evt event.CreateEvent) bool {
-
-       if evt.Meta == nil {
-               return false
-       }
-
-       labels := evt.Meta.GetLabels()
-       return checkLabel(labels)
-}
-
-func (j *jobPredicate) Delete(evt event.DeleteEvent) bool {
-
-       if evt.Meta == nil {
-               return false
-       }
-
-       labels := evt.Meta.GetLabels()
-       return checkLabel(labels)
-}
-
-func (j *jobPredicate) Update(evt event.UpdateEvent) bool {
-
-       if evt.MetaNew == nil {
-               return false
-       }
-
-       labels := evt.MetaNew.GetLabels()
-       return checkLabel(labels)
-}
-
-func (j *jobPredicate) Generic(evt event.GenericEvent) bool {
-
-       labels := evt.Meta.GetLabels()
-       return checkLabel(labels)
-}
diff --git a/central-controller/src/monitor/pkg/controller/resourcebundlestate/pod_controller.go b/central-controller/src/monitor/pkg/controller/resourcebundlestate/pod_controller.go
deleted file mode 100644 (file)
index 96d417c..0000000
+++ /dev/null
@@ -1,183 +0,0 @@
-package resourcebundlestate
-
-import (
-       "context"
-       "log"
-
-       "github.com/open-ness/EMCO/src/monitor/pkg/apis/k8splugin/v1alpha1"
-
-       corev1 "k8s.io/api/core/v1"
-       k8serrors "k8s.io/apimachinery/pkg/api/errors"
-       "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/handler"
-       "sigs.k8s.io/controller-runtime/pkg/manager"
-       "sigs.k8s.io/controller-runtime/pkg/reconcile"
-       "sigs.k8s.io/controller-runtime/pkg/source"
-)
-
-// AddPodController the new controller to the controller manager
-func AddPodController(mgr manager.Manager) error {
-       return addPodController(mgr, newPodReconciler(mgr))
-}
-
-func addPodController(mgr manager.Manager, r *podReconciler) error {
-       // Create a new controller
-       c, err := controller.New("Pod-controller", mgr, controller.Options{Reconciler: r})
-       if err != nil {
-               return err
-       }
-
-       // Watch for changes to secondar resource Pods
-       // Predicate filters pods which don't have the k8splugin label
-       err = c.Watch(&source.Kind{Type: &corev1.Pod{}}, &handler.EnqueueRequestForObject{}, &podPredicate{})
-       if err != nil {
-               return err
-       }
-
-       return nil
-}
-
-func newPodReconciler(m manager.Manager) *podReconciler {
-       return &podReconciler{client: m.GetClient()}
-}
-
-type podReconciler struct {
-       client client.Client
-}
-
-// Reconcile implements the loop that will update the ResourceBundleState CR
-// whenever we get any updates from all the pods we watch.
-func (r *podReconciler) Reconcile(req reconcile.Request) (reconcile.Result, error) {
-       log.Printf("Updating ResourceBundleState for Pod: %+v\n", req)
-
-       pod := &corev1.Pod{}
-       err := r.client.Get(context.TODO(), req.NamespacedName, pod)
-       if err != nil {
-               if k8serrors.IsNotFound(err) {
-                       log.Printf("Pod not found: %+v. Remove from CR if it is stored there.\n", req.NamespacedName)
-                       // Remove the Pod's status from StatusList
-                       // This can happen if we get the DeletionTimeStamp event
-                       // after the POD has been deleted.
-                       r.deletePodFromAllCRs(req.NamespacedName)
-                       return reconcile.Result{}, nil
-               }
-               log.Printf("Failed to get pod: %+v\n", req.NamespacedName)
-               return reconcile.Result{}, err
-       }
-
-       // Find the CRs which track this pod via the labelselector
-       crSelector := returnLabel(pod.GetLabels())
-       if crSelector == nil {
-               log.Println("We should not be here. The predicate should have filtered this Pod")
-       }
-
-       // Get the CRs which have this label and update them all
-       // Ideally, we will have only one CR, but there is nothing
-       // preventing the creation of multiple.
-       // TODO: Consider using an admission validating webook to prevent multiple
-       rbStatusList := &v1alpha1.ResourceBundleStateList{}
-       err = listResources(r.client, req.Namespace, crSelector, rbStatusList)
-       if err != nil || len(rbStatusList.Items) == 0 {
-               log.Printf("Did not find any CRs tracking this resource\n")
-               return reconcile.Result{}, nil
-       }
-
-       err = r.updateCRs(rbStatusList, pod)
-       if err != nil {
-               // Requeue the update
-               return reconcile.Result{}, err
-       }
-
-       return reconcile.Result{}, nil
-}
-
-// deletePodFromAllCRs deletes pod status from all the CRs when the POD itself has been deleted
-// and we have not handled the updateCRs yet.
-// Since, we don't have the pod's labels, we need to look at all the CRs in this namespace
-func (r *podReconciler) deletePodFromAllCRs(namespacedName types.NamespacedName) error {
-
-       rbStatusList := &v1alpha1.ResourceBundleStateList{}
-       err := listResources(r.client, namespacedName.Namespace, nil, rbStatusList)
-       if err != nil || len(rbStatusList.Items) == 0 {
-               log.Printf("Did not find any CRs tracking this resource\n")
-               return nil
-       }
-       for _, cr := range rbStatusList.Items {
-               r.deleteFromSingleCR(&cr, namespacedName.Name)
-       }
-
-       return nil
-}
-
-func (r *podReconciler) updateCRs(crl *v1alpha1.ResourceBundleStateList, pod *corev1.Pod) error {
-
-       for _, cr := range crl.Items {
-               // Pod is not scheduled for deletion
-               if pod.DeletionTimestamp == nil {
-                       err := r.updateSingleCR(&cr, pod)
-                       if err != nil {
-                               return err
-                       }
-               } else {
-                       // Pod is scheduled for deletion
-                       r.deleteFromSingleCR(&cr, pod.Name)
-               }
-       }
-
-       return nil
-}
-
-func (r *podReconciler) deleteFromSingleCR(cr *v1alpha1.ResourceBundleState, name string) error {
-       cr.Status.ResourceCount--
-       length := len(cr.Status.PodStatuses)
-       for i, rstatus := range cr.Status.PodStatuses {
-               if rstatus.Name == name {
-                       //Delete that status from the array
-                       cr.Status.PodStatuses[i] = cr.Status.PodStatuses[length-1]
-                       cr.Status.PodStatuses[length-1] = corev1.Pod{}
-                       cr.Status.PodStatuses = cr.Status.PodStatuses[:length-1]
-                       return nil
-               }
-       }
-
-       log.Println("Did not find a status for POD in CR")
-       return nil
-}
-
-func (r *podReconciler) updateSingleCR(cr *v1alpha1.ResourceBundleState, pod *corev1.Pod) error {
-
-       // Update status after searching for it in the list of resourceStatuses
-       for i, rstatus := range cr.Status.PodStatuses {
-               // Look for the status if we already have it in the CR
-               if rstatus.Name == pod.Name {
-                       pod.Status.DeepCopyInto(&cr.Status.PodStatuses[i].Status)
-                       err := r.client.Status().Update(context.TODO(), cr)
-                       if err != nil {
-                               log.Printf("failed to update rbstate: %v\n", err)
-                               return err
-                       }
-                       return nil
-               }
-       }
-
-       // Exited for loop with no status found
-       // Increment the number of tracked resources
-       cr.Status.ResourceCount++
-
-       // Add it to CR
-       cr.Status.PodStatuses = append(cr.Status.PodStatuses, corev1.Pod{
-               TypeMeta:   pod.TypeMeta,
-               ObjectMeta: pod.ObjectMeta,
-               Status:     pod.Status,
-       })
-
-       err := r.client.Status().Update(context.TODO(), cr)
-       if err != nil {
-               log.Printf("failed to update rbstate: %v\n", err)
-               return err
-       }
-
-       return nil
-}
diff --git a/central-controller/src/monitor/pkg/controller/resourcebundlestate/pod_predicate.go b/central-controller/src/monitor/pkg/controller/resourcebundlestate/pod_predicate.go
deleted file mode 100644 (file)
index f1c1960..0000000
+++ /dev/null
@@ -1,44 +0,0 @@
-package resourcebundlestate
-
-import (
-       "sigs.k8s.io/controller-runtime/pkg/event"
-)
-
-type podPredicate struct {
-}
-
-func (p *podPredicate) Create(evt event.CreateEvent) bool {
-
-       if evt.Meta == nil {
-               return false
-       }
-
-       labels := evt.Meta.GetLabels()
-       return checkLabel(labels)
-}
-
-func (p *podPredicate) Delete(evt event.DeleteEvent) bool {
-
-       if evt.Meta == nil {
-               return false
-       }
-
-       labels := evt.Meta.GetLabels()
-       return checkLabel(labels)
-}
-
-func (p *podPredicate) Update(evt event.UpdateEvent) bool {
-
-       if evt.MetaNew == nil {
-               return false
-       }
-
-       labels := evt.MetaNew.GetLabels()
-       return checkLabel(labels)
-}
-
-func (p *podPredicate) Generic(evt event.GenericEvent) bool {
-
-       labels := evt.Meta.GetLabels()
-       return checkLabel(labels)
-}
diff --git a/central-controller/src/monitor/pkg/controller/resourcebundlestate/secret_controller.go b/central-controller/src/monitor/pkg/controller/resourcebundlestate/secret_controller.go
deleted file mode 100644 (file)
index a097e2f..0000000
+++ /dev/null
@@ -1,180 +0,0 @@
-package resourcebundlestate
-
-import (
-       "context"
-       "log"
-
-       "github.com/open-ness/EMCO/src/monitor/pkg/apis/k8splugin/v1alpha1"
-
-       corev1 "k8s.io/api/core/v1"
-       k8serrors "k8s.io/apimachinery/pkg/api/errors"
-       "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/handler"
-       "sigs.k8s.io/controller-runtime/pkg/manager"
-       "sigs.k8s.io/controller-runtime/pkg/reconcile"
-       "sigs.k8s.io/controller-runtime/pkg/source"
-)
-
-// AddSecretController the new controller to the controller manager
-func AddSecretController(mgr manager.Manager) error {
-       return addSecretController(mgr, newSecretReconciler(mgr))
-}
-
-func addSecretController(mgr manager.Manager, r *secretReconciler) error {
-       // Create a new controller
-       c, err := controller.New("Secret-controller", mgr, controller.Options{Reconciler: r})
-       if err != nil {
-               return err
-       }
-
-       // Watch for changes to secondar resource Secret
-       // Predicate filters Secret which don't have the k8splugin label
-       err = c.Watch(&source.Kind{Type: &corev1.Secret{}}, &handler.EnqueueRequestForObject{}, &secretPredicate{})
-       if err != nil {
-               return err
-       }
-
-       return nil
-}
-
-func newSecretReconciler(m manager.Manager) *secretReconciler {
-       return &secretReconciler{client: m.GetClient()}
-}
-
-type secretReconciler struct {
-       client client.Client
-}
-
-// Reconcile implements the loop that will update the ResourceBundleState CR
-// whenever we get any updates from all the Secrets we watch.
-func (r *secretReconciler) Reconcile(req reconcile.Request) (reconcile.Result, error) {
-       log.Printf("Updating ResourceBundleState for Secret: %+v\n", req)
-
-       sec := &corev1.Secret{}
-       err := r.client.Get(context.TODO(), req.NamespacedName, sec)
-       if err != nil {
-               if k8serrors.IsNotFound(err) {
-                       log.Printf("Secret not found: %+v. Remove from CR if it is stored there.\n", req.NamespacedName)
-                       // Remove the Secret's status from StatusList
-                       // This can happen if we get the DeletionTimeStamp event
-                       // after the Secret has been deleted.
-                       r.deleteSecretFromAllCRs(req.NamespacedName)
-                       return reconcile.Result{}, nil
-               }
-               log.Printf("Failed to get Secret: %+v\n", req.NamespacedName)
-               return reconcile.Result{}, err
-       }
-
-       // Find the CRs which track this Secret via the labelselector
-       crSelector := returnLabel(sec.GetLabels())
-       if crSelector == nil {
-               log.Println("We should not be here. The predicate should have filtered this Secret")
-       }
-
-       // Get the CRs which have this label and update them all
-       // Ideally, we will have only one CR, but there is nothing
-       // preventing the creation of multiple.
-       // TODO: Consider using an admission validating webook to prevent multiple
-       rbStatusList := &v1alpha1.ResourceBundleStateList{}
-       err = listResources(r.client, req.Namespace, crSelector, rbStatusList)
-       if err != nil || len(rbStatusList.Items) == 0 {
-               log.Printf("Did not find any CRs tracking this resource\n")
-               return reconcile.Result{}, nil
-       }
-
-       err = r.updateCRs(rbStatusList, sec)
-       if err != nil {
-               // Requeue the update
-               return reconcile.Result{}, err
-       }
-
-       return reconcile.Result{}, nil
-}
-
-// deleteSecretFromAllCRs deletes Secret status from all the CRs when the Secret itself has been deleted
-// and we have not handled the updateCRs yet.
-// Since, we don't have the Secret's labels, we need to look at all the CRs in this namespace
-func (r *secretReconciler) deleteSecretFromAllCRs(namespacedName types.NamespacedName) error {
-
-       rbStatusList := &v1alpha1.ResourceBundleStateList{}
-       err := listResources(r.client, namespacedName.Namespace, nil, rbStatusList)
-       if err != nil || len(rbStatusList.Items) == 0 {
-               log.Printf("Did not find any CRs tracking this resource\n")
-               return nil
-       }
-       for _, cr := range rbStatusList.Items {
-               r.deleteFromSingleCR(&cr, namespacedName.Name)
-       }
-
-       return nil
-}
-
-func (r *secretReconciler) updateCRs(crl *v1alpha1.ResourceBundleStateList, sec *corev1.Secret) error {
-
-       for _, cr := range crl.Items {
-               // Secret is not scheduled for deletion
-               if sec.DeletionTimestamp == nil {
-                       err := r.updateSingleCR(&cr, sec)
-                       if err != nil {
-                               return err
-                       }
-               } else {
-                       // Secret is scheduled for deletion
-                       r.deleteFromSingleCR(&cr, sec.Name)
-               }
-       }
-
-       return nil
-}
-
-func (r *secretReconciler) deleteFromSingleCR(cr *v1alpha1.ResourceBundleState, name string) error {
-       cr.Status.ResourceCount--
-       length := len(cr.Status.SecretStatuses)
-       for i, rstatus := range cr.Status.SecretStatuses {
-               if rstatus.Name == name {
-                       //Delete that status from the array
-                       cr.Status.SecretStatuses[i] = cr.Status.SecretStatuses[length-1]
-                       cr.Status.SecretStatuses = cr.Status.SecretStatuses[:length-1]
-                       return nil
-               }
-       }
-
-       log.Println("Did not find a status for SecretStatuses in CR")
-       return nil
-}
-
-func (r *secretReconciler) updateSingleCR(cr *v1alpha1.ResourceBundleState, sec *corev1.Secret) error {
-
-       // Update status after searching for it in the list of resourceStatuses
-       for _, rstatus := range cr.Status.SecretStatuses {
-               // Look for the status if we already have it in the CR
-               if rstatus.Name == sec.Name {
-                       err := r.client.Status().Update(context.TODO(), cr)
-                       if err != nil {
-                               log.Printf("failed to update rbstate: %v\n", err)
-                               return err
-                       }
-                       return nil
-               }
-       }
-
-       // Exited for loop with no status found
-       // Increment the number of tracked resources
-       cr.Status.ResourceCount++
-
-       // Add it to CR
-       cr.Status.SecretStatuses = append(cr.Status.SecretStatuses, corev1.Secret{
-               TypeMeta:   sec.TypeMeta,
-               ObjectMeta: sec.ObjectMeta,
-       })
-
-       err := r.client.Status().Update(context.TODO(), cr)
-       if err != nil {
-               log.Printf("failed to update rbstate: %v\n", err)
-               return err
-       }
-
-       return nil
-}
diff --git a/central-controller/src/monitor/pkg/controller/resourcebundlestate/secret_predicate.go b/central-controller/src/monitor/pkg/controller/resourcebundlestate/secret_predicate.go
deleted file mode 100644 (file)
index e25e111..0000000
+++ /dev/null
@@ -1,44 +0,0 @@
-package resourcebundlestate
-
-import (
-       "sigs.k8s.io/controller-runtime/pkg/event"
-)
-
-type secretPredicate struct {
-}
-
-func (s *secretPredicate) Create(evt event.CreateEvent) bool {
-
-       if evt.Meta == nil {
-               return false
-       }
-
-       labels := evt.Meta.GetLabels()
-       return checkLabel(labels)
-}
-
-func (s *secretPredicate) Delete(evt event.DeleteEvent) bool {
-
-       if evt.Meta == nil {
-               return false
-       }
-
-       labels := evt.Meta.GetLabels()
-       return checkLabel(labels)
-}
-
-func (s *secretPredicate) Update(evt event.UpdateEvent) bool {
-
-       if evt.MetaNew == nil {
-               return false
-       }
-
-       labels := evt.MetaNew.GetLabels()
-       return checkLabel(labels)
-}
-
-func (s *secretPredicate) Generic(evt event.GenericEvent) bool {
-
-       labels := evt.Meta.GetLabels()
-       return checkLabel(labels)
-}
diff --git a/central-controller/src/monitor/pkg/controller/resourcebundlestate/service_controller.go b/central-controller/src/monitor/pkg/controller/resourcebundlestate/service_controller.go
deleted file mode 100644 (file)
index b6d6d07..0000000
+++ /dev/null
@@ -1,183 +0,0 @@
-package resourcebundlestate
-
-import (
-       "context"
-       "log"
-
-       "github.com/open-ness/EMCO/src/monitor/pkg/apis/k8splugin/v1alpha1"
-
-       corev1 "k8s.io/api/core/v1"
-       k8serrors "k8s.io/apimachinery/pkg/api/errors"
-       "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/handler"
-       "sigs.k8s.io/controller-runtime/pkg/manager"
-       "sigs.k8s.io/controller-runtime/pkg/reconcile"
-       "sigs.k8s.io/controller-runtime/pkg/source"
-)
-
-// AddServiceController the new controller to the controller manager
-func AddServiceController(mgr manager.Manager) error {
-       return addServiceController(mgr, newServiceReconciler(mgr))
-}
-
-func addServiceController(mgr manager.Manager, r *serviceReconciler) error {
-       // Create a new controller
-       c, err := controller.New("Service-controller", mgr, controller.Options{Reconciler: r})
-       if err != nil {
-               return err
-       }
-
-       // Watch for changes to secondar resource Services
-       // Predicate filters Service which don't have the k8splugin label
-       err = c.Watch(&source.Kind{Type: &corev1.Service{}}, &handler.EnqueueRequestForObject{}, &servicePredicate{})
-       if err != nil {
-               return err
-       }
-
-       return nil
-}
-
-func newServiceReconciler(m manager.Manager) *serviceReconciler {
-       return &serviceReconciler{client: m.GetClient()}
-}
-
-type serviceReconciler struct {
-       client client.Client
-}
-
-// Reconcile implements the loop that will update the ResourceBundleState CR
-// whenever we get any updates from all the services we watch.
-func (r *serviceReconciler) Reconcile(req reconcile.Request) (reconcile.Result, error) {
-       log.Printf("Updating ResourceBundleState for Service: %+v\n", req)
-
-       svc := &corev1.Service{}
-       err := r.client.Get(context.TODO(), req.NamespacedName, svc)
-       if err != nil {
-               if k8serrors.IsNotFound(err) {
-                       log.Printf("Service not found: %+v. Remove from CR if it is stored there.\n", req.NamespacedName)
-                       // Remove the Service's status from StatusList
-                       // This can happen if we get the DeletionTimeStamp event
-                       // after the Service has been deleted.
-                       r.deleteServiceFromAllCRs(req.NamespacedName)
-                       return reconcile.Result{}, nil
-               }
-               log.Printf("Failed to get service: %+v\n", req.NamespacedName)
-               return reconcile.Result{}, err
-       }
-
-       // Find the CRs which track this service via the labelselector
-       crSelector := returnLabel(svc.GetLabels())
-       if crSelector == nil {
-               log.Println("We should not be here. The predicate should have filtered this Service")
-       }
-
-       // Get the CRs which have this label and update them all
-       // Ideally, we will have only one CR, but there is nothing
-       // preventing the creation of multiple.
-       // TODO: Consider using an admission validating webook to prevent multiple
-       rbStatusList := &v1alpha1.ResourceBundleStateList{}
-       err = listResources(r.client, req.Namespace, crSelector, rbStatusList)
-       if err != nil || len(rbStatusList.Items) == 0 {
-               log.Printf("Did not find any CRs tracking this resource\n")
-               return reconcile.Result{}, nil
-       }
-
-       err = r.updateCRs(rbStatusList, svc)
-       if err != nil {
-               // Requeue the update
-               return reconcile.Result{}, err
-       }
-
-       return reconcile.Result{}, nil
-}
-
-// deleteServiceFromAllCRs deletes service status from all the CRs when the Service itself has been deleted
-// and we have not handled the updateCRs yet.
-// Since, we don't have the service's labels, we need to look at all the CRs in this namespace
-func (r *serviceReconciler) deleteServiceFromAllCRs(namespacedName types.NamespacedName) error {
-
-       rbStatusList := &v1alpha1.ResourceBundleStateList{}
-       err := listResources(r.client, namespacedName.Namespace, nil, rbStatusList)
-       if err != nil || len(rbStatusList.Items) == 0 {
-               log.Printf("Did not find any CRs tracking this resource\n")
-               return nil
-       }
-       for _, cr := range rbStatusList.Items {
-               r.deleteFromSingleCR(&cr, namespacedName.Name)
-       }
-
-       return nil
-}
-
-func (r *serviceReconciler) updateCRs(crl *v1alpha1.ResourceBundleStateList, svc *corev1.Service) error {
-
-       for _, cr := range crl.Items {
-               // Service is not scheduled for deletion
-               if svc.DeletionTimestamp == nil {
-                       err := r.updateSingleCR(&cr, svc)
-                       if err != nil {
-                               return err
-                       }
-               } else {
-                       // Service is scheduled for deletion
-                       r.deleteFromSingleCR(&cr, svc.Name)
-               }
-       }
-
-       return nil
-}
-
-func (r *serviceReconciler) deleteFromSingleCR(cr *v1alpha1.ResourceBundleState, name string) error {
-       cr.Status.ResourceCount--
-       length := len(cr.Status.ServiceStatuses)
-       for i, rstatus := range cr.Status.ServiceStatuses {
-               if rstatus.Name == name {
-                       //Delete that status from the array
-                       cr.Status.ServiceStatuses[i] = cr.Status.ServiceStatuses[length-1]
-                       cr.Status.ServiceStatuses[length-1].Status = corev1.ServiceStatus{}
-                       cr.Status.ServiceStatuses = cr.Status.ServiceStatuses[:length-1]
-                       return nil
-               }
-       }
-
-       log.Println("Did not find a status for Service in CR")
-       return nil
-}
-
-func (r *serviceReconciler) updateSingleCR(cr *v1alpha1.ResourceBundleState, svc *corev1.Service) error {
-
-       // Update status after searching for it in the list of resourceStatuses
-       for i, rstatus := range cr.Status.ServiceStatuses {
-               // Look for the status if we already have it in the CR
-               if rstatus.Name == svc.Name {
-                       svc.Status.DeepCopyInto(&cr.Status.ServiceStatuses[i].Status)
-                       err := r.client.Status().Update(context.TODO(), cr)
-                       if err != nil {
-                               log.Printf("failed to update rbstate: %v\n", err)
-                               return err
-                       }
-                       return nil
-               }
-       }
-
-       // Exited for loop with no status found
-       // Increment the number of tracked resources
-       cr.Status.ResourceCount++
-
-       // Add it to CR
-       cr.Status.ServiceStatuses = append(cr.Status.ServiceStatuses, corev1.Service{
-               TypeMeta:   svc.TypeMeta,
-               ObjectMeta: svc.ObjectMeta,
-               Status:     svc.Status,
-       })
-
-       err := r.client.Status().Update(context.TODO(), cr)
-       if err != nil {
-               log.Printf("failed to update rbstate: %v\n", err)
-               return err
-       }
-
-       return nil
-}
diff --git a/central-controller/src/monitor/pkg/controller/resourcebundlestate/service_predicate.go b/central-controller/src/monitor/pkg/controller/resourcebundlestate/service_predicate.go
deleted file mode 100644 (file)
index d427443..0000000
+++ /dev/null
@@ -1,44 +0,0 @@
-package resourcebundlestate
-
-import (
-       "sigs.k8s.io/controller-runtime/pkg/event"
-)
-
-type servicePredicate struct {
-}
-
-func (s *servicePredicate) Create(evt event.CreateEvent) bool {
-
-       if evt.Meta == nil {
-               return false
-       }
-
-       labels := evt.Meta.GetLabels()
-       return checkLabel(labels)
-}
-
-func (s *servicePredicate) Delete(evt event.DeleteEvent) bool {
-
-       if evt.Meta == nil {
-               return false
-       }
-
-       labels := evt.Meta.GetLabels()
-       return checkLabel(labels)
-}
-
-func (s *servicePredicate) Update(evt event.UpdateEvent) bool {
-
-       if evt.MetaNew == nil {
-               return false
-       }
-
-       labels := evt.MetaNew.GetLabels()
-       return checkLabel(labels)
-}
-
-func (s *servicePredicate) Generic(evt event.GenericEvent) bool {
-
-       labels := evt.Meta.GetLabels()
-       return checkLabel(labels)
-}
diff --git a/central-controller/src/monitor/pkg/controller/resourcebundlestate/statefulSet_controller.go b/central-controller/src/monitor/pkg/controller/resourcebundlestate/statefulSet_controller.go
deleted file mode 100644 (file)
index 679f494..0000000
+++ /dev/null
@@ -1,183 +0,0 @@
-package resourcebundlestate
-
-import (
-       "context"
-       "log"
-
-       "github.com/open-ness/EMCO/src/monitor/pkg/apis/k8splugin/v1alpha1"
-
-       appsv1 "k8s.io/api/apps/v1"
-       k8serrors "k8s.io/apimachinery/pkg/api/errors"
-       "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/handler"
-       "sigs.k8s.io/controller-runtime/pkg/manager"
-       "sigs.k8s.io/controller-runtime/pkg/reconcile"
-       "sigs.k8s.io/controller-runtime/pkg/source"
-)
-
-// AddStatefulSetController the new controller to the controller manager
-func AddStatefulSetController(mgr manager.Manager) error {
-       return addStatefulSetController(mgr, newStatefulSetReconciler(mgr))
-}
-
-func addStatefulSetController(mgr manager.Manager, r *statefulSetReconciler) error {
-       // Create a new controller
-       c, err := controller.New("Statefulset-controller", mgr, controller.Options{Reconciler: r})
-       if err != nil {
-               return err
-       }
-
-       // Watch for changes to secondar resource StatefulSets
-       // Predicate filters StatefulSet which don't have the k8splugin label
-       err = c.Watch(&source.Kind{Type: &appsv1.StatefulSet{}}, &handler.EnqueueRequestForObject{}, &statefulSetPredicate{})
-       if err != nil {
-               return err
-       }
-
-       return nil
-}
-
-func newStatefulSetReconciler(m manager.Manager) *statefulSetReconciler {
-       return &statefulSetReconciler{client: m.GetClient()}
-}
-
-type statefulSetReconciler struct {
-       client client.Client
-}
-
-// Reconcile implements the loop that will update the ResourceBundleState CR
-// whenever we get any updates from all the StatefulSets we watch.
-func (r *statefulSetReconciler) Reconcile(req reconcile.Request) (reconcile.Result, error) {
-       log.Printf("Updating ResourceBundleState for StatefulSet: %+v\n", req)
-
-       sfs := &appsv1.StatefulSet{}
-       err := r.client.Get(context.TODO(), req.NamespacedName, sfs)
-       if err != nil {
-               if k8serrors.IsNotFound(err) {
-                       log.Printf("StatefulSet not found: %+v. Remove from CR if it is stored there.\n", req.NamespacedName)
-                       // Remove the StatefulSet's status from StatusList
-                       // This can happen if we get the DeletionTimeStamp event
-                       // after the StatefulSet has been deleted.
-                       r.deleteStatefulSetFromAllCRs(req.NamespacedName)
-                       return reconcile.Result{}, nil
-               }
-               log.Printf("Failed to get statefulSet: %+v\n", req.NamespacedName)
-               return reconcile.Result{}, err
-       }
-
-       // Find the CRs which track this statefulSet via the labelselector
-       crSelector := returnLabel(sfs.GetLabels())
-       if crSelector == nil {
-               log.Println("We should not be here. The predicate should have filtered this StatefulSet")
-       }
-
-       // Get the CRs which have this label and update them all
-       // Ideally, we will have only one CR, but there is nothing
-       // preventing the creation of multiple.
-       // TODO: Consider using an admission validating webook to prevent multiple
-       rbStatusList := &v1alpha1.ResourceBundleStateList{}
-       err = listResources(r.client, req.Namespace, crSelector, rbStatusList)
-       if err != nil || len(rbStatusList.Items) == 0 {
-               log.Printf("Did not find any CRs tracking this resource\n")
-               return reconcile.Result{}, nil
-       }
-
-       err = r.updateCRs(rbStatusList, sfs)
-       if err != nil {
-               // Requeue the update
-               return reconcile.Result{}, err
-       }
-
-       return reconcile.Result{}, nil
-}
-
-// deleteStatefulSetFromAllCRs deletes statefulSet status from all the CRs when the StatefulSet itself has been deleted
-// and we have not handled the updateCRs yet.
-// Since, we don't have the statefulSet's labels, we need to look at all the CRs in this namespace
-func (r *statefulSetReconciler) deleteStatefulSetFromAllCRs(namespacedName types.NamespacedName) error {
-
-       rbStatusList := &v1alpha1.ResourceBundleStateList{}
-       err := listResources(r.client, namespacedName.Namespace, nil, rbStatusList)
-       if err != nil || len(rbStatusList.Items) == 0 {
-               log.Printf("Did not find any CRs tracking this resource\n")
-               return nil
-       }
-       for _, cr := range rbStatusList.Items {
-               r.deleteFromSingleCR(&cr, namespacedName.Name)
-       }
-
-       return nil
-}
-
-func (r *statefulSetReconciler) updateCRs(crl *v1alpha1.ResourceBundleStateList, sfs *appsv1.StatefulSet) error {
-
-       for _, cr := range crl.Items {
-               // StatefulSet is not scheduled for deletion
-               if sfs.DeletionTimestamp == nil {
-                       err := r.updateSingleCR(&cr, sfs)
-                       if err != nil {
-                               return err
-                       }
-               } else {
-                       // StatefulSet is scheduled for deletion
-                       r.deleteFromSingleCR(&cr, sfs.Name)
-               }
-       }
-
-       return nil
-}
-
-func (r *statefulSetReconciler) deleteFromSingleCR(cr *v1alpha1.ResourceBundleState, name string) error {
-       cr.Status.ResourceCount--
-       length := len(cr.Status.StatefulSetStatuses)
-       for i, rstatus := range cr.Status.StatefulSetStatuses {
-               if rstatus.Name == name {
-                       //Delete that status from the array
-                       cr.Status.StatefulSetStatuses[i] = cr.Status.StatefulSetStatuses[length-1]
-                       cr.Status.StatefulSetStatuses[length-1].Status = appsv1.StatefulSetStatus{}
-                       cr.Status.StatefulSetStatuses = cr.Status.StatefulSetStatuses[:length-1]
-                       return nil
-               }
-       }
-
-       log.Println("Did not find a status for StatefulSet in CR")
-       return nil
-}
-
-func (r *statefulSetReconciler) updateSingleCR(cr *v1alpha1.ResourceBundleState, sfs *appsv1.StatefulSet) error {
-
-       // Update status after searching for it in the list of resourceStatuses
-       for i, rstatus := range cr.Status.StatefulSetStatuses {
-               // Look for the status if we already have it in the CR
-               if rstatus.Name == sfs.Name {
-                       sfs.Status.DeepCopyInto(&cr.Status.StatefulSetStatuses[i].Status)
-                       err := r.client.Status().Update(context.TODO(), cr)
-                       if err != nil {
-                               log.Printf("failed to update rbstate: %v\n", err)
-                               return err
-                       }
-                       return nil
-               }
-       }
-
-       // Exited for loop with no status found
-       // Increment the number of tracked resources
-       cr.Status.ResourceCount++
-
-       // Add it to CR
-       cr.Status.StatefulSetStatuses = append(cr.Status.StatefulSetStatuses, appsv1.StatefulSet{
-               TypeMeta:   sfs.TypeMeta,
-               ObjectMeta: sfs.ObjectMeta,
-               Status:     sfs.Status,
-       })
-
-       err := r.client.Status().Update(context.TODO(), cr)
-       if err != nil {
-               log.Printf("failed to update rbstate: %v\n", err)
-               return err
-       }
-
-       return nil
-}
diff --git a/central-controller/src/monitor/pkg/controller/resourcebundlestate/statefulSet_predicate.go b/central-controller/src/monitor/pkg/controller/resourcebundlestate/statefulSet_predicate.go
deleted file mode 100644 (file)
index af31313..0000000
+++ /dev/null
@@ -1,44 +0,0 @@
-package resourcebundlestate
-
-import (
-       "sigs.k8s.io/controller-runtime/pkg/event"
-)
-
-type statefulSetPredicate struct {
-}
-
-func (s *statefulSetPredicate) Create(evt event.CreateEvent) bool {
-
-       if evt.Meta == nil {
-               return false
-       }
-
-       labels := evt.Meta.GetLabels()
-       return checkLabel(labels)
-}
-
-func (s *statefulSetPredicate) Delete(evt event.DeleteEvent) bool {
-
-       if evt.Meta == nil {
-               return false
-       }
-
-       labels := evt.Meta.GetLabels()
-       return checkLabel(labels)
-}
-
-func (s *statefulSetPredicate) Update(evt event.UpdateEvent) bool {
-
-       if evt.MetaNew == nil {
-               return false
-       }
-
-       labels := evt.MetaNew.GetLabels()
-       return checkLabel(labels)
-}
-
-func (s *statefulSetPredicate) Generic(evt event.GenericEvent) bool {
-
-       labels := evt.Meta.GetLabels()
-       return checkLabel(labels)
-}
diff --git a/central-controller/src/monitor/pkg/generated/clientset/versioned/doc.go b/central-controller/src/monitor/pkg/generated/clientset/versioned/doc.go
deleted file mode 100644 (file)
index 6f869b4..0000000
+++ /dev/null
@@ -1,6 +0,0 @@
-// SPDX-License-Identifier: Apache-2.0
-// Copyright (c) 2020 Intel Corporation
-// Code generated by client-gen. DO NOT EDIT.
-
-// This package has the automatically generated clientset.
-package versioned
diff --git a/central-controller/src/monitor/pkg/generated/clientset/versioned/fake/doc.go b/central-controller/src/monitor/pkg/generated/clientset/versioned/fake/doc.go
deleted file mode 100644 (file)
index 2411223..0000000
+++ /dev/null
@@ -1,6 +0,0 @@
-// SPDX-License-Identifier: Apache-2.0
-// Copyright (c) 2020 Intel Corporation
-// Code generated by client-gen. DO NOT EDIT.
-
-// This package has the automatically generated fake clientset.
-package fake
diff --git a/central-controller/src/monitor/pkg/generated/clientset/versioned/scheme/doc.go b/central-controller/src/monitor/pkg/generated/clientset/versioned/scheme/doc.go
deleted file mode 100644 (file)
index 605085c..0000000
+++ /dev/null
@@ -1,6 +0,0 @@
-// SPDX-License-Identifier: Apache-2.0
-// Copyright (c) 2020 Intel Corporation
-// Code generated by client-gen. DO NOT EDIT.
-
-// This package contains the scheme of the automatically generated clientset.
-package scheme
diff --git a/central-controller/src/monitor/pkg/generated/clientset/versioned/typed/k8splugin/v1alpha1/doc.go b/central-controller/src/monitor/pkg/generated/clientset/versioned/typed/k8splugin/v1alpha1/doc.go
deleted file mode 100644 (file)
index 331505c..0000000
+++ /dev/null
@@ -1,6 +0,0 @@
-// SPDX-License-Identifier: Apache-2.0
-// Copyright (c) 2020 Intel Corporation
-// Code generated by client-gen. DO NOT EDIT.
-
-// This package has the automatically generated typed clients.
-package v1alpha1
diff --git a/central-controller/src/monitor/pkg/generated/clientset/versioned/typed/k8splugin/v1alpha1/fake/doc.go b/central-controller/src/monitor/pkg/generated/clientset/versioned/typed/k8splugin/v1alpha1/fake/doc.go
deleted file mode 100644 (file)
index 85e2a7e..0000000
+++ /dev/null
@@ -1,6 +0,0 @@
-// SPDX-License-Identifier: Apache-2.0
-// Copyright (c) 2020 Intel Corporation
-// Code generated by client-gen. DO NOT EDIT.
-
-// Package fake has the automatically generated clients.
-package fake
diff --git a/central-controller/src/monitor/pkg/generated/clientset/versioned/typed/k8splugin/v1alpha1/fake/fake_k8splugin_client.go b/central-controller/src/monitor/pkg/generated/clientset/versioned/typed/k8splugin/v1alpha1/fake/fake_k8splugin_client.go
deleted file mode 100644 (file)
index 73868db..0000000
+++ /dev/null
@@ -1,27 +0,0 @@
-// SPDX-License-Identifier: Apache-2.0
-// Copyright (c) 2020 Intel Corporation
-// Code generated by client-gen. DO NOT EDIT.
-
-package fake
-
-import (
-       v1alpha1 "github.com/open-ness/EMCO/src/monitor/pkg/generated/clientset/versioned/typed/k8splugin/v1alpha1"
-
-       rest "k8s.io/client-go/rest"
-       testing "k8s.io/client-go/testing"
-)
-
-type FakeK8spluginV1alpha1 struct {
-       *testing.Fake
-}
-
-func (c *FakeK8spluginV1alpha1) ResourceBundleStates(namespace string) v1alpha1.ResourceBundleStateInterface {
-       return &FakeResourceBundleStates{c, namespace}
-}
-
-// RESTClient returns a RESTClient that is used to communicate
-// with API server by this client implementation.
-func (c *FakeK8spluginV1alpha1) RESTClient() rest.Interface {
-       var ret *rest.RESTClient
-       return ret
-}
diff --git a/central-controller/src/monitor/pkg/generated/clientset/versioned/typed/k8splugin/v1alpha1/generated_expansion.go b/central-controller/src/monitor/pkg/generated/clientset/versioned/typed/k8splugin/v1alpha1/generated_expansion.go
deleted file mode 100644 (file)
index 9228609..0000000
+++ /dev/null
@@ -1,7 +0,0 @@
-// SPDX-License-Identifier: Apache-2.0
-// Copyright (c) 2020 Intel Corporation
-// Code generated by client-gen. DO NOT EDIT.
-
-package v1alpha1
-
-type ResourceBundleStateExpansion interface{}
diff --git a/central-controller/src/monitor/pkg/generated/listers/k8splugin/v1alpha1/expansion_generated.go b/central-controller/src/monitor/pkg/generated/listers/k8splugin/v1alpha1/expansion_generated.go
deleted file mode 100644 (file)
index 6af11b6..0000000
+++ /dev/null
@@ -1,13 +0,0 @@
-// SPDX-License-Identifier: Apache-2.0
-// Copyright (c) 2020 Intel Corporation
-// Code generated by lister-gen. DO NOT EDIT.
-
-package v1alpha1
-
-// ResourceBundleStateListerExpansion allows custom methods to be added to
-// ResourceBundleStateLister.
-type ResourceBundleStateListerExpansion interface{}
-
-// ResourceBundleStateNamespaceListerExpansion allows custom methods to be added to
-// ResourceBundleStateNamespaceLister.
-type ResourceBundleStateNamespaceListerExpansion interface{}
diff --git a/central-controller/src/monitor/tools.go b/central-controller/src/monitor/tools.go
deleted file mode 100644 (file)
index 6e6e18b..0000000
+++ /dev/null
@@ -1,7 +0,0 @@
-// +build tools
-
-package tools
-
-import (
-       _ "sigs.k8s.io/controller-tools/pkg/crd"
-)
diff --git a/central-controller/src/monitor/version/version.go b/central-controller/src/monitor/version/version.go
deleted file mode 100644 (file)
index e3e130b..0000000
+++ /dev/null
@@ -1,5 +0,0 @@
-package version
-
-var (
-       Version = "0.0.1"
-)
index 4db24a9..81236d0 100644 (file)
@@ -1,9 +1,16 @@
 # Steps to register local cluster
 
 **1. Copy Kubeconfig as admin.conf in this folder**
+  You can name it by default as 'admin.conf' or define it using --kubeconfigPath
+  while executing the command.
 **2. Compiled as:**
    `$ go build -o reg_cluster ./reg_cluster.go`
 **3. Edit config.json with mongo db and etcd ip**
 **4. Run command to register cluster**
-   `$ ./reg_cluster`
+   Note: You shall have the secrets used for mongo already created
+   in the sdewan-system namespace
+   `$ ./reg_cluster` This will use the default secret names
+   Or
+   `$ ./reg_cluster --mongoSecret <mongo-secret-name> --mongoDataSecret
+    <mongo-data-secret-name>`
 
index 83bf178..ea17140 100644 (file)
@@ -3,29 +3,64 @@ go 1.17
 module central-controller/src/reg_cluster
 
 require (
-       github.com/open-ness/EMCO/src/orchestrator v0.0.0-00010101000000-000000000000
-       github.com/open-ness/EMCO/src/rsync v0.0.0-00010101000000-000000000000
        github.com/pkg/errors v0.9.1
+       gitlab.com/project-emco/core/emco-base/src/orchestrator v0.0.0-00010101000000-000000000000
+       gitlab.com/project-emco/core/emco-base/src/rsync v0.0.0-00010101000000-000000000000
+       k8s.io/apimachinery v0.23.3
+       k8s.io/client-go v0.23.3
 )
 
 require (
+       github.com/davecgh/go-spew v1.1.1 // indirect
+       github.com/go-logr/logr v1.2.2 // indirect
        github.com/go-stack/stack v1.8.0 // indirect
+       github.com/gogo/protobuf v1.3.2 // indirect
+       github.com/golang/protobuf v1.5.2 // indirect
        github.com/golang/snappy v0.0.1 // indirect
-       github.com/sirupsen/logrus v1.7.0 // indirect
-       github.com/xdg/scram v0.0.0-20180814205039-7eeb5667e42c // indirect
-       github.com/xdg/stringprep v1.0.0 // indirect
-       go.mongodb.org/mongo-driver v1.1.2 // indirect
-       golang.org/x/crypto v0.0.0-20201221181555-eec23a3978ad // indirect
-       golang.org/x/net v0.0.0-20200707034311-ab3426394381 // indirect
-       golang.org/x/sync v0.0.0-20201207232520-09787c993a3a // indirect
-       golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c // indirect
-       golang.org/x/text v0.3.3 // indirect
+       github.com/google/gofuzz v1.2.0 // indirect
+       github.com/googleapis/gnostic v0.5.5 // indirect
+       github.com/imdario/mergo v0.3.12 // indirect
+       github.com/json-iterator/go v1.1.12 // indirect
+       github.com/klauspost/compress v1.13.6 // indirect
+       github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
+       github.com/modern-go/reflect2 v1.0.2 // indirect
+       github.com/sirupsen/logrus v1.8.1 // indirect
+       github.com/spf13/pflag v1.0.5 // indirect
+       github.com/tidwall/gjson v1.14.0 // indirect
+       github.com/tidwall/match v1.1.1 // indirect
+       github.com/tidwall/pretty v1.2.0 // indirect
+       github.com/xdg-go/pbkdf2 v1.0.0 // indirect
+       github.com/xdg-go/scram v1.0.2 // indirect
+       github.com/xdg-go/stringprep v1.0.2 // indirect
+       github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f // indirect
+       github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415 // indirect
+       github.com/xeipuuv/gojsonschema v1.2.0 // indirect
+       github.com/youmark/pkcs8 v0.0.0-20181117223130-1be2e3e5546d // indirect
+       go.mongodb.org/mongo-driver v1.8.4 // indirect
+       golang.org/x/crypto v0.0.0-20211215153901-e495a2d5b3d3 // indirect
+       golang.org/x/net v0.0.0-20220127200216-cd36cc0744dd // indirect
+       golang.org/x/oauth2 v0.0.0-20210819190943-2bc19b11175f // indirect
+       golang.org/x/sync v0.0.0-20210220032951-036812b2e83c // indirect
+       golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e // indirect
+       golang.org/x/term v0.0.0-20210927222741-03fcf44c2211 // indirect
+       golang.org/x/text v0.3.7 // indirect
+       golang.org/x/time v0.0.0-20210723032227-1f47c861a9ac // indirect
+       google.golang.org/appengine v1.6.7 // indirect
+       google.golang.org/protobuf v1.27.1 // indirect
+       gopkg.in/inf.v0 v0.9.1 // indirect
+       gopkg.in/yaml.v2 v2.4.0 // indirect
+       gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b // indirect
+       k8s.io/api v0.23.3 // indirect
+       k8s.io/klog/v2 v2.30.0 // indirect
+       k8s.io/utils v0.0.0-20211208161948-7d6a63dca704 // indirect
+       sigs.k8s.io/structured-merge-diff/v4 v4.2.1 // indirect
+       sigs.k8s.io/yaml v1.3.0 // indirect
 )
 
 replace (
-       github.com/open-ness/EMCO/src/monitor => ../monitor
-       github.com/open-ness/EMCO/src/orchestrator => ../vendor/github.com/open-ness/EMCO/src/orchestrator
-       github.com/open-ness/EMCO/src/rsync => ../rsync
+       gitlab.com/project-emco/core/emco-base/src/monitor => ../monitor
+       gitlab.com/project-emco/core/emco-base/src/orchestrator => ../vendor/gitlab.com/project-emco/core/emco-base/src/orchestrator
+       gitlab.com/project-emco/core/emco-base/src/rsync => ../rsync
        k8s.io/api => k8s.io/api v0.19.0
        k8s.io/apiextensions-apiserver => k8s.io/apiextensions-apiserver v0.19.0
        k8s.io/apimachinery => k8s.io/apimachinery v0.19.0
index 60ee6fe..8f71137 100644 (file)
-bazil.org/fuse v0.0.0-20160811212531-371fbbdaa898/go.mod h1:Xbm+BRKSBEpa4q4hTSxohYNQpsxXPbPry4JJWOB3LB8=
 cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
 cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
-cloud.google.com/go v0.37.4/go.mod h1:NHPJ89PdicEuT9hdPXMROBD91xc5uRDxsMtSB16k7hw=
 cloud.google.com/go v0.38.0/go.mod h1:990N+gfupTy94rShfmMCWGDn0LpTmnzTp2qbd1dvSRU=
 cloud.google.com/go v0.44.1/go.mod h1:iSa0KzasP4Uvy3f1mN/7PiObzGgflwredwwASm/v6AU=
 cloud.google.com/go v0.44.2/go.mod h1:60680Gw3Yr4ikxnPRS/oxxkBccT6SA1yMk63TGekxKY=
 cloud.google.com/go v0.45.1/go.mod h1:RpBamKRgapWJb87xiFSdk4g1CME7QZg3uwTez+TSTjc=
 cloud.google.com/go v0.46.3/go.mod h1:a6bKKbmY7er1mI7TEI4lsAkts/mkhTSZK8w33B4RAg0=
-cloud.google.com/go v0.49.0/go.mod h1:hGvAdzcWNbyuxS3nWhD7H2cIJxjRRTRLQVB0bdputVY=
+cloud.google.com/go v0.50.0/go.mod h1:r9sluTvynVuxRIOHXQEHMFffphuXHOMZMycpNR5e6To=
 cloud.google.com/go v0.51.0/go.mod h1:hWtGJ6gnXH+KgDv+V0zFGDvpi07n3z8ZNj3T1RW0Gcw=
+cloud.google.com/go v0.52.0/go.mod h1:pXajvRH/6o3+F9jDHZWQ5PbGhn+o8w9qiu/CffaVdO4=
+cloud.google.com/go v0.53.0/go.mod h1:fp/UouUEsRkN6ryDKNW/Upv/JBKnv6WDthjR6+vze6M=
+cloud.google.com/go v0.54.0/go.mod h1:1rq2OEkV3YMf6n/9ZvGWI3GWw0VoqH/1x2nd8Is/bPc=
+cloud.google.com/go v0.56.0/go.mod h1:jr7tqZxxKOVYizybht9+26Z/gUq7tiRzu+ACVAMbKVk=
+cloud.google.com/go v0.57.0/go.mod h1:oXiQ6Rzq3RAkkY7N6t3TcE6jE+CIBBbA36lwQ1JyzZs=
+cloud.google.com/go v0.62.0/go.mod h1:jmCYTdRCQuc1PHIIJ/maLInMho30T/Y0M4hTdTShOYc=
+cloud.google.com/go v0.65.0/go.mod h1:O5N8zS7uWy9vkA9vayVHs65eM1ubvY4h553ofrNHObY=
 cloud.google.com/go/bigquery v1.0.1/go.mod h1:i/xbL2UlR5RvWAURpBYZTtm/cXjCha9lbfbpx4poX+o=
 cloud.google.com/go/bigquery v1.3.0/go.mod h1:PjpwJnslEMmckchkHFfq+HTD2DmtT67aNFKH1/VBDHE=
+cloud.google.com/go/bigquery v1.4.0/go.mod h1:S8dzgnTigyfTmLBfrtrhyYhwRxG72rYxvftPBK2Dvzc=
+cloud.google.com/go/bigquery v1.5.0/go.mod h1:snEHRnqQbz117VIFhE8bmtwIDY80NLUZUMb4Nv6dBIg=
+cloud.google.com/go/bigquery v1.7.0/go.mod h1://okPTzCYNXSlb24MZs83e2Do+h+VXtc4gLoIoXIAPc=
+cloud.google.com/go/bigquery v1.8.0/go.mod h1:J5hqkt3O0uAFnINi6JXValWIb1v0goeZM77hZzJN/fQ=
 cloud.google.com/go/datastore v1.0.0/go.mod h1:LXYbyblFSglQ5pkeyhO+Qmw7ukd3C+pD7TKLgZqpHYE=
-cloud.google.com/go/firestore v1.1.0/go.mod h1:ulACoGHTpvq5r8rxGJ4ddJZBZqakUQqClKRT5SZwBmk=
+cloud.google.com/go/datastore v1.1.0/go.mod h1:umbIZjpQpHh4hmRpGhH4tLFup+FVzqBi1b3c64qFpCk=
 cloud.google.com/go/pubsub v1.0.1/go.mod h1:R0Gpsv3s54REJCy4fxDixWD93lHJMoZTyQ2kNxGRt3I=
+cloud.google.com/go/pubsub v1.1.0/go.mod h1:EwwdRX2sKPjnvnqCa270oGRyludottCI76h+R3AArQw=
+cloud.google.com/go/pubsub v1.2.0/go.mod h1:jhfEVHT8odbXTkndysNHCcx0awwzvfOlguIAii9o8iA=
+cloud.google.com/go/pubsub v1.3.1/go.mod h1:i+ucay31+CNRpDW4Lu78I4xXG+O1r/MAHgjpRVR+TSU=
 cloud.google.com/go/storage v1.0.0/go.mod h1:IhtSnM/ZTZV8YYJWCY8RULGVqBDmpoyjwiyrjsg+URw=
-cloud.google.com/go/storage v1.3.0/go.mod h1:9IAwXhoyBJ7z9LcAwkj0/7NnPzYaPeZxxVp3zm+5IqA=
-contrib.go.opencensus.io/exporter/ocagent v0.6.0/go.mod h1:zmKjrJcdo0aYcVS7bmEeSEBLPA9YJp5bjrofdU3pIXs=
+cloud.google.com/go/storage v1.5.0/go.mod h1:tpKbwo567HUNpVclU5sGELwQWBDZ8gh0ZeosJ0Rtdos=
+cloud.google.com/go/storage v1.6.0/go.mod h1:N7U0C8pVQ/+NIKOBQyamJIeKQKkZ+mxpohlUTyfDhBk=
+cloud.google.com/go/storage v1.8.0/go.mod h1:Wv1Oy7z6Yz3DshWRJFhqM/UCfaWIRTdp0RXyy7KQOVs=
+cloud.google.com/go/storage v1.10.0/go.mod h1:FLPqc6j+Ki4BU591ie1oL6qBQGu2Bl/tZ9ullr3+Kg0=
 dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU=
-github.com/Azure/azure-pipeline-go v0.2.1/go.mod h1:UGSo8XybXnIGZ3epmeBw7Jdz+HiUVpqIlpz/HKHylF4=
-github.com/Azure/azure-pipeline-go v0.2.2/go.mod h1:4rQ/NZncSvGqNkkOsNpOU1tgoNuIlp9AfUH5G1tvCHc=
-github.com/Azure/azure-sdk-for-go v16.2.1+incompatible/go.mod h1:9XXNKU+eRnpl9moKnB4QOLf1HestfXbmab5FXxiDBjc=
-github.com/Azure/azure-sdk-for-go v23.2.0+incompatible/go.mod h1:9XXNKU+eRnpl9moKnB4QOLf1HestfXbmab5FXxiDBjc=
-github.com/Azure/azure-sdk-for-go v36.1.0+incompatible/go.mod h1:9XXNKU+eRnpl9moKnB4QOLf1HestfXbmab5FXxiDBjc=
-github.com/Azure/azure-storage-blob-go v0.8.0/go.mod h1:lPI3aLPpuLTeUwh1sViKXFxwl2B6teiRqI0deQUvsw0=
-github.com/Azure/go-ansiterm v0.0.0-20170929234023-d6e3b3328b78/go.mod h1:LmzpDX56iTiv29bbRTIsUNlaFfuhWRQBWjQdVyAevI8=
-github.com/Azure/go-autorest v10.8.1+incompatible/go.mod h1:r+4oMnoxhatjLLJ6zxSWATqVooLgysK6ZNox3g/xq24=
-github.com/Azure/go-autorest v11.2.8+incompatible/go.mod h1:r+4oMnoxhatjLLJ6zxSWATqVooLgysK6ZNox3g/xq24=
 github.com/Azure/go-autorest/autorest v0.9.0/go.mod h1:xyHB1BMZT0cuDHU7I0+g046+BFDTQ8rEZB0s4Yfa6bI=
-github.com/Azure/go-autorest/autorest v0.9.3-0.20191028180845-3492b2aff503/go.mod h1:xyHB1BMZT0cuDHU7I0+g046+BFDTQ8rEZB0s4Yfa6bI=
 github.com/Azure/go-autorest/autorest v0.9.6/go.mod h1:/FALq9T/kS7b5J5qsQ+RSTUdAmGFqi0vUdVNNx8q630=
 github.com/Azure/go-autorest/autorest/adal v0.5.0/go.mod h1:8Z9fGy2MpX0PvDjB1pEgQTmVqjGhiHBW7RJJEciWzS0=
-github.com/Azure/go-autorest/autorest/adal v0.8.1-0.20191028180845-3492b2aff503/go.mod h1:Z6vX6WXXuyieHAXwMj0S6HY6e6wcHn37qQMBQlvY3lc=
 github.com/Azure/go-autorest/autorest/adal v0.8.2/go.mod h1:ZjhuQClTqx435SRJ2iMlOxPYt3d2C/T/7TiQCVZSn3Q=
 github.com/Azure/go-autorest/autorest/date v0.1.0/go.mod h1:plvfp3oPSKwf2DNjlBjWF/7vwR+cUD/ELuzDCXwHUVA=
 github.com/Azure/go-autorest/autorest/date v0.2.0/go.mod h1:vcORJHLJEh643/Ioh9+vPmf1Ij9AEBM5FuBIXLmIy0g=
 github.com/Azure/go-autorest/autorest/mocks v0.1.0/go.mod h1:OTyCOPRA2IgIlWxVYxBee2F5Gr4kF2zd2J5cFRaIDN0=
 github.com/Azure/go-autorest/autorest/mocks v0.2.0/go.mod h1:OTyCOPRA2IgIlWxVYxBee2F5Gr4kF2zd2J5cFRaIDN0=
 github.com/Azure/go-autorest/autorest/mocks v0.3.0/go.mod h1:a8FDP3DYzQ4RYfVAxAN3SVSiiO77gL2j2ronKKP0syM=
-github.com/Azure/go-autorest/autorest/to v0.3.1-0.20191028180845-3492b2aff503/go.mod h1:MgwOyqaIuKdG4TL/2ywSsIWKAfJfgHDo8ObuUk3t5sA=
-github.com/Azure/go-autorest/autorest/validation v0.2.1-0.20191028180845-3492b2aff503/go.mod h1:3EEqHnBxQGHXRYq3HT1WyXAvT7LLY3tl70hw6tQIbjI=
 github.com/Azure/go-autorest/logger v0.1.0/go.mod h1:oExouG+K6PryycPJfVSxi/koC6LSNgds39diKLz7Vrc=
 github.com/Azure/go-autorest/tracing v0.5.0/go.mod h1:r/s2XiOKccPW3HrqB+W0TQzfbtp2fGCgRFtBroKn4Dk=
 github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
 github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo=
-github.com/DATA-DOG/go-sqlmock v1.4.1/go.mod h1:f/Ixk793poVmq4qj/V1dPUg2JEAKC73Q5eFN3EC/SaM=
-github.com/DataDog/datadog-go v3.2.0+incompatible/go.mod h1:LButxg5PwREeZtORoXG3tL4fMGNddJ+vMq1mwgfaqoQ=
-github.com/MakeNowJust/heredoc v0.0.0-20170808103936-bb23615498cd/go.mod h1:64YHyfSL2R96J44Nlwm39UHepQbyR5q10x7iYa1ks2E=
-github.com/Masterminds/goutils v1.1.0/go.mod h1:8cTjp+g8YejhMuvIA5y2vz3BpJxksy863GQaJW2MFNU=
-github.com/Masterminds/semver/v3 v3.1.0/go.mod h1:VPu/7SZ7ePZ3QOrcuXROw5FAcLl4a0cBrbBpGY/8hQs=
-github.com/Masterminds/sprig/v3 v3.1.0/go.mod h1:ONGMf7UfYGAbMXCZmQLy8x3lCDIPrEZE/rU8pmrbihA=
-github.com/Masterminds/squirrel v1.2.0/go.mod h1:yaPeOnPG5ZRwL9oKdTsO/prlkPbXWZlRVMQ/gGlzIuA=
-github.com/Masterminds/vcs v1.13.1/go.mod h1:N09YCmOQr6RLxC6UNHzuVwAdodYbbnycGHSmwVJjcKA=
-github.com/Microsoft/go-winio v0.4.11/go.mod h1:VhR8bwka0BXejwEJY73c50VrPtXAaKcyvVC4A4RozmA=
-github.com/Microsoft/go-winio v0.4.15-0.20190919025122-fc70bd9a86b5/go.mod h1:tTuCMEN+UleMWgg9dVx4Hu52b1bJo+59jBh3ajtinzw=
-github.com/Microsoft/hcsshim v0.8.7/go.mod h1:OHd7sQqRFrYd3RmSgbgji+ctCwkbq2wbEYNSzOYtcBQ=
-github.com/Microsoft/hcsshim v0.8.9/go.mod h1:5692vkUqntj1idxauYlpoINNKeqCiG6Sg38RRsjT5y8=
 github.com/NYTimes/gziphandler v0.0.0-20170623195520-56545f4a5d46/go.mod h1:3wb06e3pkSAbeQ52E9H9iFoQsEEwGN64994WTCIhntQ=
-github.com/NYTimes/gziphandler v1.1.1/go.mod h1:n/CVRwUEOgIxrgPvAQhUUr9oeUtvrhMomdKFjzJNB0c=
-github.com/Nvveen/Gotty v0.0.0-20120604004816-cd527374f1e5/go.mod h1:lmUJ/7eu/Q8D7ML55dXQrVaamCz2vxCfdQBasLZfHKk=
-github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU=
-github.com/OneOfOne/xxhash v1.2.6/go.mod h1:eZbhyaAYD41SGSSsnmcpxVoRiQ/MPUTjUdIIOT9Um7Q=
 github.com/PuerkitoBio/purell v1.0.0/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbtSwDGJws/X0=
-github.com/PuerkitoBio/purell v1.1.0/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbtSwDGJws/X0=
-github.com/PuerkitoBio/purell v1.1.1/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbtSwDGJws/X0=
 github.com/PuerkitoBio/urlesc v0.0.0-20160726150825-5bd2802263f2/go.mod h1:uGdkoq3SwY9Y+13GIhn11/XLaGBb4BfwItxLd5jeuXE=
-github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578/go.mod h1:uGdkoq3SwY9Y+13GIhn11/XLaGBb4BfwItxLd5jeuXE=
-github.com/Shopify/logrus-bugsnag v0.0.0-20171204204709-577dee27f20d/go.mod h1:HI8ITrYtUY+O+ZhtlqUnD8+KwNPOyugEhfP9fdUIaEQ=
-github.com/Shopify/sarama v1.19.0/go.mod h1:FVkBWblsNy7DGZRfXLU0O9RCGt5g3g3yEuWXgklEdEo=
-github.com/Shopify/toxiproxy v2.1.4+incompatible/go.mod h1:OXgGpZ6Cli1/URJOF1DMxUHB2q5Ap20/P/eIdh4G0pI=
-github.com/agnivade/levenshtein v1.0.1/go.mod h1:CURSv5d9Uaml+FovSIICkLbAUZ9S4RqaHDIsdSBg7lM=
-github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
-github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
-github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=
-github.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=
-github.com/alecthomas/units v0.0.0-20190924025748-f65c72e2690d/go.mod h1:rBZYJk541a8SKzHPHnH3zbiI+7dagKZ0cgpgrD7Fyho=
-github.com/aliyun/aliyun-oss-go-sdk v2.0.4+incompatible/go.mod h1:T/Aws4fEfogEE9v+HPhhw+CntffsBHJ8nXQCwKr0/g8=
-github.com/andreyvit/diff v0.0.0-20170406064948-c7f18ee00883/go.mod h1:rCTlJbsFo29Kk6CurOXKm700vrz8f0KW0JNfpkRJY/8=
-github.com/antihax/optional v0.0.0-20180407024304-ca021399b1a6/go.mod h1:V8iCPQYkqmusNa815XgQio277wI47sdRh1dUOLdyC6Q=
-github.com/apache/thrift v0.12.0/go.mod h1:cp2SuWMxlEZw2r+iP2GNCdIi4C1qmUzdZFSVb+bacwQ=
-github.com/armon/circbuf v0.0.0-20150827004946-bbbad097214e/go.mod h1:3U/XgcO3hCbHZ8TKRvWD2dDTCfh9M9ya+I9JpbB7O8o=
-github.com/armon/consul-api v0.0.0-20180202201655-eb2c6b5be1b6/go.mod h1:grANhF5doyWs3UAsr3K4I6qtAmlQcZDesFNEHPZAzj8=
-github.com/armon/go-metrics v0.0.0-20180917152333-f0300d1749da/go.mod h1:Q73ZrmVTwzkszR9V5SSuryQ31EELlFMUz1kKyl939pY=
-github.com/armon/go-metrics v0.3.0/go.mod h1:zXjbSimjXTd7vOpY8B0/2LpvNvDoXBuplAD+gJD3GYs=
-github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8=
-github.com/armon/go-radix v1.0.0/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8=
-github.com/asaskevich/govalidator v0.0.0-20180720115003-f9ffefc3facf/go.mod h1:lB+ZfQJz7igIIfQNfa7Ml4HSf2uFQQRzpGGRXenZAgY=
-github.com/asaskevich/govalidator v0.0.0-20190424111038-f61b66f89f4a/go.mod h1:lB+ZfQJz7igIIfQNfa7Ml4HSf2uFQQRzpGGRXenZAgY=
-github.com/asaskevich/govalidator v0.0.0-20200108200545-475eaeb16496/go.mod h1:oGkLhpf+kjZl6xBf758TQhh5XrAeiJv/7FRz/2spLIg=
-github.com/aws/aws-sdk-go v1.15.11/go.mod h1:mFuSZ37Z9YOHbQEwBWztmVzqXrEkub65tZoCYDt7FT0=
-github.com/aws/aws-sdk-go v1.17.7/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo=
-github.com/aws/aws-sdk-go v1.25.48/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo=
-github.com/baiyubin/aliyun-sts-go-sdk v0.0.0-20180326062324-cfa1a18b161f/go.mod h1:AuiFmCCPBSrqvVMvuqFuk0qogytodnVFVSN5CeJB8Gc=
-github.com/beorn7/perks v0.0.0-20160804104726-4c0e84591b9a/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q=
-github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q=
-github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8=
-github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw=
-github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs=
-github.com/bitly/go-hostpool v0.0.0-20171023180738-a3a6125de932/go.mod h1:NOuUCSz6Q9T7+igc/hlvDOUdtWKryOrtFyIVABv/p7k=
-github.com/bitly/go-simplejson v0.5.0/go.mod h1:cXHtHw4XUPsvGaxgjIAn8PhEWG9NfngEKAMDJEczWVA=
-github.com/bketelsen/crypt v0.0.3-0.20200106085610-5cbc8cc4026c/go.mod h1:MKsuJmJgSg28kpZDP6UIiPt0e0Oz0kqKNGyRaWEPv84=
-github.com/blang/semver v3.1.0+incompatible/go.mod h1:kRBLl5iJ+tD4TcOOxsy/0fnwebNt5EWlYSAyrTnjyyk=
-github.com/blang/semver v3.5.0+incompatible/go.mod h1:kRBLl5iJ+tD4TcOOxsy/0fnwebNt5EWlYSAyrTnjyyk=
-github.com/blang/semver v3.5.1+incompatible/go.mod h1:kRBLl5iJ+tD4TcOOxsy/0fnwebNt5EWlYSAyrTnjyyk=
-github.com/bmizerany/assert v0.0.0-20160611221934-b7ed37b82869/go.mod h1:Ekp36dRnpXw/yCqJaO+ZrUyxD+3VXMFFr56k5XYrpB4=
-github.com/bradfitz/gomemcache v0.0.0-20190913173617-a41fca850d0b/go.mod h1:H0wQNHz2YrLsuXOZozoeDmnHXkNCRmMW0gwFWDfEZDA=
-github.com/brancz/gojsontoyaml v0.0.0-20191212081931-bf2969bbd742/go.mod h1:IyUJYN1gvWjtLF5ZuygmxbnsAyP3aJS6cHzIuZY50B0=
-github.com/brancz/kube-rbac-proxy v0.5.0/go.mod h1:cL2VjiIFGS90Cjh5ZZ8+It6tMcBt8rwvuw2J6Mamnl0=
-github.com/bshuster-repo/logrus-logstash-hook v0.4.1/go.mod h1:zsTqEiSzDgAa/8GZR7E1qaXrhYNDKBYy5/dWPTIflbk=
-github.com/bugsnag/bugsnag-go v0.0.0-20141110184014-b1d153021fcd/go.mod h1:2oa8nejYd4cQ/b0hMIopN0lCRxU0bueqREvZLWFrtK8=
-github.com/bugsnag/osext v0.0.0-20130617224835-0dd3f918b21b/go.mod h1:obH5gd0BsqsP2LwDJ9aOkm/6J86V6lyAXCoQWGw3K50=
-github.com/bugsnag/panicwrap v0.0.0-20151223152923-e2c28503fcd0/go.mod h1:D/8v3kj0zr8ZAKg1AQ6crr+5VwKN5eIywRkfhyM/+dE=
-github.com/campoy/embedmd v1.0.0/go.mod h1:oxyr9RCiSXg0M3VJ3ks0UGfp98BpSSGr0kpiX3MzVl8=
-github.com/cenkalti/backoff v0.0.0-20181003080854-62661b46c409/go.mod h1:90ReRw6GdpyfrHakVjL/QHaoyV4aDUVVkXQJJJ3NXXM=
 github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
-github.com/cespare/xxhash v0.0.0-20181017004759-096ff4a8a059/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc=
-github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc=
-github.com/cespare/xxhash/v2 v2.1.0/go.mod h1:dgIUBU3pDso/gPgZ1osOZ0iQf77oPR28Tjxl5dIMyVM=
-github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
-github.com/chai2010/gettext-go v0.0.0-20160711120539-c6fed771bfd5/go.mod h1:/iP1qXHoty45bqomnu2LM+VVyAEdWN+vtSHGlQgyxbw=
 github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI=
 github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI=
 github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU=
-github.com/circonus-labs/circonus-gometrics v2.3.1+incompatible/go.mod h1:nmEj6Dob7S7YxXgwXpfOuvO54S+tGdZdw9fuRZt25Ag=
-github.com/circonus-labs/circonusllhist v0.1.3/go.mod h1:kMXHVDlOchFAehlya5ePtbp5jckzBHf4XRpQvBOLI+I=
 github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
 github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc=
-github.com/cockroachdb/apd v1.1.0/go.mod h1:8Sl8LxpKi29FqWXR16WEFZRNSz3SoPzUzeMeY4+DwBQ=
-github.com/cockroachdb/cockroach-go v0.0.0-20181001143604-e0a95dfd547c/go.mod h1:XGLbWH/ujMcbPbhZq52Nv6UrCghb1yGn//133kEsvDk=
-github.com/cockroachdb/datadriven v0.0.0-20190809214429-80d97fb3cbaa/go.mod h1:zn76sxSg3SzpJ0PPJaLDCu+Bu0Lg3sKTORVIj19EIF8=
-github.com/codahale/hdrhistogram v0.0.0-20161010025455-3a0bb77429bd/go.mod h1:sE/e/2PUdi/liOCUjSTXgM1o87ZssimdTWN964YiIeI=
-github.com/containerd/cgroups v0.0.0-20190919134610-bf292b21730f/go.mod h1:OApqhQ4XNSNC13gXIwDjhOQxjWa/NxkwZXJ1EvqT0ko=
-github.com/containerd/console v0.0.0-20180822173158-c12b1e7919c1/go.mod h1:Tj/on1eG8kiEhd0+fhSDzsPAFESxzBBvdyEgyryXffw=
-github.com/containerd/containerd v1.2.7/go.mod h1:bC6axHOhabU15QhwfG7w5PipXdVtMXFTttgp+kVtyUA=
-github.com/containerd/containerd v1.3.0-beta.2.0.20190828155532-0293cbd26c69/go.mod h1:bC6axHOhabU15QhwfG7w5PipXdVtMXFTttgp+kVtyUA=
-github.com/containerd/containerd v1.3.2/go.mod h1:bC6axHOhabU15QhwfG7w5PipXdVtMXFTttgp+kVtyUA=
-github.com/containerd/continuity v0.0.0-20190426062206-aaeac12a7ffc/go.mod h1:GL3xCUCBDV3CZiTSEKksMWbLE66hEyuu9qyDOOqM47Y=
-github.com/containerd/continuity v0.0.0-20200107194136-26c1120b8d41/go.mod h1:Dq467ZllaHgAtVp4p1xUQWBrFXR9s/wyoTpG8zOJGkY=
-github.com/containerd/continuity v0.0.0-20200413184840-d3ef23f19fbb/go.mod h1:Dq467ZllaHgAtVp4p1xUQWBrFXR9s/wyoTpG8zOJGkY=
-github.com/containerd/fifo v0.0.0-20190226154929-a9fb20d87448/go.mod h1:ODA38xgv3Kuk8dQz2ZQXpnv/UZZUHUCL7pnLehbXgQI=
-github.com/containerd/go-runc v0.0.0-20180907222934-5a6d9f37cfa3/go.mod h1:IV7qH3hrUgRmyYrtgEeGWJfWbgcHL9CSRruz2Vqcph0=
-github.com/containerd/ttrpc v0.0.0-20190828154514-0e0f228740de/go.mod h1:PvCDdDGpgqzQIzDW1TphrGLssLDZp2GuS+X5DkEJB8o=
-github.com/containerd/ttrpc v1.0.1/go.mod h1:UAxOpgT9ziI0gJrmKvgcZivgxOp8iFPSk8httJEt98Y=
-github.com/containerd/typeurl v0.0.0-20180627222232-a93fcdb778cd/go.mod h1:Cm3kwCdlkCfMSHURc+r6fwoGH6/F1hH3S4sg0rLFWPc=
-github.com/coreos/bbolt v1.3.2/go.mod h1:iRUV2dpdMOn7Bo10OQBFzIJO9kkE559Wcmn+qkEiiKk=
-github.com/coreos/etcd v3.3.10+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE=
-github.com/coreos/etcd v3.3.13+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE=
-github.com/coreos/go-etcd v2.0.0+incompatible/go.mod h1:Jez6KQU2B/sWsbdaef3ED8NzMklzPG4d5KIOhIy30Tk=
-github.com/coreos/go-semver v0.2.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk=
-github.com/coreos/go-semver v0.3.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk=
-github.com/coreos/go-systemd v0.0.0-20180511133405-39ca1b05acc7/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4=
-github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4=
-github.com/coreos/pkg v0.0.0-20160727233714-3ac0863d7acf/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA=
-github.com/coreos/pkg v0.0.0-20180928190104-399ea9e2e55f/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA=
-github.com/coreos/prometheus-operator v0.38.1-0.20200424145508-7e176fda06cc/go.mod h1:erio69w1R/aC14D5nfvAXSlE8FT8jt2Hnavc50Dp33A=
-github.com/cpuguy83/go-md2man v1.0.10/go.mod h1:SmD6nW6nTyfqj6ABTjUi3V3JVMnlJmwcJI5acqYI6dE=
-github.com/cpuguy83/go-md2man/v2 v2.0.0/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU=
-github.com/creack/pty v1.1.7/go.mod h1:lj5s0c3V2DBrqTV7llrYr5NG6My20zk30Fl46Y7DoTY=
-github.com/cyphar/filepath-securejoin v0.2.2/go.mod h1:FpkQEhXnPnOthhzymB7CGsFk2G9VLXONKD9G7QGMM+4=
-github.com/cznic/b v0.0.0-20180115125044-35e9bbe41f07/go.mod h1:URriBxXwVq5ijiJ12C7iIZqlA69nTlI+LgI6/pwftG8=
-github.com/cznic/fileutil v0.0.0-20180108211300-6a051e75936f/go.mod h1:8S58EK26zhXSxzv7NQFpnliaOQsmDUxvoQO3rt154Vg=
-github.com/cznic/golex v0.0.0-20170803123110-4ab7c5e190e4/go.mod h1:+bmmJDNmKlhWNG+gwWCkaBoTy39Fs+bzRxVBzoTQbIc=
-github.com/cznic/internal v0.0.0-20180608152220-f44710a21d00/go.mod h1:olo7eAdKwJdXxb55TKGLiJ6xt1H0/tiiRCWKVLmtjY4=
-github.com/cznic/lldb v1.1.0/go.mod h1:FIZVUmYUVhPwRiPzL8nD/mpFcJ/G7SSXjjXYG4uRI3A=
-github.com/cznic/mathutil v0.0.0-20180504122225-ca4c9f2c1369/go.mod h1:e6NPNENfs9mPDVNRekM7lKScauxd5kXTr1Mfyig6TDM=
-github.com/cznic/ql v1.2.0/go.mod h1:FbpzhyZrqr0PVlK6ury+PoW3T0ODUV22OeWIxcaOrSE=
-github.com/cznic/sortutil v0.0.0-20150617083342-4c7342852e65/go.mod h1:q2w6Bg5jeox1B+QkJ6Wp/+Vn0G/bo3f1uY7Fn3vivIQ=
-github.com/cznic/strutil v0.0.0-20171016134553-529a34b1c186/go.mod h1:AHHPPPXTw0h6pVabbcbyGRK1DckRn7r/STdZEeIDzZc=
-github.com/cznic/zappy v0.0.0-20160723133515-2533cb5b45cc/go.mod h1:Y1SNZ4dRUOKXshKUbwUapqNncRrho4mkjQebgEHZLj8=
-github.com/davecgh/go-spew v0.0.0-20151105211317-5215b55f46b2/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
 github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
 github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
 github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
-github.com/daviddengcn/go-colortext v0.0.0-20160507010035-511bcaf42ccd/go.mod h1:dv4zxwHi5C/8AeI+4gX4dCWOIvNi7I6JCSX0HvlKPgE=
-github.com/deislabs/oras v0.8.1/go.mod h1:Mx0rMSbBNaNfY9hjpccEnxkOqJL6KGjtxNHPLC4G4As=
-github.com/denisenkom/go-mssqldb v0.0.0-20190515213511-eb9f6a1743f3/go.mod h1:zAg7JM8CkOJ43xKXIj7eRO9kmWm/TW578qo+oDO6tuM=
-github.com/denisenkom/go-mssqldb v0.0.0-20191001013358-cfbb681360f0/go.mod h1:xbL0rPBG9cCiLr28tMa8zpbdarY27NDyej4t/EjAShU=
-github.com/denverdino/aliyungo v0.0.0-20190125010748-a747050bb1ba/go.mod h1:dV8lFg6daOBZbT6/BDGIz6Y3WFGn8juu6G+CQ6LHtl0=
-github.com/dgrijalva/jwt-go v0.0.0-20170104182250-a601269ab70c/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ=
 github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ=
-github.com/dgryski/go-sip13 v0.0.0-20181026042036-e10d5fee7954/go.mod h1:vAd38F8PWV+bWy6jNmig1y/TA+kYO4g3RSRF0IAv0no=
-github.com/dgryski/go-sip13 v0.0.0-20190329191031-25c5027a8c7b/go.mod h1:vAd38F8PWV+bWy6jNmig1y/TA+kYO4g3RSRF0IAv0no=
-github.com/dhui/dktest v0.3.0/go.mod h1:cyzIUfGsBEbZ6BT7tnXqAShHSXCZhSNmFl70sZ7c1yc=
-github.com/dnaeon/go-vcr v1.0.1/go.mod h1:aBB1+wY4s93YsC3HHjMBMrwTj2R9FHDzUr9KyGc8n1E=
-github.com/docker/cli v0.0.0-20200130152716-5d0cf8839492/go.mod h1:JLrzqnKDaYBop7H2jaqPtU4hHvMKP+vjCwu2uszcLI8=
-github.com/docker/distribution v0.0.0-20191216044856-a8371794149d/go.mod h1:0+TTO4EOBfRPhZXAeF1Vu+W3hHZ8eLp8PgKVZlcvtFY=
-github.com/docker/distribution v2.7.0+incompatible/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w=
-github.com/docker/distribution v2.7.1+incompatible/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w=
-github.com/docker/docker v0.7.3-0.20190103212154-2b7e084dc98b/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk=
-github.com/docker/docker v0.7.3-0.20190817195342-4760db040282/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk=
-github.com/docker/docker v1.4.2-0.20200203170920-46ec8731fbce/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk=
-github.com/docker/docker-credential-helpers v0.6.3/go.mod h1:WRaJzqw3CTB9bk10avuGsjVBZsD05qeibJ1/TYlvc0Y=
-github.com/docker/go-connections v0.4.0/go.mod h1:Gbd7IOopHjR8Iph03tsViu4nIes5XhDvyHbTtUxmeec=
-github.com/docker/go-events v0.0.0-20190806004212-e31b211e4f1c/go.mod h1:Uw6UezgYA44ePAFQYUehOuCzmy5zmg/+nl2ZfMWGkpA=
-github.com/docker/go-metrics v0.0.0-20180209012529-399ea8c73916/go.mod h1:/u0gXw0Gay3ceNrsHubL3BtdOL2fHf93USgMTe0W5dI=
-github.com/docker/go-units v0.3.3/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk=
-github.com/docker/go-units v0.4.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk=
-github.com/docker/libtrust v0.0.0-20150114040149-fa567046d9b1/go.mod h1:cyGadeNEkKy96OOhEzfZl+yxihPEzKnqJwvfuSUqbZE=
 github.com/docker/spdystream v0.0.0-20160310174837-449fdfce4d96/go.mod h1:Qh8CwZgvJUkLughtfhJv5dyTYa91l1fOUCrgjqmcifM=
 github.com/docopt/docopt-go v0.0.0-20180111231733-ee0de3bc6815/go.mod h1:WwZ+bS3ebgob9U8Nd0kOddGdZWjyMGR8Wziv+TBNwSE=
-github.com/dustin/go-humanize v0.0.0-20171111073723-bb3d318650d4/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk=
-github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk=
-github.com/eapache/go-resiliency v1.1.0/go.mod h1:kFI+JgMyC7bLPUVY133qvEBtVayf5mFgVsvEsIPBvNs=
-github.com/eapache/go-xerial-snappy v0.0.0-20180814174437-776d5712da21/go.mod h1:+020luEh2TKB4/GOp8oxxtq0Daoen/Cii55CzbTV6DU=
-github.com/eapache/queue v1.1.0/go.mod h1:6eCeP0CKFpHLu8blIFXhExK/dRa7WDZfr6jVFPTqq+I=
-github.com/edsrzf/mmap-go v0.0.0-20170320065105-0bce6a688712/go.mod h1:YO35OhQPt3KJa3ryjFM5Bs14WD66h8eGKpfaBNrHW5M=
-github.com/edsrzf/mmap-go v1.0.0/go.mod h1:YO35OhQPt3KJa3ryjFM5Bs14WD66h8eGKpfaBNrHW5M=
-github.com/elastic/go-sysinfo v1.0.1/go.mod h1:O/D5m1VpYLwGjCYzEt63g3Z1uO3jXfwyzzjiW90t8cY=
-github.com/elastic/go-sysinfo v1.1.1/go.mod h1:i1ZYdU10oLNfRzq4vq62BEwD2fH8KaWh6eh0ikPT9F0=
-github.com/elastic/go-windows v1.0.0/go.mod h1:TsU0Nrp7/y3+VwE82FoZF8gC/XFg/Elz6CcloAxnPgU=
-github.com/elastic/go-windows v1.0.1/go.mod h1:FoVvqWSun28vaDQPbj2Elfc0JahhPB7WQEGa3c814Ss=
 github.com/elazarl/goproxy v0.0.0-20180725130230-947c36da3153/go.mod h1:/Zj4wYkgs4iZTTu3o/KG3Itv/qCCa8VVMlb3i9OVuzc=
 github.com/emicklei/go-restful v0.0.0-20170410110728-ff4f55a20633/go.mod h1:otzb+WCGbkyDHkqmQmT5YD2WR4BBwUdeQoFo8l/7tVs=
-github.com/emicklei/go-restful v2.9.5+incompatible/go.mod h1:otzb+WCGbkyDHkqmQmT5YD2WR4BBwUdeQoFo8l/7tVs=
 github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
 github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
 github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98=
 github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c=
-github.com/evanphx/json-patch v4.1.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk=
-github.com/evanphx/json-patch v4.5.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk=
 github.com/evanphx/json-patch v4.9.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk=
-github.com/exponent-io/jsonpath v0.0.0-20151013193312-d6023ce2651d/go.mod h1:ZZMPRZwes7CROmyNKgQzC3XPs6L/G2EJLHddWejkmf4=
-github.com/facette/natsort v0.0.0-20181210072756-2cd4dd1e2dcb/go.mod h1:bH6Xx7IW64qjjJq8M2u4dxNaBiDfKK+z/3eGDpXEQhc=
-github.com/fatih/camelcase v1.0.0/go.mod h1:yN2Sb0lFhZJUdVvtELVWefmrXpuZESvPmqwoZc+/fpc=
-github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4=
-github.com/fatih/structtag v1.1.0/go.mod h1:mBJUNpUnHmRKrKlQQlmCrh5PuhftFbNv8Ys4/aAZl94=
-github.com/fortytw2/leaktest v1.3.0/go.mod h1:jDsjWgpAGjm2CA7WthBh/CdZYEPF31XHquHwclZch5g=
 github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
 github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ=
-github.com/fsouza/fake-gcs-server v1.7.0/go.mod h1:5XIRs4YvwNbNoz+1JF8j6KLAyDh7RHGAyAK3EP2EsNk=
-github.com/garyburd/redigo v0.0.0-20150301180006-535138d7bcd7/go.mod h1:NR3MbYisc3/PwhQ00EMzDiPmrwpPxAn5GI05/YaO1SY=
 github.com/ghodss/yaml v0.0.0-20150909031657-73d445a93680/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04=
-github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04=
-github.com/globalsign/mgo v0.0.0-20180905125535-1ca0a4f7cbcb/go.mod h1:xkRDCp4j0OGD1HRkm4kmhM+pmpv3AKq5SU7GMg4oO/Q=
-github.com/globalsign/mgo v0.0.0-20181015135952-eeefdecb41b8/go.mod h1:xkRDCp4j0OGD1HRkm4kmhM+pmpv3AKq5SU7GMg4oO/Q=
-github.com/go-bindata/go-bindata/v3 v3.1.3/go.mod h1:1/zrpXsLD8YDIbhZRqXzm1Ghc7NhEvIN9+Z6R5/xH4I=
 github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU=
 github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8=
-github.com/go-ini/ini v1.25.4/go.mod h1:ByCAeIL28uOIIG0E3PJtZPDL8WnHpFKFOtgjp+3Ies8=
-github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as=
-github.com/go-kit/kit v0.9.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as=
-github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE=
-github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk=
+github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8=
 github.com/go-logr/logr v0.1.0/go.mod h1:ixOQHD9gLJUVQQ2ZOR7zLEifBX6tGkNJF4QyIY7sIas=
 github.com/go-logr/logr v0.2.0/go.mod h1:z6/tIYblkpsD+a4lm/fGIIU9mZ+XfAiaFtq7xTgseGU=
-github.com/go-logr/logr v0.2.1/go.mod h1:z6/tIYblkpsD+a4lm/fGIIU9mZ+XfAiaFtq7xTgseGU=
-github.com/go-logr/zapr v0.1.0/go.mod h1:tabnROwaDl0UNxkVeFRbY8bwB37GwRv0P8lg6aAiEnk=
-github.com/go-logr/zapr v0.1.1/go.mod h1:tabnROwaDl0UNxkVeFRbY8bwB37GwRv0P8lg6aAiEnk=
-github.com/go-logr/zapr v0.2.0/go.mod h1:qhKdvif7YF5GI9NWEpyxTSSBdGmzkNguibrdCNVPunU=
-github.com/go-openapi/analysis v0.0.0-20180825180245-b006789cd277/go.mod h1:k70tL6pCuVxPJOHXQ+wIac1FUrvNkHolPie/cLEU6hI=
-github.com/go-openapi/analysis v0.17.0/go.mod h1:IowGgpVeD0vNm45So8nr+IcQ3pxVtpRoBWb8PVZO0ik=
-github.com/go-openapi/analysis v0.17.2/go.mod h1:IowGgpVeD0vNm45So8nr+IcQ3pxVtpRoBWb8PVZO0ik=
-github.com/go-openapi/analysis v0.18.0/go.mod h1:IowGgpVeD0vNm45So8nr+IcQ3pxVtpRoBWb8PVZO0ik=
-github.com/go-openapi/analysis v0.19.2/go.mod h1:3P1osvZa9jKjb8ed2TPng3f0i/UY9snX6gxi44djMjk=
-github.com/go-openapi/analysis v0.19.5/go.mod h1:hkEAkxagaIvIP7VTn8ygJNkd4kAYON2rCu0v0ObL0AU=
-github.com/go-openapi/errors v0.17.0/go.mod h1:LcZQpmvG4wyF5j4IhA73wkLFQg+QJXOQHVjmcZxhka0=
-github.com/go-openapi/errors v0.17.2/go.mod h1:LcZQpmvG4wyF5j4IhA73wkLFQg+QJXOQHVjmcZxhka0=
-github.com/go-openapi/errors v0.18.0/go.mod h1:LcZQpmvG4wyF5j4IhA73wkLFQg+QJXOQHVjmcZxhka0=
-github.com/go-openapi/errors v0.19.2/go.mod h1:qX0BLWsyaKfvhluLejVpVNwNRdXZhEbTA4kxxpKBC94=
+github.com/go-logr/logr v1.2.0/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A=
+github.com/go-logr/logr v1.2.2 h1:ahHml/yUpnlb96Rp8HCvtYVPY8ZYpxq3g7UYchIYwbs=
+github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A=
 github.com/go-openapi/jsonpointer v0.0.0-20160704185906-46af16f9f7b1/go.mod h1:+35s3my2LFTysnkMfxsJBAMHj/DoqoB9knIWoYG/Vk0=
-github.com/go-openapi/jsonpointer v0.17.0/go.mod h1:cOnomiV+CVVwFLk0A/MExoFMjwdsUdVpsRhURCKh+3M=
-github.com/go-openapi/jsonpointer v0.17.2/go.mod h1:cOnomiV+CVVwFLk0A/MExoFMjwdsUdVpsRhURCKh+3M=
-github.com/go-openapi/jsonpointer v0.18.0/go.mod h1:cOnomiV+CVVwFLk0A/MExoFMjwdsUdVpsRhURCKh+3M=
-github.com/go-openapi/jsonpointer v0.19.2/go.mod h1:3akKfEdA7DF1sugOqz1dVQHBcuDBPKZGEoHC/NkiQRg=
-github.com/go-openapi/jsonpointer v0.19.3/go.mod h1:Pl9vOtqEWErmShwVjC8pYs9cog34VGT37dQOVbmoatg=
 github.com/go-openapi/jsonreference v0.0.0-20160704190145-13c6e3589ad9/go.mod h1:W3Z9FmVs9qj+KR4zFKmDPGiLdk1D9Rlm7cyMvf57TTg=
-github.com/go-openapi/jsonreference v0.17.0/go.mod h1:g4xxGn04lDIRh0GJb5QlpE3HfopLOL6uZrK/VgnsK9I=
-github.com/go-openapi/jsonreference v0.17.2/go.mod h1:g4xxGn04lDIRh0GJb5QlpE3HfopLOL6uZrK/VgnsK9I=
-github.com/go-openapi/jsonreference v0.18.0/go.mod h1:g4xxGn04lDIRh0GJb5QlpE3HfopLOL6uZrK/VgnsK9I=
-github.com/go-openapi/jsonreference v0.19.2/go.mod h1:jMjeRr2HHw6nAVajTXJ4eiUwohSTlpa0o73RUL1owJc=
-github.com/go-openapi/jsonreference v0.19.3/go.mod h1:rjx6GuL8TTa9VaixXglHmQmIL98+wF9xc8zWvFonSJ8=
-github.com/go-openapi/loads v0.17.0/go.mod h1:72tmFy5wsWx89uEVddd0RjRWPZm92WRLhf7AC+0+OOU=
-github.com/go-openapi/loads v0.17.2/go.mod h1:72tmFy5wsWx89uEVddd0RjRWPZm92WRLhf7AC+0+OOU=
-github.com/go-openapi/loads v0.18.0/go.mod h1:72tmFy5wsWx89uEVddd0RjRWPZm92WRLhf7AC+0+OOU=
-github.com/go-openapi/loads v0.19.0/go.mod h1:72tmFy5wsWx89uEVddd0RjRWPZm92WRLhf7AC+0+OOU=
-github.com/go-openapi/loads v0.19.2/go.mod h1:QAskZPMX5V0C2gvfkGZzJlINuP7Hx/4+ix5jWFxsNPs=
-github.com/go-openapi/loads v0.19.4/go.mod h1:zZVHonKd8DXyxyw4yfnVjPzBjIQcLt0CCsn0N0ZrQsk=
-github.com/go-openapi/runtime v0.0.0-20180920151709-4f900dc2ade9/go.mod h1:6v9a6LTXWQCdL8k1AO3cvqx5OtZY/Y9wKTgaoP6YRfA=
-github.com/go-openapi/runtime v0.18.0/go.mod h1:uI6pHuxWYTy94zZxgcwJkUWa9wbIlhteGfloI10GD4U=
-github.com/go-openapi/runtime v0.19.0/go.mod h1:OwNfisksmmaZse4+gpV3Ne9AyMOlP1lt4sK4FXt0O64=
-github.com/go-openapi/runtime v0.19.4/go.mod h1:X277bwSUBxVlCYR3r7xgZZGKVvBd/29gLDlFGtJ8NL4=
 github.com/go-openapi/spec v0.0.0-20160808142527-6aced65f8501/go.mod h1:J8+jY1nAiCcj+friV/PDoE1/3eeccG9LYBs0tYvLOWc=
-github.com/go-openapi/spec v0.17.0/go.mod h1:XkF/MOi14NmjsfZ8VtAKf8pIlbZzyoTvZsdfssdxcBI=
-github.com/go-openapi/spec v0.17.2/go.mod h1:XkF/MOi14NmjsfZ8VtAKf8pIlbZzyoTvZsdfssdxcBI=
-github.com/go-openapi/spec v0.18.0/go.mod h1:XkF/MOi14NmjsfZ8VtAKf8pIlbZzyoTvZsdfssdxcBI=
-github.com/go-openapi/spec v0.19.2/go.mod h1:sCxk3jxKgioEJikev4fgkNmwS+3kuYdJtcsZsD5zxMY=
-github.com/go-openapi/spec v0.19.3/go.mod h1:FpwSN1ksY1eteniUU7X0N/BgJ7a4WvBFVA8Lj9mJglo=
-github.com/go-openapi/spec v0.19.4/go.mod h1:FpwSN1ksY1eteniUU7X0N/BgJ7a4WvBFVA8Lj9mJglo=
-github.com/go-openapi/strfmt v0.17.0/go.mod h1:P82hnJI0CXkErkXi8IKjPbNBM6lV6+5pLP5l494TcyU=
-github.com/go-openapi/strfmt v0.17.2/go.mod h1:P82hnJI0CXkErkXi8IKjPbNBM6lV6+5pLP5l494TcyU=
-github.com/go-openapi/strfmt v0.18.0/go.mod h1:P82hnJI0CXkErkXi8IKjPbNBM6lV6+5pLP5l494TcyU=
-github.com/go-openapi/strfmt v0.19.0/go.mod h1:+uW+93UVvGGq2qGaZxdDeJqSAqBqBdl+ZPMF/cC8nDY=
-github.com/go-openapi/strfmt v0.19.2/go.mod h1:0yX7dbo8mKIvc3XSKp7MNfxw4JytCfCD6+bY1AVL9LU=
-github.com/go-openapi/strfmt v0.19.3/go.mod h1:0yX7dbo8mKIvc3XSKp7MNfxw4JytCfCD6+bY1AVL9LU=
 github.com/go-openapi/swag v0.0.0-20160704191624-1d0bd113de87/go.mod h1:DXUve3Dpr1UfpPtxFw+EFuQ41HhCWZfha5jSVRG7C7I=
-github.com/go-openapi/swag v0.17.0/go.mod h1:AByQ+nYG6gQg71GINrmuDXCPWdL640yX49/kXLo40Tg=
-github.com/go-openapi/swag v0.17.2/go.mod h1:AByQ+nYG6gQg71GINrmuDXCPWdL640yX49/kXLo40Tg=
-github.com/go-openapi/swag v0.18.0/go.mod h1:AByQ+nYG6gQg71GINrmuDXCPWdL640yX49/kXLo40Tg=
-github.com/go-openapi/swag v0.19.2/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh66Z9tfKk=
-github.com/go-openapi/swag v0.19.5/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh66Z9tfKk=
-github.com/go-openapi/validate v0.17.2/go.mod h1:Uh4HdOzKt19xGIGm1qHf/ofbX1YQ4Y+MYsct2VUrAJ4=
-github.com/go-openapi/validate v0.18.0/go.mod h1:Uh4HdOzKt19xGIGm1qHf/ofbX1YQ4Y+MYsct2VUrAJ4=
-github.com/go-openapi/validate v0.19.2/go.mod h1:1tRCw7m3jtI8eNWEEliiAqUIcBztB2KDnRCRMUi7GTA=
-github.com/go-openapi/validate v0.19.5/go.mod h1:8DJv2CVJQ6kGNpFW6eV9N3JviE1C85nY1c2z52x1Gk4=
-github.com/go-sql-driver/mysql v1.4.0/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w=
-github.com/go-sql-driver/mysql v1.4.1/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w=
 github.com/go-stack/stack v1.8.0 h1:5SgMzNM5HxrEjV0ww2lTmX6E2Izsfxas4+YHWRs3Lsk=
 github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY=
-github.com/gobuffalo/envy v1.6.5/go.mod h1:N+GkhhZ/93bGZc6ZKhJLP6+m+tCNPKwgSpH9kaifseQ=
-github.com/gobuffalo/envy v1.7.0/go.mod h1:n7DRkBerg/aorDM8kbduw5dN3oXGswK5liaSCx4T5NI=
-github.com/gobuffalo/envy v1.7.1/go.mod h1:FurDp9+EDPE4aIUS3ZLyD+7/9fpx7YRt/ukY6jIHf0w=
-github.com/gobuffalo/flect v0.1.5/go.mod h1:W3K3X9ksuZfir8f/LrfVtWmCDQFfayuylOJ7sz/Fj80=
-github.com/gobuffalo/flect v0.2.0/go.mod h1:W3K3X9ksuZfir8f/LrfVtWmCDQFfayuylOJ7sz/Fj80=
-github.com/gobuffalo/flect v0.2.1/go.mod h1:vmkQwuZYhN5Pc4ljYQZzP+1sq+NEkK+lh20jmEmX3jc=
-github.com/gobuffalo/logger v1.0.1/go.mod h1:2zbswyIUa45I+c+FLXuWl9zSWEiVuthsk8ze5s8JvPs=
-github.com/gobuffalo/packd v0.3.0/go.mod h1:zC7QkmNkYVGKPw4tHpBQ+ml7W/3tIebgeo1b36chA3Q=
-github.com/gobuffalo/packr/v2 v2.7.1/go.mod h1:qYEvAazPaVxy7Y7KR0W8qYEE+RymX74kETFqjFoFlOc=
-github.com/gobwas/glob v0.2.3/go.mod h1:d3Ez4x06l9bZtSvzIay5+Yzi0fmZzPgnTbPcKjJAkT8=
-github.com/gocql/gocql v0.0.0-20190301043612-f6df8288f9b4/go.mod h1:4Fw1eo5iaEhDUs8XyuhSVCVy52Jq3L+/3GJgYkwc+/0=
-github.com/godbus/dbus v0.0.0-20190422162347-ade71ed3457e/go.mod h1:bBOAhwG1umN6/6ZUMtDFBMQR8jRg9O75tm9K00oMsK4=
-github.com/gofrs/flock v0.7.1/go.mod h1:F1TvTiK9OcQqauNUHlbJvyl9Qa1QvF/gOUDKA14jxHU=
-github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=
-github.com/gogo/protobuf v1.2.0/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=
-github.com/gogo/protobuf v1.2.1/go.mod h1:hp+jE20tsWTFYpLwKvXlhS1hjn+gTNwPg2I6zVXpSg4=
-github.com/gogo/protobuf v1.2.2-0.20190730201129-28a6bbf47e48/go.mod h1:SlYgWuQ5SjCEi6WLHjHCa1yvBfUnHcTbrrZtXPKa29o=
 github.com/gogo/protobuf v1.3.1/go.mod h1:SlYgWuQ5SjCEi6WLHjHCa1yvBfUnHcTbrrZtXPKa29o=
-github.com/golang-migrate/migrate/v4 v4.6.2/go.mod h1:JYi6reN3+Z734VZ0akNuyOJNcrg45ZL7LDBMW3WGJL0=
-github.com/golang-sql/civil v0.0.0-20190719163853-cb61b32ac6fe/go.mod h1:8vg3r2VgvsThLBIFL93Qb5yWzgyZWhEmBwUJWevAkK0=
+github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q=
+github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q=
 github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
-github.com/golang/groupcache v0.0.0-20160516000752-02826c3e7903/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
-github.com/golang/groupcache v0.0.0-20190129154638-5b532d6fd5ef/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
 github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
-github.com/golang/groupcache v0.0.0-20191027212112-611e8accdfc9/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
 github.com/golang/groupcache v0.0.0-20191227052852-215e87163ea7/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
+github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
 github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
 github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
 github.com/golang/mock v1.3.1/go.mod h1:sBzyDLLjw3U8JLTeZvSv8jJB+tU5PVekmnlKIyFUx0Y=
-github.com/golang/protobuf v0.0.0-20161109072736-4bd1920723d7/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
+github.com/golang/mock v1.4.0/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw=
+github.com/golang/mock v1.4.1/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw=
+github.com/golang/mock v1.4.3/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw=
+github.com/golang/mock v1.4.4/go.mod h1:l3mdAwkq5BuhzHwde/uurv3sEJeZMXNpwsxVWU71h+4=
 github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
 github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
 github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
 github.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw=
+github.com/golang/protobuf v1.3.4/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw=
+github.com/golang/protobuf v1.3.5/go.mod h1:6O5/vntMXwX2lRkT1hjjk0nAC1IDOTvTlVgjlRvqsdk=
 github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8=
 github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA=
 github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs=
@@ -348,509 +111,159 @@ github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:W
 github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0=
 github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QDs8UjoX8=
 github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=
-github.com/golang/snappy v0.0.0-20170215233205-553a64147049/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
-github.com/golang/snappy v0.0.0-20180518054509-2e65f85255db/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
+github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk=
+github.com/golang/protobuf v1.5.2 h1:ROPKBNFfQgOUMifHyP+KYbvpjbdoFNs+aK7DXlji0Tw=
+github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY=
 github.com/golang/snappy v0.0.1 h1:Qgr9rKW7uDUkrbSmQeiDsGa8SjGyCOGtuasMWwvp2P4=
 github.com/golang/snappy v0.0.1/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
-github.com/golangplus/bytes v0.0.0-20160111154220-45c989fe5450/go.mod h1:Bk6SMAONeMXrxql8uvOKuAZSu8aM5RUGv+1C6IJaEho=
-github.com/golangplus/fmt v0.0.0-20150411045040-2a5d6d7d2995/go.mod h1:lJgMEyOkYFkPcDKwRXegd+iM6E7matEszMG5HhwytU8=
-github.com/golangplus/testing v0.0.0-20180327235837-af21d9c3145e/go.mod h1:0AA//k/eakGydO4jKRoRL2j92ZKSzTgj9tclaCrvXHk=
 github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
 github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
 github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M=
 github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
 github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
-github.com/google/go-cmp v0.4.0 h1:xsAVV57WRhGj6kEIi8ReJzQlHHqcBYCElAvkovg3B/4=
 github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
-github.com/google/go-github v17.0.0+incompatible/go.mod h1:zLgOLi98H3fifZn+44m+umXrS52loVEgC2AApnigrVQ=
-github.com/google/go-querystring v1.0.0/go.mod h1:odCYkC5MyYFN7vkCjXpyrEuKhc/BUO6wN/zVPAxq5ck=
-github.com/google/gofuzz v0.0.0-20161122191042-44d81051d367/go.mod h1:HP5RmnzzSNb993RKQDq4+1A4ia9nllfqcQFTQJedwGI=
+github.com/google/go-cmp v0.4.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
+github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
+github.com/google/go-cmp v0.5.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
+github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
+github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
+github.com/google/go-cmp v0.5.6 h1:BKbKCqvP6I+rmFHt06ZmyQtvB8xAkWdhFyr0ZUNZcxQ=
 github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
 github.com/google/gofuzz v1.1.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
+github.com/google/gofuzz v1.2.0 h1:xRy4A+RhZaiKjJ1bPfwQ8sedCA+YS2YcCHW6ec7JMi0=
+github.com/google/gofuzz v1.2.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
 github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs=
+github.com/google/martian/v3 v3.0.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0=
 github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc=
 github.com/google/pprof v0.0.0-20190515194954-54271f7e092f/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc=
-github.com/google/pprof v0.0.0-20190723021845-34ac40c74b70/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc=
 github.com/google/pprof v0.0.0-20191218002539-d4f498aebedc/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=
+github.com/google/pprof v0.0.0-20200212024743-f11f1df84d12/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=
+github.com/google/pprof v0.0.0-20200229191704-1ebb73c60ed3/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=
+github.com/google/pprof v0.0.0-20200430221834-fc25d7d30c6d/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=
+github.com/google/pprof v0.0.0-20200708004538-1a94d8640e99/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=
 github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI=
-github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510/go.mod h1:pupxD2MaaD3pAXIBCelhxNneeOaAeabZDe5s4K6zSpQ=
-github.com/google/uuid v1.0.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
-github.com/google/uuid v1.1.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
 github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
-github.com/googleapis/gax-go v2.0.2+incompatible/go.mod h1:SFVmujtThgffbyetf+mdk2eWhX2bMyUtNHzFKcPA9HY=
 github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg=
 github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk=
-github.com/googleapis/gnostic v0.0.0-20170729233727-0c5108395e2d/go.mod h1:sJBsCZ4ayReDTBIg8b9dl28c5xFWyhBTVRp3pOg5EKY=
-github.com/googleapis/gnostic v0.3.1/go.mod h1:on+2t9HRStVgn95RSsFWFz+6Q0Snyqv1awfrALZdbtU=
 github.com/googleapis/gnostic v0.4.1/go.mod h1:LRhVm6pbyptWbWbuZ38d1eyptfvIytN3ir6b65WBswg=
-github.com/gophercloud/gophercloud v0.2.0/go.mod h1:vxM41WHh5uqHVBMZHzuwNOHh8XEoIEcSTewFxm1c5g8=
-github.com/gophercloud/gophercloud v0.3.0/go.mod h1:vxM41WHh5uqHVBMZHzuwNOHh8XEoIEcSTewFxm1c5g8=
-github.com/gophercloud/gophercloud v0.6.0/go.mod h1:GICNByuaEBibcjmjvI7QvYJSZEbGkcYwAR7EZK2WMqM=
-github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY=
-github.com/gopherjs/gopherjs v0.0.0-20191106031601-ce3c9ade29de/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY=
-github.com/gorilla/context v1.1.1/go.mod h1:kBGZzfjB9CEq2AlWe17Uuf7NDRt0dE0s8S51q0aT7Yg=
-github.com/gorilla/handlers v0.0.0-20150720190736-60c7bfde3e33/go.mod h1:Qkdc/uu4tH4g6mTK6auzZ766c4CA0Ng8+o/OAirnOIQ=
-github.com/gorilla/mux v1.6.2/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs=
-github.com/gorilla/mux v1.7.1/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs=
-github.com/gorilla/mux v1.7.2/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs=
-github.com/gorilla/websocket v0.0.0-20170926233335-4201258b820c/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ=
-github.com/gorilla/websocket v1.4.0/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ=
-github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
-github.com/gosuri/uitable v0.0.4/go.mod h1:tKR86bXuXPZazfOTG1FIzvjIdXzd0mo4Vtn16vt0PJo=
+github.com/googleapis/gnostic v0.5.5 h1:9fHAtK0uDfpveeqqo1hkEZJcFvYXAiCN3UutL8F9xHw=
+github.com/googleapis/gnostic v0.5.5/go.mod h1:7+EbHbldMins07ALC74bsA81Ovc97DwqyJO1AENw9kA=
 github.com/gregjones/httpcache v0.0.0-20180305231024-9cad4c3443a7/go.mod h1:FecbI9+v66THATjSRHfNgh1IVFe/9kFxbXtjV0ctIMA=
-github.com/grpc-ecosystem/go-grpc-middleware v1.0.0/go.mod h1:FiyG127CGDf3tlThmgyCl78X/SZQqEOJBCDaAfeWzPs=
-github.com/grpc-ecosystem/go-grpc-middleware v1.0.1-0.20190118093823-f849b5445de4/go.mod h1:FiyG127CGDf3tlThmgyCl78X/SZQqEOJBCDaAfeWzPs=
-github.com/grpc-ecosystem/go-grpc-middleware v1.1.0/go.mod h1:f5nM7jw/oeRSadq3xCzHAvxcr8HZnzsqU6ILg/0NiiE=
-github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0/go.mod h1:8NvIoxWQoOIhqOTXgfV/d3M/q6VIi02HzZEHgUlZvzk=
-github.com/grpc-ecosystem/grpc-gateway v1.9.0/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY=
-github.com/grpc-ecosystem/grpc-gateway v1.9.4/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY=
-github.com/grpc-ecosystem/grpc-gateway v1.9.5/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY=
-github.com/grpc-ecosystem/grpc-gateway v1.12.1/go.mod h1:8XEsbTttt/W+VvjtQhLACqCisSPWTxCZ7sBRjU6iH9c=
-github.com/grpc-ecosystem/grpc-health-probe v0.2.1-0.20181220223928-2bf0a5b182db/go.mod h1:uBKkC2RbarFsvS5jMJHpVhTLvGlGQj9JJwkaePE3FWI=
-github.com/hailocab/go-hostpool v0.0.0-20160125115350-e80d13ce29ed/go.mod h1:tMWxXQ9wFIaZeTI9F+hmhFiGpFmhOHzyShyFUhRm0H4=
-github.com/hashicorp/consul/api v1.1.0/go.mod h1:VmuI/Lkw1nC05EYQWNKwWGbkg+FbDBtguAZLlVdkD9Q=
-github.com/hashicorp/consul/api v1.3.0/go.mod h1:MmDNSzIMUjNpY/mQ398R4bk2FnqQLoPndWW5VkKPlCE=
-github.com/hashicorp/consul/sdk v0.1.1/go.mod h1:VKf9jXwCTEY1QZP2MOLRhb5i/I/ssyNV1vwHyQBF0x8=
-github.com/hashicorp/consul/sdk v0.3.0/go.mod h1:VKf9jXwCTEY1QZP2MOLRhb5i/I/ssyNV1vwHyQBF0x8=
-github.com/hashicorp/errwrap v0.0.0-20141028054710-7554cd9344ce/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4=
-github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4=
-github.com/hashicorp/go-cleanhttp v0.5.0/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80=
-github.com/hashicorp/go-cleanhttp v0.5.1/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80=
-github.com/hashicorp/go-immutable-radix v1.0.0/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60=
-github.com/hashicorp/go-immutable-radix v1.1.0/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60=
-github.com/hashicorp/go-msgpack v0.5.3/go.mod h1:ahLV/dePpqEmjfWmKiqvPkv/twdG7iPBM1vqhUKIvfM=
-github.com/hashicorp/go-msgpack v0.5.5/go.mod h1:ahLV/dePpqEmjfWmKiqvPkv/twdG7iPBM1vqhUKIvfM=
-github.com/hashicorp/go-multierror v0.0.0-20161216184304-ed905158d874/go.mod h1:JMRHfdO9jKNzS/+BTlxCjKNQHg/jZAft8U7LloJvN7I=
-github.com/hashicorp/go-multierror v1.0.0/go.mod h1:dHtQlpGsu+cZNNAkkCN/P3hoUDHhCYQXV3UM06sGGrk=
-github.com/hashicorp/go-retryablehttp v0.5.3/go.mod h1:9B5zBasrRhHXnJnui7y6sL7es7NDiJgTc6Er0maI1Xs=
-github.com/hashicorp/go-rootcerts v1.0.0/go.mod h1:K6zTfqpRlCUIjkwsN4Z+hiSfzSTQa6eBIzfwKfwNnHU=
-github.com/hashicorp/go-rootcerts v1.0.1/go.mod h1:pqUvnprVnM5bf7AOirdbb01K4ccR319Vf4pU3K5EGc8=
-github.com/hashicorp/go-sockaddr v1.0.0/go.mod h1:7Xibr9yA9JjQq1JpNB2Vw7kxv8xerXegt+ozgdvDeDU=
-github.com/hashicorp/go-sockaddr v1.0.2/go.mod h1:rB4wwRAUzs07qva3c5SdrY/NEtAUjGlgmH/UkBUC97A=
-github.com/hashicorp/go-syslog v1.0.0/go.mod h1:qPfqrKkXGihmCqbJM2mZgkZGvKG1dFdvsLplgctolz4=
-github.com/hashicorp/go-uuid v1.0.0/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro=
-github.com/hashicorp/go-uuid v1.0.1/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro=
-github.com/hashicorp/go-version v1.1.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA=
-github.com/hashicorp/go.net v0.0.1/go.mod h1:hjKkEWcCURg++eb33jQU7oqQcI9XDCnUzHA0oac0k90=
 github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
 github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
-github.com/hashicorp/golang-lru v0.5.3/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4=
-github.com/hashicorp/golang-lru v0.5.4/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4=
-github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ=
-github.com/hashicorp/logutils v1.0.0/go.mod h1:QIAnNjmIWmVIIkWDTG1z5v++HQmx9WQRO+LraFDTW64=
-github.com/hashicorp/mdns v1.0.0/go.mod h1:tL+uN++7HEJ6SQLQ2/p+z2pH24WQKWjBPkE0mNTz8vQ=
-github.com/hashicorp/memberlist v0.1.3/go.mod h1:ajVTdAv/9Im8oMAAj5G31PhhMCZJV2pPBoIllUwCN7I=
-github.com/hashicorp/memberlist v0.1.4/go.mod h1:ajVTdAv/9Im8oMAAj5G31PhhMCZJV2pPBoIllUwCN7I=
-github.com/hashicorp/memberlist v0.1.5/go.mod h1:ajVTdAv/9Im8oMAAj5G31PhhMCZJV2pPBoIllUwCN7I=
-github.com/hashicorp/serf v0.8.2/go.mod h1:6hOLApaqBFA1NXqRQAsxw9QxuDEvNxSQRwA/JwenrHc=
-github.com/hashicorp/serf v0.8.5/go.mod h1:UpNcs7fFbpKIyZaUuSW6EPiH+eZC7OuyFD+wc1oal+k=
+github.com/hpcloud/tail v1.0.0 h1:nfCOvKYfkgYP8hkirhJocXT2+zOD8yUNjXaWfTlyFKI=
 github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU=
-github.com/huandu/xstrings v1.3.1/go.mod h1:y5/lhBue+AyNmUVz9RLU9xbLR0o4KIIExikq4ovT0aE=
-github.com/iancoleman/strcase v0.0.0-20190422225806-e506e3ef7365/go.mod h1:SK73tn/9oHe+/Y0h39VT4UCxmurVJkR5NA7kMEAOgSE=
 github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc=
 github.com/imdario/mergo v0.3.5/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJh5FfA=
-github.com/imdario/mergo v0.3.6/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJh5FfA=
-github.com/imdario/mergo v0.3.7/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJh5FfA=
-github.com/imdario/mergo v0.3.8/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJh5FfA=
-github.com/imdario/mergo v0.3.9/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJh5FfA=
-github.com/imdario/mergo v0.3.11/go.mod h1:jmQim1M+e3UYxmgPu/WyfjB3N3VflVyUjjjwH0dnCYA=
-github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8=
-github.com/influxdata/influxdb v1.7.7/go.mod h1:qZna6X/4elxqT3yI9iZYdZrWWdeFOOprn86kgg4+IzY=
-github.com/jackc/fake v0.0.0-20150926172116-812a484cc733/go.mod h1:WrMFNQdiFJ80sQsxDoMokWK1W5TQtxBFNpzWTD84ibQ=
-github.com/jackc/pgx v3.2.0+incompatible/go.mod h1:0ZGrqGqkRlliWnWB4zKnWtjbSWbGkVEFm4TeybAXq+I=
-github.com/jessevdk/go-flags v0.0.0-20180331124232-1c38ed7ad0cc/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI=
-github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI=
-github.com/jmespath/go-jmespath v0.0.0-20160202185014-0b12d6b521d8/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k=
-github.com/jmespath/go-jmespath v0.0.0-20160803190731-bd40a432e4c7/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k=
-github.com/jmespath/go-jmespath v0.0.0-20180206201540-c2b33e8439af/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k=
-github.com/jmoiron/sqlx v1.2.0/go.mod h1:1FEQNm3xlJgrMD+FBdI9+xvCksHtbpVBBw5dYhBSsks=
-github.com/joefitzgerald/rainbow-reporter v0.1.0/go.mod h1:481CNgqmVHQZzdIbN52CupLJyoVwB10FQ/IQlF1pdL8=
-github.com/joeshaw/multierror v0.0.0-20140124173710-69b34d4ec901/go.mod h1:Z86h9688Y0wesXCyonoVr47MasHilkuLMqGhRZ4Hpak=
-github.com/joho/godotenv v1.3.0/go.mod h1:7hK45KPybAkOC6peb+G5yklZfMxEjkZhHbwpqxOKXbg=
-github.com/jonboulle/clockwork v0.1.0/go.mod h1:Ii8DK3G1RaLaWxj9trq07+26W01tbo22gdxWY5EU2bo=
-github.com/jpillora/backoff v1.0.0/go.mod h1:J/6gKK9jxlEcS3zixgDgUAsiuZ7yrSoa/FX5e0EB2j4=
-github.com/json-iterator/go v0.0.0-20180612202835-f2b4162afba3/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU=
+github.com/imdario/mergo v0.3.12 h1:b6R2BslTbIEToALKP7LxUvijTsNI9TAe80pLWN2g/HU=
+github.com/imdario/mergo v0.3.12/go.mod h1:jmQim1M+e3UYxmgPu/WyfjB3N3VflVyUjjjwH0dnCYA=
 github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU=
-github.com/json-iterator/go v1.1.7/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
-github.com/json-iterator/go v1.1.8/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
-github.com/json-iterator/go v1.1.9/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
 github.com/json-iterator/go v1.1.10/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
-github.com/jsonnet-bundler/jsonnet-bundler v0.3.1/go.mod h1:/by7P/OoohkI3q4CgSFqcoFsVY+IaNbzOVDknEsKDeU=
+github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM=
+github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo=
 github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU=
 github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/XSXhF0NWZEnDohbsk=
-github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU=
-github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w=
-github.com/julienschmidt/httprouter v1.3.0/go.mod h1:JR6WtHb+2LUe8TCKY3cZOxFyyO8IZAc4RVcycCCAKdM=
-github.com/kardianos/osext v0.0.0-20190222173326-2bc1f35cddc0/go.mod h1:1NbS8ALrpOvjt0rHPNLyCIeMtbizbir8U//inJ+zuB8=
-github.com/kisielk/errcheck v1.1.0/go.mod h1:EZBBE59ingxPouuu3KfxchcWSUPOHkagtvWXihfKN4Q=
 github.com/kisielk/errcheck v1.2.0/go.mod h1:/BMXB+zMLi60iA8Vv6Ksmxu/1UDYcXs4uQLJ+jE2L00=
+github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8=
 github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
-github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
-github.com/konsorten/go-windows-terminal-sequences v1.0.2/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
-github.com/konsorten/go-windows-terminal-sequences v1.0.3/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
-github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc=
+github.com/klauspost/compress v1.13.6 h1:P76CopJELS0TiO2mebmnzgWaajssP/EszplttgQxcgc=
+github.com/klauspost/compress v1.13.6/go.mod h1:/3/Vjq9QcHkK5uEr5lBEmyoZ1iFhe47etQ6QUkpK6sk=
 github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
 github.com/kr/pretty v0.2.0/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI=
+github.com/kr/pretty v0.2.1 h1:Fmg33tUaq4/8ym9TJN1x7sLJnHVwhP33CNkpYV/7rwI=
 github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
-github.com/kr/pty v1.1.5/go.mod h1:9r2w37qlBe7rQ6e1fg1S/9xpWHSnaqNdHD3WcMdbPDA=
+github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE=
 github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
-github.com/kshvakov/clickhouse v1.3.5/go.mod h1:DMzX7FxRymoNkVgizH0DWAL8Cur7wHLgx3MUnGwJqpE=
-github.com/kylelemons/godebug v0.0.0-20160406211939-eadb3ce320cb/go.mod h1:B69LEHPfb2qLo0BaaOLcbitczOKLWTsrBG9LczfCD4k=
-github.com/kylelemons/godebug v0.0.0-20170820004349-d65d576e9348/go.mod h1:B69LEHPfb2qLo0BaaOLcbitczOKLWTsrBG9LczfCD4k=
-github.com/lann/builder v0.0.0-20180802200727-47ae307949d0/go.mod h1:dXGbAdH5GtBTC4WfIxhKZfyBF/HBFgRZSWwZ9g/He9o=
-github.com/lann/ps v0.0.0-20150810152359-62de8c46ede0/go.mod h1:vmVJ0l/dxyfGW6FmdpVm2joNMFikkuWg0EoCKLGUMNw=
-github.com/leanovate/gopter v0.2.4/go.mod h1:gNcbPWNEWRe4lm+bycKqxUYoH5uoVje5SkOJ3uoLer8=
-github.com/lib/pq v1.0.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo=
-github.com/lib/pq v1.2.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo=
-github.com/lib/pq v1.3.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo=
-github.com/liggitt/tabwriter v0.0.0-20181228230101-89fcab3d43de/go.mod h1:zAbeS9B/r2mtpb6U+EI2rYA5OAXxsYw6wTamcNW+zcE=
-github.com/lightstep/lightstep-tracer-common/golang/gogo v0.0.0-20190605223551-bc2310a04743/go.mod h1:qklhhLq1aX+mtWk9cPHPzaBjWImj5ULL6C7HFJtXQMM=
-github.com/lightstep/lightstep-tracer-go v0.18.0/go.mod h1:jlF1pusYV4pidLvZ+XD0UBX0ZE6WURAspgAczcDHrL4=
-github.com/lithammer/dedent v1.1.0/go.mod h1:jrXYCQtgg0nJiN+StA2KgR7w6CiQNv9Fd/Z9BP0jIOc=
-github.com/lovoo/gcloud-opentracing v0.3.0/go.mod h1:ZFqk2y38kMDDikZPAK7ynTTGuyt17nSPdS3K5e+ZTBY=
-github.com/magiconair/properties v1.8.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ=
-github.com/magiconair/properties v1.8.1/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ=
 github.com/mailru/easyjson v0.0.0-20160728113105-d5b7844b561a/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc=
-github.com/mailru/easyjson v0.0.0-20180823135443-60711f1a8329/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc=
-github.com/mailru/easyjson v0.0.0-20190312143242-1de009706dbe/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc=
-github.com/mailru/easyjson v0.0.0-20190614124828-94de47d64c63/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc=
-github.com/mailru/easyjson v0.0.0-20190626092158-b2ccc519800e/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc=
-github.com/mailru/easyjson v0.7.0/go.mod h1:KAzv3t3aY1NaHWoQz1+4F1ccyAH66Jk7yos7ldAVICs=
-github.com/markbates/inflect v1.0.4/go.mod h1:1fR9+pO2KHEO9ZRtto13gDwwZaAKstQzferVeWqbgNs=
-github.com/marstr/guid v1.1.0/go.mod h1:74gB1z2wpxxInTG6yaqA7KrtM0NZ+RbrcqDvYHefzho=
-github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU=
-github.com/mattn/go-colorable v0.1.2/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE=
-github.com/mattn/go-ieproxy v0.0.0-20190610004146-91bb50d98149/go.mod h1:31jz6HNzdxOmlERGGEc4v/dMssOfmp2p5bT/okiKFFc=
-github.com/mattn/go-ieproxy v0.0.0-20190702010315-6dee0af9227d/go.mod h1:31jz6HNzdxOmlERGGEc4v/dMssOfmp2p5bT/okiKFFc=
-github.com/mattn/go-ieproxy v0.0.0-20191113090002-7c0f6868bffe/go.mod h1:pYabZ6IHcRpFh7vIaLfK7rdcWgFEb3SFJ6/gNWuh88E=
-github.com/mattn/go-isatty v0.0.3/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4=
-github.com/mattn/go-isatty v0.0.4/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4=
-github.com/mattn/go-isatty v0.0.6/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s=
-github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s=
-github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU=
-github.com/mattn/go-runewidth v0.0.2/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU=
-github.com/mattn/go-runewidth v0.0.4/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU=
-github.com/mattn/go-runewidth v0.0.6/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI=
-github.com/mattn/go-shellwords v1.0.10/go.mod h1:EZzvwXDESEeg03EKmM+RmDnNOPKG4lLtQsUlTZDWQ8Y=
-github.com/mattn/go-sqlite3 v1.9.0/go.mod h1:FPy6KqzDD04eiIsT53CuJW3U88zkxoIYsOqkbpncsNc=
-github.com/mattn/go-sqlite3 v1.10.0/go.mod h1:FPy6KqzDD04eiIsT53CuJW3U88zkxoIYsOqkbpncsNc=
-github.com/mattn/go-sqlite3 v1.12.0/go.mod h1:FPy6KqzDD04eiIsT53CuJW3U88zkxoIYsOqkbpncsNc=
-github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0=
-github.com/matttproud/golang_protobuf_extensions v1.0.2-0.20181231171920-c182affec369/go.mod h1:BSXmuO+STAnVfrANrmjBb36TMTDstsz7MSK+HVaYKv4=
-github.com/maxbrunsfeld/counterfeiter/v6 v6.2.2/go.mod h1:eD9eIE7cdwcMi9rYluz88Jz2VyhSmden33/aXg4oVIY=
-github.com/miekg/dns v1.0.14/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg=
-github.com/miekg/dns v1.1.15/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg=
-github.com/miekg/dns v1.1.22/go.mod h1:bPDLeHnStXmXAq1m/Ch/hvfNHr14JKNPMBo3VZKjuso=
-github.com/mikefarah/yaml/v2 v2.4.0/go.mod h1:ahVqZF4n1W4NqwvVnZzC4es67xsW9uR/RRf2RRxieJU=
-github.com/mikefarah/yq/v2 v2.4.1/go.mod h1:i8SYf1XdgUvY2OFwSqGAtWOOgimD2McJ6iutoxRm4k0=
-github.com/minio/minio-go/v6 v6.0.49/go.mod h1:qD0lajrGW49lKZLtXKtCB4X/qkMf0a5tBvN2PaZg7Gg=
-github.com/minio/sha256-simd v0.1.1/go.mod h1:B5e1o+1/KgNmWrSQK08Y6Z1Vb5pwIktudl0J58iy0KM=
-github.com/mitchellh/cli v1.0.0/go.mod h1:hNIlj7HEI86fIcpObd7a0FcrxTWetlwJDGcceTlRvqc=
-github.com/mitchellh/copystructure v1.0.0/go.mod h1:SNtv71yrdKgLRyLFxmLdkAbkKEFWgYaq1OVrnRcwhnw=
-github.com/mitchellh/go-homedir v1.0.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0=
-github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0=
-github.com/mitchellh/go-testing-interface v1.0.0/go.mod h1:kRemZodwjscx+RGhAo8eIhFbs2+BFgRtFPeD/KE+zxI=
-github.com/mitchellh/go-wordwrap v1.0.0/go.mod h1:ZXFpozHsX6DPmq2I0TCekCxypsnAUbP2oI0UX1GXzOo=
-github.com/mitchellh/gox v0.4.0/go.mod h1:Sd9lOJ0+aimLBi73mGofS1ycjY8lL3uZM3JPS42BGNg=
-github.com/mitchellh/hashstructure v0.0.0-20170609045927-2bca23e0e452/go.mod h1:QjSHrPWS+BGUVBYkbTZWEnOh3G1DutKwClXU/ABz6AQ=
-github.com/mitchellh/iochan v1.0.0/go.mod h1:JwYml1nuB7xOzsp52dPpHFffvOCDupsG0QubkSMEySY=
-github.com/mitchellh/mapstructure v0.0.0-20160808181253-ca63d7c062ee/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y=
-github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y=
-github.com/mitchellh/osext v0.0.0-20151018003038-5e2d6d41470f/go.mod h1:OkQIRizQZAeMln+1tSwduZz7+Af5oFlKirV/MSYes2A=
-github.com/mitchellh/reflectwalk v1.0.0/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw=
-github.com/moby/term v0.0.0-20200312100748-672ec06f55cd/go.mod h1:DdlQx2hp0Ss5/fLikoLlEeIYiATotOjgB//nb973jeo=
 github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
+github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg=
 github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
-github.com/modern-go/reflect2 v0.0.0-20180320133207-05fbef0ca5da/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
 github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
 github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
-github.com/morikuni/aec v0.0.0-20170113033406-39771216ff4c/go.mod h1:BbKIizmSmc5MMPqRYbxO4ZU0S0+P200+tUnFx7PXmsc=
-github.com/morikuni/aec v1.0.0/go.mod h1:BbKIizmSmc5MMPqRYbxO4ZU0S0+P200+tUnFx7PXmsc=
-github.com/mozillazg/go-cos v0.13.0/go.mod h1:Zp6DvvXn0RUOXGJ2chmWt2bLEqRAnJnS3DnAZsJsoaE=
-github.com/mozillazg/go-httpheader v0.2.1/go.mod h1:jJ8xECTlalr6ValeXYdOF8fFUISeBAdw6E61aqQma60=
+github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M=
+github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk=
+github.com/montanaflynn/stats v0.0.0-20171201202039-1bf9dbcd8cbe/go.mod h1:wL8QJuTMNUDYhXwkmfOly8iTdp5TEcJFWZD2D7SIkUc=
 github.com/munnerz/goautoneg v0.0.0-20120707110453-a547fc61f48d/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ=
-github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U=
-github.com/mwitkow/go-conntrack v0.0.0-20190716064945-2f068394615f/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U=
 github.com/mxk/go-flowrate v0.0.0-20140419014527-cca7078d478f/go.mod h1:ZdcZmHo+o7JKHSa8/e818NopupXU1YMK5fe1lsApnBw=
-github.com/nakagami/firebirdsql v0.0.0-20190310045651-3c02a58cfed8/go.mod h1:86wM1zFnC6/uDBfZGNwB65O+pR2OFi5q/YQaEUid1qA=
-github.com/ncw/swift v1.0.47/go.mod h1:23YIA4yWVnGwv2dQlN4bB7egfYX6YLn0Yo/S6zZO/ZM=
-github.com/oklog/run v1.0.0/go.mod h1:dlhp/R75TPv97u0XWUtDeV/lRKWPKSdTuV0TZvrmrQA=
-github.com/oklog/ulid v0.0.0-20170117200651-66bb6560562f/go.mod h1:CirwcVhetQ6Lv90oh/F+FBtV6XMibvdAFo93nm5qn4U=
-github.com/oklog/ulid v1.3.1/go.mod h1:CirwcVhetQ6Lv90oh/F+FBtV6XMibvdAFo93nm5qn4U=
-github.com/olekukonko/tablewriter v0.0.0-20170122224234-a0225b3f23b5/go.mod h1:vsDQFd/mU46D+Z4whnwzcISnGGzXWMclvtLoiIKAKIo=
-github.com/olekukonko/tablewriter v0.0.1/go.mod h1:vsDQFd/mU46D+Z4whnwzcISnGGzXWMclvtLoiIKAKIo=
-github.com/olekukonko/tablewriter v0.0.2/go.mod h1:rSAaSIOAGT9odnlyGlUfAJaoc5w2fSBUmeGDbRWPxyQ=
 github.com/onsi/ginkgo v0.0.0-20170829012221-11459a886d9c/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
 github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
-github.com/onsi/ginkgo v1.7.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
-github.com/onsi/ginkgo v1.8.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
-github.com/onsi/ginkgo v1.10.1/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
-github.com/onsi/ginkgo v1.10.3/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
+github.com/onsi/ginkgo v1.11.0 h1:JAKSXpt1YjtLA7YpPiqO9ss6sNXEsPfSGdwN0UHqzrw=
 github.com/onsi/ginkgo v1.11.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
-github.com/onsi/ginkgo v1.12.0/go.mod h1:oUhWkIvk5aDxtKvDDuw8gItl8pKl42LzjC9KZE0HfGg=
 github.com/onsi/gomega v0.0.0-20170829124025-dcabb60a477c/go.mod h1:C1qb7wdrVGGVU+Z6iS04AVkA3Q65CEZX59MT0QO5uiA=
-github.com/onsi/gomega v1.4.3/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY=
-github.com/onsi/gomega v1.5.0/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY=
+github.com/onsi/gomega v1.7.0 h1:XPnZz8VVBHjVsy1vzJmRwIcSwiUO+JFfrv/xGiigmME=
 github.com/onsi/gomega v1.7.0/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY=
-github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY=
-github.com/onsi/gomega v1.8.1/go.mod h1:Ho0h+IUsWyvy1OpqCwxlQ/21gkhVunqlU8fDGcoTdcA=
-github.com/onsi/gomega v1.9.0/go.mod h1:Ho0h+IUsWyvy1OpqCwxlQ/21gkhVunqlU8fDGcoTdcA=
-github.com/opencontainers/go-digest v0.0.0-20170106003457-a6d0ee40d420/go.mod h1:cMLVZDEM3+U2I4VmLI6N8jQYUd2OVphdqWwCJHrFt2s=
-github.com/opencontainers/go-digest v0.0.0-20180430190053-c9281466c8b2/go.mod h1:cMLVZDEM3+U2I4VmLI6N8jQYUd2OVphdqWwCJHrFt2s=
-github.com/opencontainers/go-digest v1.0.0-rc1/go.mod h1:cMLVZDEM3+U2I4VmLI6N8jQYUd2OVphdqWwCJHrFt2s=
-github.com/opencontainers/image-spec v1.0.0/go.mod h1:BtxoFyWECRxE4U/7sNtV5W15zMzWCbyJoFRP3s7yZA0=
-github.com/opencontainers/image-spec v1.0.1/go.mod h1:BtxoFyWECRxE4U/7sNtV5W15zMzWCbyJoFRP3s7yZA0=
-github.com/opencontainers/image-spec v1.0.2-0.20190823105129-775207bd45b6/go.mod h1:BtxoFyWECRxE4U/7sNtV5W15zMzWCbyJoFRP3s7yZA0=
-github.com/opencontainers/runc v0.0.0-20190115041553-12f6a991201f/go.mod h1:qT5XzbpPznkRYVz/mWwUaVBUv2rmF59PVA73FjuZG0U=
-github.com/opencontainers/runc v0.1.1/go.mod h1:qT5XzbpPznkRYVz/mWwUaVBUv2rmF59PVA73FjuZG0U=
-github.com/opencontainers/runtime-spec v0.1.2-0.20190507144316-5b71a03e2700/go.mod h1:jwyrGlmzljRJv/Fgzds9SsS/C5hL+LL3ko9hs6T5lQ0=
-github.com/opencontainers/runtime-tools v0.0.0-20181011054405-1d69bd0f9c39/go.mod h1:r3f7wjNzSs2extwzU3Y+6pKfobzPh+kKFJ3ofN+3nfs=
-github.com/openshift/origin v0.0.0-20160503220234-8f127d736703/go.mod h1:0Rox5r9C8aQn6j1oAOQ0c1uC86mYbUFObzjBRvUKHII=
-github.com/openshift/prom-label-proxy v0.1.1-0.20191016113035-b8153a7f39f1/go.mod h1:p5MuxzsYP1JPsNGwtjtcgRHHlGziCJJfztff91nNixw=
-github.com/opentracing-contrib/go-stdlib v0.0.0-20190519235532-cf7a6c988dc9/go.mod h1:PLldrQSroqzH70Xl+1DQcGnefIbqsKR7UDaiux3zV+w=
-github.com/opentracing/basictracer-go v1.0.0/go.mod h1:QfBfYuafItcjQuMwinw9GhYKwFXS9KnPs5lxoYwgW74=
-github.com/opentracing/opentracing-go v1.0.2/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o=
-github.com/opentracing/opentracing-go v1.1.0/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o=
-github.com/openzipkin/zipkin-go v0.1.6/go.mod h1:QgAqvLzwWbR/WpD4A3cGpPtJrZXNIiJc5AZX7/PBEpw=
-github.com/operator-framework/api v0.3.7-0.20200602203552-431198de9fc2/go.mod h1:Xbje9x0SHmh0nihE21kpesB38vk3cyxnE6JdDS8Jo1Q=
-github.com/operator-framework/api v0.3.8/go.mod h1:Xbje9x0SHmh0nihE21kpesB38vk3cyxnE6JdDS8Jo1Q=
-github.com/operator-framework/operator-registry v1.12.6-0.20200611222234-275301b779f8/go.mod h1:loVINznYhgBIkmv83kU4yee88RS0BBk+hqOw9r4bhJk=
-github.com/operator-framework/operator-sdk v0.19.0/go.mod h1:8MR6CguLizat2RGjdSMifGwW6mEMwKqAtZnSUHJ6SxU=
-github.com/otiai10/copy v1.2.0/go.mod h1:rrF5dJ5F0t/EWSYODDu4j9/vEeYHMkc8jt0zJChqQWw=
-github.com/otiai10/curr v0.0.0-20150429015615-9b4961190c95/go.mod h1:9qAhocn7zKJG+0mI8eUu6xqkFDYS2kb2saOteoSB3cE=
-github.com/otiai10/curr v1.0.0/go.mod h1:LskTG5wDwr8Rs+nNQ+1LlxRjAtTZZjtJW4rMXl6j4vs=
-github.com/otiai10/mint v1.3.0/go.mod h1:F5AjcsTsWUqX+Na9fpHb52P8pcRX2CI6A3ctIT91xUo=
-github.com/otiai10/mint v1.3.1/go.mod h1:/yxELlJQ0ufhjUwhshSj+wFjZ78CnZ48/1wtmBH1OTc=
-github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc=
-github.com/pascaldekloe/goe v0.1.0/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc=
-github.com/pborman/uuid v1.2.0/go.mod h1:X/NO0urCmaxf9VXbdlT7C2Yzkj2IKimNn4k+gtPdI/k=
-github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic=
 github.com/peterbourgon/diskv v2.0.1+incompatible/go.mod h1:uqqh8zWWbv1HBMNONnaR/tNboyR3/BZd58JJSHlUSCU=
-github.com/phayes/freeport v0.0.0-20180830031419-95f893ade6f2/go.mod h1:iIss55rKnNBTvrwdmkUpLnDpZoAHvWaiq5+iMmen4AE=
-github.com/pierrec/lz4 v2.0.5+incompatible/go.mod h1:pdkljMzZIN41W+lC3N2tnIh5sFi+IEE17M5jbnwPHcY=
-github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
-github.com/pkg/errors v0.8.1-0.20171018195549-f15c970de5b7/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
-github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
 github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
 github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
-github.com/pmezard/go-difflib v0.0.0-20151028094244-d8ed2627bdf0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
 github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
 github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
-github.com/posener/complete v1.1.1/go.mod h1:em0nMJCgc9GFtwrmVmEMR/ZL6WyhyjMBndrE9hABlRI=
-github.com/prometheus/alertmanager v0.18.0/go.mod h1:WcxHBl40VSPuOaqWae6l6HpnEOVRIycEJ7i9iYkadEE=
-github.com/prometheus/alertmanager v0.20.0/go.mod h1:9g2i48FAyZW6BtbsnvHtMHQXl2aVtrORKwKVCQ+nbrg=
-github.com/prometheus/client_golang v0.0.0-20180209125602-c332b6f63c06/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw=
-github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw=
-github.com/prometheus/client_golang v0.9.2/go.mod h1:OsXs2jCmiKlQ1lTBmv21f2mNfw4xf/QclQDMrYNZzcM=
-github.com/prometheus/client_golang v0.9.3-0.20190127221311-3c4408c8b829/go.mod h1:p2iRAGwDERtqlqzRXnrOVns+ignqQo//hLXqYxZYVNs=
-github.com/prometheus/client_golang v0.9.3/go.mod h1:/TN21ttK/J9q6uSwhBd54HahCDft0ttaMvbicHlPoso=
-github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo=
-github.com/prometheus/client_golang v1.1.0/go.mod h1:I1FGZT9+L76gKKOs5djB6ezCbFQP1xR9D75/vuwEF3g=
-github.com/prometheus/client_golang v1.2.0/go.mod h1:XMU6Z2MjaRKVu/dC1qupJI9SiNkDYzz3xecMgSW/F+U=
-github.com/prometheus/client_golang v1.2.1/go.mod h1:XMU6Z2MjaRKVu/dC1qupJI9SiNkDYzz3xecMgSW/F+U=
-github.com/prometheus/client_golang v1.5.1/go.mod h1:e9GMxYsXl05ICDXkRhurwBS4Q3OK1iX/F2sw+iXX5zU=
-github.com/prometheus/client_golang v1.7.1/go.mod h1:PY5Wy2awLA44sXw4AOSfFBetzPP4j5+D6mVACh+pe2M=
-github.com/prometheus/client_model v0.0.0-20171117100541-99fa1f4be8e5/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo=
-github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo=
-github.com/prometheus/client_model v0.0.0-20190115171406-56726106282f/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo=
-github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
 github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
-github.com/prometheus/client_model v0.2.0/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
-github.com/prometheus/common v0.0.0-20180110214958-89604d197083/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro=
-github.com/prometheus/common v0.0.0-20181113130724-41aa239b4cce/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro=
-github.com/prometheus/common v0.0.0-20181126121408-4724e9255275/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro=
-github.com/prometheus/common v0.2.0/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4=
-github.com/prometheus/common v0.4.0/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4=
-github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4=
-github.com/prometheus/common v0.6.0/go.mod h1:eBmuwkDJBwy6iBfxCBob6t6dR6ENT/y+J+Zk0j9GMYc=
-github.com/prometheus/common v0.7.0/go.mod h1:DjGbpBbp5NYNiECxcL/VnbXCCaQpKd3tt26CguLLsqA=
-github.com/prometheus/common v0.9.1/go.mod h1:yhUN8i9wzaXS3w1O07YhxHEBxD+W35wd8bs7vj7HSQ4=
-github.com/prometheus/common v0.10.0/go.mod h1:Tlit/dnDKsSWFlCLTWaA1cyBgKHSMdTB80sz/V91rCo=
-github.com/prometheus/procfs v0.0.0-20180125133057-cb4147076ac7/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk=
-github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk=
-github.com/prometheus/procfs v0.0.0-20181204211112-1dc9a6cbc91a/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk=
-github.com/prometheus/procfs v0.0.0-20190117184657-bf6a532e95b1/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk=
-github.com/prometheus/procfs v0.0.0-20190425082905-87a4384529e0/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA=
-github.com/prometheus/procfs v0.0.0-20190507164030-5867b95ac084/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA=
-github.com/prometheus/procfs v0.0.0-20190522114515-bc1a522cf7b1/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA=
-github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA=
-github.com/prometheus/procfs v0.0.3/go.mod h1:4A/X28fw3Fc593LaREMrKMqOKvUAntwMDaekg4FpcdQ=
-github.com/prometheus/procfs v0.0.5/go.mod h1:4A/X28fw3Fc593LaREMrKMqOKvUAntwMDaekg4FpcdQ=
-github.com/prometheus/procfs v0.0.6/go.mod h1:7Qr8sr6344vo1JqZ6HhLceV9o3AJ1Ff+GxbHq6oeK9A=
-github.com/prometheus/procfs v0.0.8/go.mod h1:7Qr8sr6344vo1JqZ6HhLceV9o3AJ1Ff+GxbHq6oeK9A=
-github.com/prometheus/procfs v0.0.11/go.mod h1:lV6e/gmhEcM9IjHGsFOCxxuZ+z1YqCvr4OA4YeYWdaU=
-github.com/prometheus/procfs v0.1.3/go.mod h1:lV6e/gmhEcM9IjHGsFOCxxuZ+z1YqCvr4OA4YeYWdaU=
-github.com/prometheus/prometheus v0.0.0-20180315085919-58e2a31db8de/go.mod h1:oAIUtOny2rjMX0OWN5vPR5/q/twIROJvdqnQKDdil/s=
-github.com/prometheus/prometheus v1.8.2-0.20200110114423-1e64d757f711/go.mod h1:7U90zPoLkWjEIQcy/rweQla82OCTUzxVHE51G3OhJbI=
-github.com/prometheus/prometheus v2.3.2+incompatible/go.mod h1:oAIUtOny2rjMX0OWN5vPR5/q/twIROJvdqnQKDdil/s=
-github.com/prometheus/tsdb v0.7.1/go.mod h1:qhTCs0VvXwvX/y3TZrWD7rabWM+ijKTux40TwIPHuXU=
-github.com/rcrowley/go-metrics v0.0.0-20181016184325-3113b8401b8a/go.mod h1:bCqnVzQkZxMG4s8nGwiZ5l3QUCyqpo9Y+/ZMZ9VjZe4=
-github.com/robfig/cron v0.0.0-20170526150127-736158dc09e1/go.mod h1:JGuDeoQd7Z6yL4zQhZ3OPEVHB7fL6Ka6skscFHfmt2k=
-github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6SoW27p1b0cqNHllgS5HIMJraePCO15w5zCzIWYg=
-github.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ=
-github.com/rogpeppe/go-internal v1.1.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
 github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
-github.com/rogpeppe/go-internal v1.3.2/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTEfhy4qGm1nDQc=
-github.com/rogpeppe/go-internal v1.4.0/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTEfhy4qGm1nDQc=
-github.com/rogpeppe/go-internal v1.5.0/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTEfhy4qGm1nDQc=
-github.com/rs/cors v1.6.0/go.mod h1:gFx+x8UowdsKA9AchylcLynDq+nNFfI8FkUZdN/jGCU=
-github.com/rubenv/sql-migrate v0.0.0-20200212082348-64f95ea68aa3/go.mod h1:rtQlpHw+eR6UrqaS3kX1VYeaCxzCVdimDS7g5Ln4pPc=
-github.com/russross/blackfriday v1.5.2/go.mod h1:JO/DiYxRf+HjHt06OyowR9PTA263kcR/rfWxYHBV53g=
-github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
-github.com/ryanuber/columnize v0.0.0-20160712163229-9b3edd62028f/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts=
-github.com/ryanuber/columnize v2.1.0+incompatible/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts=
-github.com/samuel/go-zookeeper v0.0.0-20190810000440-0ceca61e4d75/go.mod h1:gi+0XIa01GRL2eRQVjQkKGqKF3SF9vZR/HnPullcV2E=
-github.com/samuel/go-zookeeper v0.0.0-20190923202752-2cc03de413da/go.mod h1:gi+0XIa01GRL2eRQVjQkKGqKF3SF9vZR/HnPullcV2E=
-github.com/santhosh-tekuri/jsonschema v1.2.4/go.mod h1:TEAUOeZSmIxTTuHatJzrvARHiuO9LYd+cIxzgEHCQI4=
-github.com/satori/go.uuid v0.0.0-20160603004225-b111a074d5ef/go.mod h1:dA0hQrYB0VpLJoorglMZABFdXlWrHn1NEOzdhQKdks0=
-github.com/satori/go.uuid v1.2.0/go.mod h1:dA0hQrYB0VpLJoorglMZABFdXlWrHn1NEOzdhQKdks0=
-github.com/sclevine/spec v1.2.0/go.mod h1:W4J29eT/Kzv7/b9IWLB055Z+qvVC9vt0Arko24q7p+U=
-github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529/go.mod h1:DxrIzT+xaE7yg65j358z/aeFdxmN0P9QXhEzd20vsDc=
-github.com/sergi/go-diff v1.0.0/go.mod h1:0CfEIISq7TuYL3j771MWULgwwjU+GofnZX9QAmXWZgo=
-github.com/shopspring/decimal v0.0.0-20180709203117-cd690d0c9e24/go.mod h1:M+9NzErvs504Cn4c5DxATwIqPbtswREoFCre64PpcG4=
-github.com/shurcooL/httpfs v0.0.0-20171119174359-809beceb2371/go.mod h1:ZY1cvUeJuFPAdZ/B6v7RHavJWZn2YPVFQ1OSXhCGOkg=
-github.com/shurcooL/httpfs v0.0.0-20190707220628-8d4bc4ba7749/go.mod h1:ZY1cvUeJuFPAdZ/B6v7RHavJWZn2YPVFQ1OSXhCGOkg=
-github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc=
-github.com/shurcooL/vfsgen v0.0.0-20180825020608-02ddb050ef6b/go.mod h1:TrYk7fJVaAttu97ZZKrO9UbRa8izdowaMIZcxYMbVaw=
-github.com/shurcooL/vfsgen v0.0.0-20181202132449-6a9ea43bcacd/go.mod h1:TrYk7fJVaAttu97ZZKrO9UbRa8izdowaMIZcxYMbVaw=
-github.com/sirupsen/logrus v1.0.4-0.20170822132746-89742aefa4b2/go.mod h1:pMByvHTf9Beacp5x1UXfOR9xyW/9antXMhjMPG0dEzc=
-github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo=
-github.com/sirupsen/logrus v1.4.1/go.mod h1:ni0Sbl8bgC9z8RoU9G6nDWqqs/fq4eDPysMBDgk/93Q=
-github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE=
-github.com/sirupsen/logrus v1.5.0/go.mod h1:+F7Ogzej0PZc/94MaYx/nvG9jOFMD2osvC3s+Squfpo=
-github.com/sirupsen/logrus v1.6.0/go.mod h1:7uNnSEd1DgxDLC74fIahvMZmmYsHGZGEOFrfsX/uA88=
-github.com/sirupsen/logrus v1.7.0 h1:ShrD1U9pZB12TX0cVy0DtePoCH97K8EtX+mg7ZARUtM=
-github.com/sirupsen/logrus v1.7.0/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0=
-github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc=
-github.com/smartystreets/assertions v1.0.1/go.mod h1:kHHU4qYBaI3q23Pp3VPrmWhuIUrLW/7eUrw0BU5VaoM=
-github.com/smartystreets/goconvey v0.0.0-20190330032615-68dc04aab96a/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA=
-github.com/smartystreets/goconvey v1.6.4/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA=
-github.com/soheilhy/cmux v0.1.4/go.mod h1:IM3LyeVVIOuxMH7sFAkER9+bJ4dT7Ms6E4xg4kGIyLM=
-github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA=
-github.com/spaolacci/murmur3 v1.1.0/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA=
-github.com/spf13/afero v1.1.2/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B0CQ=
+github.com/sirupsen/logrus v1.8.1 h1:dJKuHgqk1NNQlqoA6BTlM1Wf9DOH3NBjQyu0h9+AZZE=
+github.com/sirupsen/logrus v1.8.1/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0=
 github.com/spf13/afero v1.2.2/go.mod h1:9ZxEEn6pIJ8Rxe320qSDBk6AsU0r9pR7Q4OcevTdifk=
-github.com/spf13/cast v1.3.0/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE=
-github.com/spf13/cast v1.3.1/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE=
-github.com/spf13/cobra v0.0.2-0.20171109065643-2da4a54c5cee/go.mod h1:1l0Ry5zgKvJasoi3XT1TypsSe7PqH0Sj9dhYf7v3XqQ=
-github.com/spf13/cobra v0.0.3/go.mod h1:1l0Ry5zgKvJasoi3XT1TypsSe7PqH0Sj9dhYf7v3XqQ=
-github.com/spf13/cobra v0.0.5/go.mod h1:3K3wKZymM7VvHMDS9+Akkh4K60UwM26emMESw8tLCHU=
-github.com/spf13/cobra v0.0.6/go.mod h1:/6GTrnGXV9HjY+aR4k0oJ5tcvakLuG6EuKReYlHNrgE=
-github.com/spf13/cobra v0.0.7/go.mod h1:/6GTrnGXV9HjY+aR4k0oJ5tcvakLuG6EuKReYlHNrgE=
-github.com/spf13/cobra v1.0.0/go.mod h1:/6GTrnGXV9HjY+aR4k0oJ5tcvakLuG6EuKReYlHNrgE=
-github.com/spf13/cobra v1.1.1/go.mod h1:WnodtKOvamDL/PwE2M4iKs8aMDBZ5Q5klgD3qfVJQMI=
-github.com/spf13/jwalterweatherman v1.0.0/go.mod h1:cQK4TGJAtQXfYWX+Ddv3mKDzgVb68N+wFjFa4jdeBTo=
 github.com/spf13/pflag v0.0.0-20170130214245-9ff6c6923cff/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4=
-github.com/spf13/pflag v1.0.1-0.20171106142849-4c012f6dcd95/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4=
-github.com/spf13/pflag v1.0.1/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4=
-github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4=
+github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA=
 github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
-github.com/spf13/viper v1.3.2/go.mod h1:ZiWeW+zYFKm7srdB9IoDzzZXaJaI5eL9QjNiN/DMA2s=
-github.com/spf13/viper v1.4.0/go.mod h1:PTJ7Z/lr49W6bUbkmS1V3by4uWynFiR9p7+dSq/yZzE=
-github.com/spf13/viper v1.7.0/go.mod h1:8WkrPz2fc9jxqZNCJI/76HCieCp4Q8HaLFoCha5qpdg=
+github.com/stoewer/go-strcase v1.2.0/go.mod h1:IBiWB2sKIp3wVVQ3Y035++gc+knqhUQag1KpM8ahLw8=
 github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
-github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
-github.com/stretchr/objx v0.2.0/go.mod h1:qt09Ya8vawLte6SNmTgCsAVtYtaKzEcn8ATUoHMkEqE=
-github.com/stretchr/testify v0.0.0-20151208002404-e3a8ff8ce365/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
 github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
 github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
 github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
-github.com/stretchr/testify v1.5.1 h1:nOGnQDM7FYENwehXlg/kFVnos3rEvtKTjRvOWSzb6H4=
 github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA=
-github.com/subosito/gotenv v1.2.0/go.mod h1:N0PQaV/YGNqwC0u51sEeR/aUtSLEXKX9iv69rRypqCw=
-github.com/syndtr/gocapability v0.0.0-20170704070218-db04d3cc01c8/go.mod h1:hkRG7XYTFWNJGYcbNJQlaLq0fg1yr4J4t/NcTQtrfww=
-github.com/thanos-io/thanos v0.11.0/go.mod h1:N/Yes7J68KqvmY+xM6J5CJqEvWIvKSR5sqGtmuD6wDc=
-github.com/tidwall/pretty v0.0.0-20180105212114-65a9db5fad51/go.mod h1:XNkn88O1ChpSDQmQeStsy+sBenx6DDtFZJxhVysOjyk=
-github.com/tidwall/pretty v1.0.0 h1:HsD+QiTn7sK6flMKIvNmpqz1qrpP3Ps6jOKIKMooyg4=
+github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
+github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY=
+github.com/tidwall/gjson v1.14.0 h1:6aeJ0bzojgWLa82gDQHcx3S0Lr/O51I9bJ5nv6JFx5w=
+github.com/tidwall/gjson v1.14.0/go.mod h1:/wbyibRr2FHMks5tjHJ5F8dMZh3AcwJEMf5vlfC0lxk=
+github.com/tidwall/match v1.1.1 h1:+Ho715JplO36QYgwN9PGYNhgZvoUSc9X2c80KVTi+GA=
+github.com/tidwall/match v1.1.1/go.mod h1:eRSPERbgtNPcGhD8UCthc6PmLEQXEWd3PRB5JTxsfmM=
 github.com/tidwall/pretty v1.0.0/go.mod h1:XNkn88O1ChpSDQmQeStsy+sBenx6DDtFZJxhVysOjyk=
-github.com/tmc/grpc-websocket-proxy v0.0.0-20170815181823-89b8d40f7ca8/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U=
-github.com/tmc/grpc-websocket-proxy v0.0.0-20190109142713-0ad062ec5ee5/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U=
-github.com/tv42/httpunix v0.0.0-20150427012821-b75d8614f926/go.mod h1:9ESjWnEqriFuLhtthL60Sar/7RFoluCcXsuvEwTV5KM=
-github.com/uber/jaeger-client-go v2.20.1+incompatible/go.mod h1:WVhlPFC8FDjOFMMWRy2pZqQJSXxYSwNYOkTr/Z6d3Kk=
-github.com/uber/jaeger-lib v2.2.0+incompatible/go.mod h1:ComeNDZlWwrWnDv8aPp0Ba6+uUTzImX/AauajbLI56U=
-github.com/ugorji/go v1.1.4/go.mod h1:uQMGLiO92mf5W77hV/PUCpI3pbzQx3CRekS0kk+RGrc=
-github.com/ugorji/go/codec v0.0.0-20181204163529-d75b2dcb6bc8/go.mod h1:VFNgLljTbGfSG7qAOspJ7OScBnGdDN/yBr0sguwnwf0=
-github.com/urfave/cli v0.0.0-20171014202726-7bc6a0acffa5/go.mod h1:70zkFmudgCuE/ngEzBv17Jvp/497gISqfk5gWijbERA=
-github.com/urfave/cli v1.20.0/go.mod h1:70zkFmudgCuE/ngEzBv17Jvp/497gISqfk5gWijbERA=
-github.com/vektah/gqlparser v1.1.2/go.mod h1:1ycwN7Ij5njmMkPPAOaRFY4rET2Enx7IkVv3vaXspKw=
-github.com/xanzy/go-gitlab v0.15.0/go.mod h1:8zdQa/ri1dfn8eS3Ir1SyfvOKlw7WBJ8DVThkpGiXrs=
-github.com/xdg/scram v0.0.0-20180814205039-7eeb5667e42c h1:u40Z8hqBAAQyv+vATcGgV0YCnDjqSL7/q/JyPhhJSPk=
-github.com/xdg/scram v0.0.0-20180814205039-7eeb5667e42c/go.mod h1:lB8K/P019DLNhemzwFU4jHLhdvlE6uDZjXFejJXr49I=
-github.com/xdg/stringprep v1.0.0 h1:d9X0esnoa3dFsV0FG35rAT0RIhYFlPq7MiP+DW89La0=
-github.com/xdg/stringprep v1.0.0/go.mod h1:Jhud4/sHMO4oL310DaZAKk9ZaJ08SJfe+sJh0HrGL1Y=
+github.com/tidwall/pretty v1.2.0 h1:RWIZEg2iJ8/g6fDDYzMpobmaoGh5OLl4AXtGUGPcqCs=
+github.com/tidwall/pretty v1.2.0/go.mod h1:ITEVvHYasfjBbM0u2Pg8T2nJnzm8xPwvNhhsoaGGjNU=
+github.com/xdg-go/pbkdf2 v1.0.0 h1:Su7DPu48wXMwC3bs7MCNG+z4FhcyEuz5dlvchbq0B0c=
+github.com/xdg-go/pbkdf2 v1.0.0/go.mod h1:jrpuAogTd400dnrH08LKmI/xc1MbPOebTwRqcT5RDeI=
+github.com/xdg-go/scram v1.0.2 h1:akYIkZ28e6A96dkWNJQu3nmCzH3YfwMPQExUYDaRv7w=
+github.com/xdg-go/scram v1.0.2/go.mod h1:1WAq6h33pAW+iRreB34OORO2Nf7qel3VV3fjBj+hCSs=
+github.com/xdg-go/stringprep v1.0.2 h1:6iq84/ryjjeRmMJwxutI51F2GIPlP5BfTvXHeYjyhBc=
+github.com/xdg-go/stringprep v1.0.2/go.mod h1:8F9zXuvzgwmyT5DUm4GUfZGDdT3W+LCvS6+da4O5kxM=
+github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f h1:J9EGpcZtP0E/raorCMxlFGSTBrsSlaDGf3jU/qvAE2c=
 github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f/go.mod h1:N2zxlSyiKSe5eX1tZViRH5QA0qijqEDrYZiPEAiq3wU=
+github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415 h1:EzJWgHovont7NscjpAxXsDA8S8BMYve8Y5+7cuRE7R0=
 github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415/go.mod h1:GwrjFmJcFw6At/Gs6z4yjiIwzuJ1/+UwLxMQDVQXShQ=
-github.com/xeipuuv/gojsonschema v0.0.0-20180618132009-1d523034197f/go.mod h1:5yf86TLmAcydyeJq5YvxkGPE2fm/u4myDekKRoLuqhs=
-github.com/xeipuuv/gojsonschema v1.1.0/go.mod h1:5yf86TLmAcydyeJq5YvxkGPE2fm/u4myDekKRoLuqhs=
-github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU=
-github.com/xlab/handysort v0.0.0-20150421192137-fb3537ed64a1/go.mod h1:QcJo0QPSfTONNIgpN5RA8prR7fF8nkF6cTWTcNerRO8=
-github.com/xlab/treeprint v0.0.0-20180616005107-d6fb6747feb6/go.mod h1:ce1O1j6UtZfjr22oyGxGLbauSBp2YVXpARAosm7dHBg=
-github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77/go.mod h1:aYKd//L2LvnjZzWKhF00oedf4jCCReLcmhLdhm1A27Q=
+github.com/xeipuuv/gojsonschema v1.2.0 h1:LhYJRs+L4fBtjZUfuSZIKGeVu0QRy8e5Xi7D17UxZ74=
+github.com/xeipuuv/gojsonschema v1.2.0/go.mod h1:anYRn/JVcOK2ZgGU+IjEV4nwlhoK5sQluxsYJ78Id3Y=
+github.com/youmark/pkcs8 v0.0.0-20181117223130-1be2e3e5546d h1:splanxYIlg+5LfHAM6xpdFEAYOk8iySO56hMFq6uLyA=
+github.com/youmark/pkcs8 v0.0.0-20181117223130-1be2e3e5546d/go.mod h1:rHwXgn7JulP+udvsHwJoVG1YGAP6VLg4y9I5dyZdqmA=
+github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
 github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
-github.com/yvasiyarov/go-metrics v0.0.0-20140926110328-57bccd1ccd43/go.mod h1:aX5oPXxHm3bOH+xeAttToC8pqch2ScQN/JoXYupl6xs=
-github.com/yvasiyarov/gorelic v0.0.0-20141212073537-a9bba5b9ab50/go.mod h1:NUSPSUX/bi6SeDMUh6brw0nXpxHnc96TguQh0+r/ssA=
-github.com/yvasiyarov/newrelic_platform_go v0.0.0-20140908184405-b21fdbd4370f/go.mod h1:GlGEuHIJweS1mbCqG+7vt2nvWLzLLnRHbXz5JKd/Qbg=
-github.com/ziutek/mymysql v1.5.4/go.mod h1:LMSpPZ6DbqWFxNCHW77HeMg9I646SAhApZ/wKdgO/C0=
-gitlab.com/nyarla/go-crypt v0.0.0-20160106005555-d9a5dc2b789b/go.mod h1:T3BPAOm2cqquPa0MKWeNkmOM5RQsRhkrwMWonFMN7fE=
-go.elastic.co/apm v1.5.0/go.mod h1:OdB9sPtM6Vt7oz3VXt7+KR96i9li74qrxBGHTQygFvk=
-go.elastic.co/apm/module/apmhttp v1.5.0/go.mod h1:1FbmNuyD3ddauwzgVwFB0fqY6KbZt3JkV187tGCYYhY=
-go.elastic.co/apm/module/apmot v1.5.0/go.mod h1:d2KYwhJParTpyw2WnTNy8geNlHKKFX+4oK3YLlsesWE=
-go.elastic.co/fastjson v1.0.0/go.mod h1:PmeUOMMtLHQr9ZS9J9owrAVg0FkaZDRZJEFTTGHtchs=
-go.etcd.io/bbolt v1.3.2/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU=
-go.etcd.io/bbolt v1.3.3/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU=
-go.etcd.io/bbolt v1.3.4/go.mod h1:G5EMThwa9y8QZGBClrRx5EY+Yw9kAhnjy3bSjsnlVTQ=
-go.etcd.io/etcd v0.5.0-alpha.5.0.20200819165624-17cef6e3e9d5/go.mod h1:skWido08r9w6Lq/w70DO5XYIKMu4QFu1+4VsqLQuJy8=
-go.mongodb.org/mongo-driver v1.0.3/go.mod h1:u7ryQJ+DOzQmeO7zB6MHyr8jkEQvC8vH7qLUO4lqsUM=
-go.mongodb.org/mongo-driver v1.1.0/go.mod h1:u7ryQJ+DOzQmeO7zB6MHyr8jkEQvC8vH7qLUO4lqsUM=
-go.mongodb.org/mongo-driver v1.1.1/go.mod h1:u7ryQJ+DOzQmeO7zB6MHyr8jkEQvC8vH7qLUO4lqsUM=
-go.mongodb.org/mongo-driver v1.1.2 h1:jxcFYjlkl8xaERsgLo+RNquI0epW6zuy/ZRQs6jnrFA=
-go.mongodb.org/mongo-driver v1.1.2/go.mod h1:u7ryQJ+DOzQmeO7zB6MHyr8jkEQvC8vH7qLUO4lqsUM=
-go.opencensus.io v0.20.1/go.mod h1:6WKK9ahsWS3RSO+PY9ZHZUfv2irvY6gN279GOPZjmmk=
-go.opencensus.io v0.20.2/go.mod h1:6WKK9ahsWS3RSO+PY9ZHZUfv2irvY6gN279GOPZjmmk=
+github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
+github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
+go.mongodb.org/mongo-driver v1.8.4 h1:NruvZPPL0PBcRJKmbswoWSrmHeUvzdxA3GCPfD/NEOA=
+go.mongodb.org/mongo-driver v1.8.4/go.mod h1:0sQWfOeY63QTntERDJJ/0SuKK0T1uVSgKCuAROlKEPY=
 go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU=
 go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8=
 go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
-go.uber.org/atomic v1.3.2/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE=
-go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE=
-go.uber.org/atomic v1.5.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ=
-go.uber.org/atomic v1.6.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ=
-go.uber.org/automaxprocs v1.2.0/go.mod h1:YfO3fm683kQpzETxlTGZhGIVmXAhaw3gxeBADbpZtnU=
-go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0=
-go.uber.org/multierr v1.5.0/go.mod h1:FeouvMocqHpRaaGuG9EjoKcStLC43Zu/fmqdUMPcKYU=
-go.uber.org/tools v0.0.0-20190618225709-2cfd321de3ee/go.mod h1:vJERXedbb3MVM5f9Ejo0C68/HhF8uaILCdgjnY+goOA=
-go.uber.org/zap v1.8.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q=
-go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q=
-go.uber.org/zap v1.14.1/go.mod h1:Mb2vm2krFEG5DV0W9qcHBYFtp/Wku1cvYaqPsS/WYfc=
-golang.org/x/crypto v0.0.0-20171113213409-9f005a07e0d3/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
-golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
-golang.org/x/crypto v0.0.0-20181029021203-45a5f77698d3/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
-golang.org/x/crypto v0.0.0-20181203042331-505ab145d0a9/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
-golang.org/x/crypto v0.0.0-20190211182817-74369b46fc67/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
+go.opencensus.io v0.22.3/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
+go.opencensus.io v0.22.4/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
 golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
-golang.org/x/crypto v0.0.0-20190320223903-b7391e95e576/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
-golang.org/x/crypto v0.0.0-20190325154230-a5d413f7728c/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
-golang.org/x/crypto v0.0.0-20190426145343-a29dc8fdc734/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
 golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
-golang.org/x/crypto v0.0.0-20190513172903-22d7a77e9e5f/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
 golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
-golang.org/x/crypto v0.0.0-20190611184440-5c40567a22f8/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
-golang.org/x/crypto v0.0.0-20190617133340-57b3e21c3d56/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
-golang.org/x/crypto v0.0.0-20190621222207-cc06ce4a13d4/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
-golang.org/x/crypto v0.0.0-20190923035154-9ee001bba392/go.mod h1:/lpIB1dKB+9EgE3H3cr1v9wB50oz8l4C4h62xy7jSTY=
 golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
-golang.org/x/crypto v0.0.0-20191112222119-e1110fd1c708/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
 golang.org/x/crypto v0.0.0-20191206172530-e9b2fee46413/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
-golang.org/x/crypto v0.0.0-20200128174031-69ecbb4d6d5d/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
-golang.org/x/crypto v0.0.0-20200414173820-0848c9571904/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
 golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
-golang.org/x/crypto v0.0.0-20201221181555-eec23a3978ad h1:DN0cp81fZ3njFcrLCytUHRSUkqBjfTo4Tx9RJTWs0EY=
-golang.org/x/crypto v0.0.0-20201221181555-eec23a3978ad/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I=
+golang.org/x/crypto v0.0.0-20201216223049-8b5274cf687f/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I=
+golang.org/x/crypto v0.0.0-20211215153901-e495a2d5b3d3 h1:0es+/5331RGQPcXlMfP+WrnIIS6dNnNRe0WB02W0F4M=
+golang.org/x/crypto v0.0.0-20211215153901-e495a2d5b3d3/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
 golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
 golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
 golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8=
 golang.org/x/exp v0.0.0-20190829153037-c13cbed26979/go.mod h1:86+5VVa7VpoJ4kLfm080zCjGlMRFzhUhsZKEZO7MGek=
 golang.org/x/exp v0.0.0-20191030013958-a1ab85dbe136/go.mod h1:JXzH8nQsPlswgeRAPE3MuO9GYsAcnJvJ4vnMwN/5qkY=
+golang.org/x/exp v0.0.0-20191129062945-2f5052295587/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4=
 golang.org/x/exp v0.0.0-20191227195350-da58074b4299/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4=
+golang.org/x/exp v0.0.0-20200119233911-0405dc783f0a/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4=
+golang.org/x/exp v0.0.0-20200207192155-f17229e696bd/go.mod h1:J/WKrq2StrnmMY6+EHIKF9dgMWnmCNThgcyBT1FY9mM=
+golang.org/x/exp v0.0.0-20200224162631-6cc2880d07d6/go.mod h1:3jZMyOhIsHpP37uCMkUooju7aAi5cS1Q23tOzKc+0MU=
 golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js=
 golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0=
 golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
@@ -861,189 +274,162 @@ golang.org/x/lint v0.0.0-20190409202823-959b441ac422/go.mod h1:6SW0HCj/g11FgYtHl
 golang.org/x/lint v0.0.0-20190909230951-414d861bb4ac/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
 golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
 golang.org/x/lint v0.0.0-20191125180803-fdd1cda4f05f/go.mod h1:5qLYkcX4OjUUV8bRuDixDT3tpyyb+LUpUlRWLxfhWrs=
+golang.org/x/lint v0.0.0-20200130185559-910be7a94367/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY=
+golang.org/x/lint v0.0.0-20200302205851-738671d3881b/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY=
 golang.org/x/mobile v0.0.0-20190312151609-d3739f865fa6/go.mod h1:z+o9i4GpDbdi3rU15maQ/Ox0txvL9dWGYEHz965HBQE=
 golang.org/x/mobile v0.0.0-20190719004257-d2bd2a29d028/go.mod h1:E/iHnbuqvinMTCcRqshq8CkpyQDoeVncDDYHnLhea+o=
 golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc=
 golang.org/x/mod v0.1.0/go.mod h1:0QHyrYULN0/3qlju5TqG8bIK38QM8yzMo5ekMj3DlcY=
 golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg=
+golang.org/x/mod v0.1.1-0.20191107180719-034126e5016b/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg=
 golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
 golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
-golang.org/x/net v0.0.0-20170114055629-f2499483f923/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
 golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
 golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
 golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
-golang.org/x/net v0.0.0-20181005035420-146acd28ed58/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
-golang.org/x/net v0.0.0-20181023162649-9b4f9f5ad519/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
-golang.org/x/net v0.0.0-20181108082009-03003ca0c849/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
-golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
-golang.org/x/net v0.0.0-20181201002055-351d144fa1fc/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
-golang.org/x/net v0.0.0-20181220203305-927f97764cc3/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
 golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
-golang.org/x/net v0.0.0-20190125091013-d26f9f9a57f3/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
 golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
 golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
-golang.org/x/net v0.0.0-20190320064053-1272bf9dcd53/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
 golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
-golang.org/x/net v0.0.0-20190424112056-4829fb13d2c6/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
 golang.org/x/net v0.0.0-20190501004415-9ce7a6920f09/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
 golang.org/x/net v0.0.0-20190503192946-f4e77d36d62c/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
-golang.org/x/net v0.0.0-20190522155817-f3200d17e092/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks=
 golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks=
-golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
-golang.org/x/net v0.0.0-20190619014844-b5b0513f8c1b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
 golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
 golang.org/x/net v0.0.0-20190628185345-da137c7871d7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
 golang.org/x/net v0.0.0-20190724013045-ca1201d0de80/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
-golang.org/x/net v0.0.0-20190813141303-74dc4d7220e7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
-golang.org/x/net v0.0.0-20190827160401-ba9fcec4b297/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
-golang.org/x/net v0.0.0-20190923162816-aa69164e4478/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
-golang.org/x/net v0.0.0-20191002035440-2ec189313ef0/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
-golang.org/x/net v0.0.0-20191004110552-13f9640d40b9/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
-golang.org/x/net v0.0.0-20191028085509-fe3aa8a45271/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
-golang.org/x/net v0.0.0-20191112182307-2180aed22343/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
 golang.org/x/net v0.0.0-20191209160850-c0dbc17a3553/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
+golang.org/x/net v0.0.0-20200114155413-6afb5195e5aa/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
+golang.org/x/net v0.0.0-20200202094626-16171245cfb2/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
+golang.org/x/net v0.0.0-20200222125558-5a598a2470a0/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
 golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
 golang.org/x/net v0.0.0-20200301022130-244492dfa37a/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
 golang.org/x/net v0.0.0-20200324143707-d3edc9973b7e/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
-golang.org/x/net v0.0.0-20200707034311-ab3426394381 h1:VXak5I6aEWmAXeQjA+QSZzlgNrpq9mjcfDemuexIKsU=
+golang.org/x/net v0.0.0-20200501053045-e0ff5e5a1de5/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
+golang.org/x/net v0.0.0-20200506145744-7e3656a0809f/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
+golang.org/x/net v0.0.0-20200513185701-a91f0712d120/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
+golang.org/x/net v0.0.0-20200520182314-0ba52f642ac2/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
+golang.org/x/net v0.0.0-20200625001655-4c5254603344/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
 golang.org/x/net v0.0.0-20200707034311-ab3426394381/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
+golang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
+golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
+golang.org/x/net v0.0.0-20220127200216-cd36cc0744dd h1:O7DYs+zxREGLKzKoMQrtrEacpb0ZVXA5rIwylE2Xchk=
+golang.org/x/net v0.0.0-20220127200216-cd36cc0744dd/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk=
 golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
-golang.org/x/oauth2 v0.0.0-20181106182150-f42d05182288/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
 golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
-golang.org/x/oauth2 v0.0.0-20190402181905-9f3314589c9a/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
 golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
 golang.org/x/oauth2 v0.0.0-20191202225959-858c2ad4c8b6/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
+golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
+golang.org/x/oauth2 v0.0.0-20210819190943-2bc19b11175f h1:Qmd2pbz05z7z6lm0DrgQVVPuBm92jqujBKMHMOlOQEw=
+golang.org/x/oauth2 v0.0.0-20210819190943-2bc19b11175f/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
 golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
 golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
 golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
 golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
 golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
 golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
-golang.org/x/sync v0.0.0-20201207232520-09787c993a3a h1:DcqTD9SDLc+1P/r1EmRBwnVsrOwW+kk2vWf9n+1sGhs=
-golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
-golang.org/x/sys v0.0.0-20170830134202-bb24a47a89ea/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
-golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
+golang.org/x/sync v0.0.0-20200317015054-43a5402ce75a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
+golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
+golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
+golang.org/x/sync v0.0.0-20210220032951-036812b2e83c h1:5KslGYwFpkhGh+Q16bwMP3cOontH8FOep7tGV86Y7SQ=
+golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
 golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
-golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
 golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
-golang.org/x/sys v0.0.0-20181026203630-95b1ffbd15a5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
-golang.org/x/sys v0.0.0-20181107165924-66b7b1311ac8/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
-golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
-golang.org/x/sys v0.0.0-20181122145206-62eef0e2fa9b/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
-golang.org/x/sys v0.0.0-20181205085412-a5c9d58dba9a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
-golang.org/x/sys v0.0.0-20190102155601-82a175fd1598/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
-golang.org/x/sys v0.0.0-20190209173611-3b5209105503/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
 golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
-golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
-golang.org/x/sys v0.0.0-20190310054646-10058d7d4faa/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/sys v0.0.0-20190321052220-f7bb7a8bee54/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/sys v0.0.0-20190425145619-16072639606e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/sys v0.0.0-20190426135247-a129542de9ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 golang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/sys v0.0.0-20190514135907-3a4b5fb9f71f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/sys v0.0.0-20190515120540-06a5c4944438/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/sys v0.0.0-20190602015325-4c4f7f33c9ed/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/sys v0.0.0-20190616124812-15dcb6c0061f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/sys v0.0.0-20190626221950-04f50cda93cb/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/sys v0.0.0-20190712062909-fae7ac547cb7/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 golang.org/x/sys v0.0.0-20190726091711-fc99dfbffb4e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/sys v0.0.0-20190801041406-cbf593c0f2f3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/sys v0.0.0-20190813064441-fde4db37ae7a/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/sys v0.0.0-20190826190057-c7b8b68b1456/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/sys v0.0.0-20190916202348-b4ddaad3f8a3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/sys v0.0.0-20190922100055-0a153f010e69/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/sys v0.0.0-20190924154521-2837fb4f24fe/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20191001151750-bb3f8db39f24/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/sys v0.0.0-20191010194322-b09406accb47/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/sys v0.0.0-20191025021431-6c3a3bfe00ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/sys v0.0.0-20191112214154-59a1497f0cea/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/sys v0.0.0-20191113165036-4c7a9d0fe056/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/sys v0.0.0-20191120155948-bd437916bb0e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 golang.org/x/sys v0.0.0-20191228213918-04cbcbbfeed8/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/sys v0.0.0-20200106162015-b016eb3dc98e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/sys v0.0.0-20200120151820-655fe14d7479/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20200113162924-86b910548bc1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 golang.org/x/sys v0.0.0-20200122134326-e047566fdf82/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 golang.org/x/sys v0.0.0-20200202164722-d101bd2416d5/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20200212091648-12a6c2dcc1e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 golang.org/x/sys v0.0.0-20200302150141-5c8b2ff67527/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/sys v0.0.0-20200615200032-f1bc736245b1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20200331124033-c3d80250170d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20200501052902-10377860bb8e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20200511232937-7e40ca221e25/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20200515095857-1151b9dac4a9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20200523222454-059865788121/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 golang.org/x/sys v0.0.0-20200622214017-ed371f2e16b4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c h1:VwygUrnw9jn88c4u8GD3rZQbqrP/tgas88tPUbBxQrk=
-golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20200803210538-64077c9b5642/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e h1:fLOSk5Q00efkSvAm+4xcoXD+RRmLmmulPn5I3Y9F2EM=
+golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
 golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw=
-golang.org/x/text v0.0.0-20160726164857-2910a502d2bf/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
+golang.org/x/term v0.0.0-20210927222741-03fcf44c2211 h1:JGgROgKl9N8DuW20oFS5gxc+lE67/N3FcwmBPMe7ArY=
+golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
+golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
 golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
-golang.org/x/text v0.3.1-0.20180805044716-cb6730876b98/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
 golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
 golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
-golang.org/x/text v0.3.3 h1:cokOdA+Jmi5PJGXLlLllQSgYigAEfHXJAERHVMaCc2k=
 golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
-golang.org/x/time v0.0.0-20180412165947-fbb02b2291d2/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
+golang.org/x/text v0.3.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
+golang.org/x/text v0.3.7 h1:olpwvP2KacW1ZWvsR7uQhoyTYvKAupfQrRGBFM352Gk=
+golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
 golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
 golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
 golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
-golang.org/x/tools v0.0.0-20180221164845-07fd8470d635/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
-golang.org/x/tools v0.0.0-20180828015842-6cd1fcedba52/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
+golang.org/x/time v0.0.0-20210723032227-1f47c861a9ac h1:7zkz7BUtwNFFqcowJ+RIgu2MaV/MapERkDIy+mwPyjs=
+golang.org/x/time v0.0.0-20210723032227-1f47c861a9ac/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
 golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
 golang.org/x/tools v0.0.0-20181011042414-1f849cf54d09/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
 golang.org/x/tools v0.0.0-20181030221726-6c7e314b6563/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
 golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
-golang.org/x/tools v0.0.0-20190118193359-16909d206f00/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
-golang.org/x/tools v0.0.0-20190125232054-d66bd3c5d5a6/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
 golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY=
 golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
 golang.org/x/tools v0.0.0-20190312151545-0bb0c0a6e846/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
 golang.org/x/tools v0.0.0-20190312170243-e65039ee4138/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
-golang.org/x/tools v0.0.0-20190328211700-ab21143f2384/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
 golang.org/x/tools v0.0.0-20190425150028-36563e24a262/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
-golang.org/x/tools v0.0.0-20190425222832-ad9eeb80039a/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
 golang.org/x/tools v0.0.0-20190506145303-2d16b83fe98c/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
 golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
+golang.org/x/tools v0.0.0-20190531172133-b3315ee88b7d/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
 golang.org/x/tools v0.0.0-20190606124116-d0a3d012864b/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
-golang.org/x/tools v0.0.0-20190614205625-5aca471b1d59/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
-golang.org/x/tools v0.0.0-20190617190820-da514acc4774/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
 golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
-golang.org/x/tools v0.0.0-20190624222133-a101b041ded4/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
 golang.org/x/tools v0.0.0-20190628153133-6cdbf07be9d0/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
-golang.org/x/tools v0.0.0-20190706070813-72ffa07ba3db/go.mod h1:jcCCGcm9btYwXyDqrUWc6MKQKKGJCWEQ3AfLSRIbEuI=
-golang.org/x/tools v0.0.0-20190813034749-528a2984e271/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
 golang.org/x/tools v0.0.0-20190816200558-6889da9d5479/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
-golang.org/x/tools v0.0.0-20190907020128-2ca718005c18/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
 golang.org/x/tools v0.0.0-20190911174233-4f2ddba30aff/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
-golang.org/x/tools v0.0.0-20190918214516-5a1a30219888/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
-golang.org/x/tools v0.0.0-20190920225731-5eefd052ad72/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
-golang.org/x/tools v0.0.0-20191004055002-72853e10c5a3/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
 golang.org/x/tools v0.0.0-20191012152004-8de300cfc20a/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
-golang.org/x/tools v0.0.0-20191029041327-9cc4af7d6b2c/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
-golang.org/x/tools v0.0.0-20191029190741-b9c20aec41a5/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
-golang.org/x/tools v0.0.0-20191030203535-5e247c9ad0a0/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
-golang.org/x/tools v0.0.0-20191111182352-50fa39b762bc/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
-golang.org/x/tools v0.0.0-20191112195655-aa38f8e97acc/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
 golang.org/x/tools v0.0.0-20191113191852-77e3bb0ad9e7/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
 golang.org/x/tools v0.0.0-20191115202509-3a792d9c32b2/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
 golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
 golang.org/x/tools v0.0.0-20191125144606-a911d9008d1f/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
+golang.org/x/tools v0.0.0-20191130070609-6e064ea0cf2d/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
+golang.org/x/tools v0.0.0-20191216173652-a0e659d51361/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
 golang.org/x/tools v0.0.0-20191227053925-7b8e75db28f4/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
-golang.org/x/tools v0.0.0-20200403190813-44a64ad78b9b/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
-golang.org/x/tools v0.0.0-20200616133436-c1934b75d054/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
+golang.org/x/tools v0.0.0-20200117161641-43d50277825c/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
+golang.org/x/tools v0.0.0-20200122220014-bf1340f18c4a/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
+golang.org/x/tools v0.0.0-20200130002326-2f3ba24bd6e7/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
+golang.org/x/tools v0.0.0-20200204074204-1cc6d1ef6c74/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
+golang.org/x/tools v0.0.0-20200207183749-b753a1ba74fa/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
+golang.org/x/tools v0.0.0-20200212150539-ea181f53ac56/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
+golang.org/x/tools v0.0.0-20200224181240-023911ca70b2/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
+golang.org/x/tools v0.0.0-20200227222343-706bc42d1f0d/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
+golang.org/x/tools v0.0.0-20200304193943-95d2e580d8eb/go.mod h1:o4KQGtdN14AW+yjsvvwRTJJuXz8XRtIHtEnmAXLyFUw=
+golang.org/x/tools v0.0.0-20200312045724-11d5b4c81c7d/go.mod h1:o4KQGtdN14AW+yjsvvwRTJJuXz8XRtIHtEnmAXLyFUw=
+golang.org/x/tools v0.0.0-20200331025713-a30bf2db82d4/go.mod h1:Sl4aGygMT6LrqrWclx+PTx3U+LnKx/seiNR+3G19Ar8=
+golang.org/x/tools v0.0.0-20200501065659-ab2804fb9c9d/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
+golang.org/x/tools v0.0.0-20200512131952-2bc93b1c0c88/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
+golang.org/x/tools v0.0.0-20200515010526-7d3b6ebf133d/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
+golang.org/x/tools v0.0.0-20200618134242-20370b0cb4b2/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
+golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
+golang.org/x/tools v0.0.0-20200729194436-6467de6f59a7/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA=
+golang.org/x/tools v0.0.0-20200804011535-6c149bb5ef0d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA=
+golang.org/x/tools v0.0.0-20200825202427-b303f430e36d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA=
+golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
 golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
 golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
 golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
-gomodules.xyz/jsonpatch/v2 v2.0.1/go.mod h1:IhYNNY4jnS53ZnfE4PAmpKtDpTCj1JFXc+3mwe7XcUU=
-gomodules.xyz/jsonpatch/v3 v3.0.1/go.mod h1:CBhndykehEwTOlEfnsfJwvkFQbSN8YZFr9M+cIHAJto=
-gomodules.xyz/orderedmap v0.1.0/go.mod h1:g9/TPUCm1t2gwD3j3zfV8uylyYhVdCNSi+xCEIu7yTU=
-google.golang.org/api v0.0.0-20160322025152-9bf6e6e569ff/go.mod h1:4mhQ8q/RsB7i+udVvVy5NUi08OU8ZlA0gRVgrF7VFY0=
-google.golang.org/api v0.3.1/go.mod h1:6wY9I6uQWHQ8EM57III9mq/AjF+i8G65rmVagqKMtkk=
-google.golang.org/api v0.3.2/go.mod h1:6wY9I6uQWHQ8EM57III9mq/AjF+i8G65rmVagqKMtkk=
+golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE=
+golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
 google.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE=
 google.golang.org/api v0.7.0/go.mod h1:WtwebWUNSVBH/HAw79HIFXZNqEvBhG+Ra+ax0hx3E3M=
 google.golang.org/api v0.8.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg=
@@ -1051,45 +437,65 @@ google.golang.org/api v0.9.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEn
 google.golang.org/api v0.13.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI=
 google.golang.org/api v0.14.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI=
 google.golang.org/api v0.15.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI=
+google.golang.org/api v0.17.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE=
+google.golang.org/api v0.18.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE=
+google.golang.org/api v0.19.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE=
+google.golang.org/api v0.20.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE=
+google.golang.org/api v0.22.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE=
+google.golang.org/api v0.24.0/go.mod h1:lIXQywCXRcnZPGlsd8NbLnOjtAoL6em04bJ9+z0MncE=
+google.golang.org/api v0.28.0/go.mod h1:lIXQywCXRcnZPGlsd8NbLnOjtAoL6em04bJ9+z0MncE=
+google.golang.org/api v0.29.0/go.mod h1:Lcubydp8VUV7KeIHD9z2Bys/sm/vGKnG1UHuDBSrHWM=
+google.golang.org/api v0.30.0/go.mod h1:QGmEvQ87FHZNiUVJkT14jQNYJ4ZJjdRF23ZXz5138Fc=
 google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM=
-google.golang.org/appengine v1.3.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
 google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
 google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
 google.golang.org/appengine v1.6.1/go.mod h1:i06prIuMbXzDqacNJfV5OdTW448YApPu5ww/cMBSeb0=
 google.golang.org/appengine v1.6.5/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc=
-google.golang.org/cloud v0.0.0-20151119220103-975617b05ea8/go.mod h1:0H1ncTHf11KCFhTc/+EFRbzSCOZx+VUbRMk55Yv5MYk=
+google.golang.org/appengine v1.6.6/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc=
+google.golang.org/appengine v1.6.7 h1:FZR1q0exgwxzPzp/aF+VccGrSfxfPpkBqjIIEq3ru6c=
+google.golang.org/appengine v1.6.7/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc=
 google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
 google.golang.org/genproto v0.0.0-20190307195333-5fe7a883aa19/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
-google.golang.org/genproto v0.0.0-20190404172233-64821d5d2107/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
 google.golang.org/genproto v0.0.0-20190418145605-e7d98fc518a7/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
 google.golang.org/genproto v0.0.0-20190425155659-357c62f0e4bb/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
 google.golang.org/genproto v0.0.0-20190502173448-54afdca5d873/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
-google.golang.org/genproto v0.0.0-20190530194941-fb225487d101/go.mod h1:z3L6/3dTEVtUr6QSP8miRzeRqwQOioJ9I66odjN4I7s=
-google.golang.org/genproto v0.0.0-20190716160619-c506a9f90610/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc=
 google.golang.org/genproto v0.0.0-20190801165951-fa694d86fc64/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc=
 google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc=
 google.golang.org/genproto v0.0.0-20190911173649-1774047e7e51/go.mod h1:IbNlFCBrqXvoKpeg0TB2l7cyZUmoaFKYIwrEpbDKLA8=
-google.golang.org/genproto v0.0.0-20190927181202-20e1ac93f88c/go.mod h1:IbNlFCBrqXvoKpeg0TB2l7cyZUmoaFKYIwrEpbDKLA8=
 google.golang.org/genproto v0.0.0-20191108220845-16a3f7862a1a/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
 google.golang.org/genproto v0.0.0-20191115194625-c23dd37a84c9/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
+google.golang.org/genproto v0.0.0-20191216164720-4f79533eabd1/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
 google.golang.org/genproto v0.0.0-20191230161307-f3c370f40bfb/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
-google.golang.org/genproto v0.0.0-20200117163144-32f20d992d24/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
+google.golang.org/genproto v0.0.0-20200115191322-ca5a22157cba/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
+google.golang.org/genproto v0.0.0-20200122232147-0452cf42e150/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
+google.golang.org/genproto v0.0.0-20200204135345-fa8e72b47b90/go.mod h1:GmwEX6Z4W5gMy59cAlVYjN9JhxgbQH6Gn+gFDQe2lzA=
+google.golang.org/genproto v0.0.0-20200212174721-66ed5ce911ce/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
+google.golang.org/genproto v0.0.0-20200224152610-e50cd9704f63/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
+google.golang.org/genproto v0.0.0-20200228133532-8c2c7df3a383/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
+google.golang.org/genproto v0.0.0-20200305110556-506484158171/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
+google.golang.org/genproto v0.0.0-20200312145019-da6875a35672/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
+google.golang.org/genproto v0.0.0-20200331122359-1ee6d9798940/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
+google.golang.org/genproto v0.0.0-20200430143042-b979b6f78d84/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
+google.golang.org/genproto v0.0.0-20200511104702-f5ebc3bea380/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
+google.golang.org/genproto v0.0.0-20200515170657-fc4c6c6a6587/go.mod h1:YsZOwe1myG/8QRHRsmBRE1LrgQY60beZKjly0O1fX9U=
 google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo=
-google.golang.org/grpc v0.0.0-20160317175043-d3ddb4469d5a/go.mod h1:yo6s7OP7yaDglbqo1J04qKzAhqBH6lvTonzMVmEdcZw=
-google.golang.org/grpc v1.17.0/go.mod h1:6QZJwpn2B+Zp71q/5VxRsJ6NXXVCE5NRUHRo+f3cWCs=
+google.golang.org/genproto v0.0.0-20200618031413-b414f8b61790/go.mod h1:jDfRM7FcilCzHH/e9qn6dsT145K34l5v+OpcnNgKAAA=
+google.golang.org/genproto v0.0.0-20200729003335-053ba62fc06f/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
+google.golang.org/genproto v0.0.0-20200804131852-c06518451d9c/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
+google.golang.org/genproto v0.0.0-20200825200019-8632dd797987/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
+google.golang.org/genproto v0.0.0-20201019141844-1ed22bb0c154/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
 google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
 google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38=
-google.golang.org/grpc v1.21.0/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM=
 google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM=
-google.golang.org/grpc v1.22.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg=
-google.golang.org/grpc v1.22.1/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg=
 google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg=
-google.golang.org/grpc v1.23.1/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg=
-google.golang.org/grpc v1.24.0/go.mod h1:XDChyiUovWa60DnaeDeZmSW86xtLtjtZbwvSiRnRtcA=
 google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY=
 google.golang.org/grpc v1.26.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk=
 google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk=
+google.golang.org/grpc v1.27.1/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk=
 google.golang.org/grpc v1.28.0/go.mod h1:rpkK4SK4GF4Ach/+MFLZUBavHOvF2JJB5uozKKal+60=
+google.golang.org/grpc v1.29.1/go.mod h1:itym6AZVZYACWQqET3MqgPpjcuV5QH3BxFS3IjizoKk=
+google.golang.org/grpc v1.30.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak=
+google.golang.org/grpc v1.31.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak=
 google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8=
 google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0=
 google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM=
@@ -1099,96 +505,61 @@ google.golang.org/protobuf v1.22.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2
 google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
 google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
 google.golang.org/protobuf v1.24.0/go.mod h1:r/3tXBNzIEhYS9I1OUVjXDlt8tc493IdKGjtUeSXeh4=
-gopkg.in/airbrake/gobrake.v2 v2.0.9/go.mod h1:/h5ZAUhDkGaJfjzjKLSjv6zCL6O0LLBxU4K+aSYdM/U=
-gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw=
+google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c=
+google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw=
+google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
+google.golang.org/protobuf v1.27.1 h1:SnqbnDw1V7RiZcXPx5MEeqPv2s79L9i7BJUlG/+RurQ=
+google.golang.org/protobuf v1.27.1/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
 gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
-gopkg.in/check.v1 v1.0.0-20141024133853-64131543e789/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
 gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
+gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15 h1:YR8cESwS4TdDjEe65xsg0ogRM/Nc3DYOhEAlW+xobZo=
 gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
-gopkg.in/cheggaaa/pb.v1 v1.0.25/go.mod h1:V/YB90LKu/1FcN3WVnfiiE5oMCibMjukxqG/qStrOgw=
 gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI=
+gopkg.in/fsnotify.v1 v1.4.7 h1:xOHLXZwVvI9hhs+cLKq5+I5onOuwQLhQwiu63xxlHs4=
 gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys=
-gopkg.in/fsnotify/fsnotify.v1 v1.4.7/go.mod h1:Fyux9zXlo4rWoMSIzpn9fDAYjalPqJ/K1qJ27s+7ltE=
-gopkg.in/gemnasium/logrus-airbrake-hook.v2 v2.1.2/go.mod h1:Xk6kEKp8OKb+X14hQBKWaSkCsqBpgog8nAV2xsGOxlo=
-gopkg.in/gorp.v1 v1.7.2/go.mod h1:Wo3h+DBQZIxATwftsglhdD/62zRFPhGhTiu5jUJmCaw=
-gopkg.in/imdario/mergo.v0 v0.3.7/go.mod h1:9qPP6AGrlC1G2PTNXko614FwGZvorN7MiBU0Eppok+U=
+gopkg.in/inf.v0 v0.9.1 h1:73M5CoZyi3ZLMOyDlQh031Cx6N9NDJ2Vvfl76EDAgDc=
 gopkg.in/inf.v0 v0.9.1/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw=
-gopkg.in/ini.v1 v1.42.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
-gopkg.in/ini.v1 v1.51.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
-gopkg.in/op/go-logging.v1 v1.0.0-20160211212156-b2cb9fa56473/go.mod h1:N1eN2tsCx0Ydtgjl4cqmbRCsY4/+z4cYDeqwZTk6zog=
-gopkg.in/resty.v1 v1.12.0/go.mod h1:mDo4pnntr5jdWRML875a/NmxYqAlA73dVijT2AXvQQo=
+gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ=
 gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw=
-gopkg.in/yaml.v2 v2.0.0-20170812160011-eb3733d160e7/go.mod h1:JAlM8MvJe8wmxCU4Bli9HhUf9+ttbYbLASfIpnQbh74=
-gopkg.in/yaml.v2 v2.1.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
 gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
 gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
-gopkg.in/yaml.v2 v2.2.3/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
-gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
-gopkg.in/yaml.v2 v2.2.5/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
 gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
-gopkg.in/yaml.v2 v2.3.0 h1:clyUAQHOM3G0M3f5vQj7LuJrETvjVot3Z5el9nffUtU=
 gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
-gopkg.in/yaml.v3 v3.0.0-20190905181640-827449938966/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
-gotest.tools v2.2.0+incompatible/go.mod h1:DsYFclhRJ6vuDpmuTbkuFWG+y2sxOXAzmJt81HFBacw=
-gotest.tools/v3 v3.0.2/go.mod h1:3SzNCllyD9/Y+b5r9JIKQ474KzkZyqLqEfYqMsX94Bk=
-helm.sh/helm/v3 v3.2.4/go.mod h1:ZaXz/vzktgwjyGGFbUWtIQkscfE7WYoRGP2szqAFHR0=
-honnef.co/go/tools v0.0.0-20180728063816-88497007e858/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
+gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY=
+gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
+gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
+gopkg.in/yaml.v3 v3.0.0-20200615113413-eeeca48fe776/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
+gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b h1:h8qDotaEPuJATrMmW04NCwg7v22aHH28wwpauUhK9Oo=
+gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
 honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
 honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
 honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
 honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
 honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg=
-howett.net/plist v0.0.0-20181124034731-591f970eefbb/go.mod h1:vMygbs4qMhSZSc4lCUl2OEE+rDiIIJAIdR4m7MiMcm0=
+honnef.co/go/tools v0.0.1-2020.1.3/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k=
+honnef.co/go/tools v0.0.1-2020.1.4/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k=
+k8s.io/api v0.19.0 h1:XyrFIJqTYZJ2DU7FBE/bSPz7b1HvbVBuBf07oeo6eTc=
 k8s.io/api v0.19.0/go.mod h1:I1K45XlvTrDjmj5LoM5LuP/KYrhWbjUKT/SoPG0qTjw=
-k8s.io/apiextensions-apiserver v0.19.0/go.mod h1:znfQxNpjqz/ZehvbfMg5N6fvBJW5Lqu5HVLTJQdP4Fs=
+k8s.io/apimachinery v0.19.0 h1:gjKnAda/HZp5k4xQYjL0K/Yb66IvNqjthCb03QlKpaQ=
 k8s.io/apimachinery v0.19.0/go.mod h1:DnPGDnARWFvYa3pMHgSxtbZb7gpzzAZ1pTfaUNDVlmA=
-k8s.io/apiserver v0.0.0-20190409021813-1ec86e4da56c/go.mod h1:6bqaTSOSJavUIXUtfaR9Os9JtTCm8ZqH2SUl2S60C4w=
-k8s.io/autoscaler v0.0.0-20190607113959-1b4f1855cb8e/go.mod h1:QEXezc9uKPT91dwqhSJq3GNI3B1HxFRQHiku9kmrsSA=
-k8s.io/cli-runtime v0.19.0/go.mod h1:tun9l0eUklT8IHIM0jors17KmUjcrAxn0myoBYwuNuo=
+k8s.io/client-go v0.19.0 h1:1+0E0zfWFIWeyRhQYWzimJOyAk2UT7TiARaLNwJCf7k=
 k8s.io/client-go v0.19.0/go.mod h1:H9E/VT95blcFQnlyShFgnFT9ZnJOAceiUHM3MlRC+mU=
-k8s.io/code-generator v0.18.2/go.mod h1:+UHX5rSbxmR8kzS+FAv7um6dtYrZokQvjHpDSYRVkTc=
-k8s.io/code-generator v0.19.0/go.mod h1:moqLn7w0t9cMs4+5CQyxnfA/HV8MF6aAVENF+WZZhgk=
-k8s.io/component-base v0.0.0-20191122220729-2684fb322cb9/go.mod h1:NFuUusy/X4Tk21m21tcNUihnmp4OI7lXU7/xA+rYXkc=
-k8s.io/component-base v0.18.2/go.mod h1:kqLlMuhJNHQ9lz8Z7V5bxUUtjFZnrypArGl58gmDfUM=
-k8s.io/component-base v0.19.0/go.mod h1:dKsY8BxkA+9dZIAh2aWJLL/UdASFDNtGYTCItL4LM7Y=
-k8s.io/gengo v0.0.0-20190128074634-0689ccc1d7d6/go.mod h1:ezvh/TsK7cY6rbqRK0oQQ8IAqLxYwwyPxAX1Pzy0ii0=
-k8s.io/gengo v0.0.0-20200114144118-36b2048a9120/go.mod h1:ezvh/TsK7cY6rbqRK0oQQ8IAqLxYwwyPxAX1Pzy0ii0=
 k8s.io/gengo v0.0.0-20200413195148-3a45101e95ac/go.mod h1:ezvh/TsK7cY6rbqRK0oQQ8IAqLxYwwyPxAX1Pzy0ii0=
-k8s.io/gengo v0.0.0-20200428234225-8167cfdcfc14/go.mod h1:ezvh/TsK7cY6rbqRK0oQQ8IAqLxYwwyPxAX1Pzy0ii0=
-k8s.io/klog v0.0.0-20181102134211-b9b56d5dfc92/go.mod h1:Gq+BEi5rUBO/HRz0bTSXDUcqjScdoY3a9IHpCEIOOfk=
-k8s.io/klog v0.3.0/go.mod h1:Gq+BEi5rUBO/HRz0bTSXDUcqjScdoY3a9IHpCEIOOfk=
-k8s.io/klog v0.3.3/go.mod h1:Gq+BEi5rUBO/HRz0bTSXDUcqjScdoY3a9IHpCEIOOfk=
-k8s.io/klog v0.4.0/go.mod h1:4Bi6QPql/J/LkTDqv7R/cd3hPo4k2DG6Ptcz060Ez5I=
-k8s.io/klog v1.0.0/go.mod h1:4Bi6QPql/J/LkTDqv7R/cd3hPo4k2DG6Ptcz060Ez5I=
 k8s.io/klog/v2 v2.0.0/go.mod h1:PBfzABfn139FHAV07az/IF9Wp1bkk3vpT2XSJ76fSDE=
 k8s.io/klog/v2 v2.2.0/go.mod h1:Od+F08eJP+W3HUb4pSrPpgp9DGU4GzlpG/TmITuYh/Y=
-k8s.io/klog/v2 v2.4.0/go.mod h1:Od+F08eJP+W3HUb4pSrPpgp9DGU4GzlpG/TmITuYh/Y=
-k8s.io/kube-openapi v0.0.0-20190320154901-5e45bb682580/go.mod h1:BXM9ceUBTj2QnfH2MK1odQs778ajze1RxcmP6S8RVVc=
-k8s.io/kube-openapi v0.0.0-20191107075043-30be4d16710a/go.mod h1:1TqjTSzOxsLGIKfj0lK8EeCP7K1iUG65v09OM0/WG5E=
-k8s.io/kube-openapi v0.0.0-20200121204235-bf4fb3bd569c/go.mod h1:GRQhZsXIAJ1xR0C9bd8UpWHZ5plfAS9fzPjJuQ6JL3E=
+k8s.io/klog/v2 v2.30.0 h1:bUO6drIvCIsvZ/XFgfxoGFQU/a4Qkh0iAlvUR7vlHJw=
+k8s.io/klog/v2 v2.30.0/go.mod h1:y1WjHnz7Dj687irZUWR/WLkLc5N1YHtjLdmgWjndZn0=
 k8s.io/kube-openapi v0.0.0-20200805222855-6aeccd4b50c6/go.mod h1:UuqjUnNftUyPE5H64/qeyjQoUZhGpeFDVdxjTeEVN2o=
-k8s.io/kube-openapi v0.0.0-20201113171705-d219536bb9fd/go.mod h1:WOJ3KddDSol4tAGcJo0Tvi+dK12EcqSLqcWsryKMpfM=
-k8s.io/kube-state-metrics v1.7.2/go.mod h1:U2Y6DRi07sS85rmVPmBFlmv+2peBcL8IWGjM+IjYA/E=
-k8s.io/kubectl v0.19.0/go.mod h1:gPCjjsmE6unJzgaUNXIFGZGafiUp5jh0If3F/x7/rRg=
-k8s.io/kubernetes v1.14.1/go.mod h1:ocZa8+6APFNC2tX1DZASIbocyYT5jHzqFVsY5aoB7Jk=
-k8s.io/metrics v0.19.0/go.mod h1:WykpW8B60OeAJx1imdwUgyOID2kDljr/Q+1zrPJ98Wo=
-k8s.io/utils v0.0.0-20190308190857-21c4ce38f2a7/go.mod h1:8k8uAuAQ0rXslZKaEWd0c3oVhZz7sSzSiPnVZayjIX0=
-k8s.io/utils v0.0.0-20190801114015-581e00157fb1/go.mod h1:sZAwmy6armz5eXlNoLmJcl4F1QuKu7sr+mFQ0byX7Ew=
-k8s.io/utils v0.0.0-20191114184206-e782cd3c129f/go.mod h1:sZAwmy6armz5eXlNoLmJcl4F1QuKu7sr+mFQ0byX7Ew=
-k8s.io/utils v0.0.0-20191114200735-6ca3b61696b6/go.mod h1:sZAwmy6armz5eXlNoLmJcl4F1QuKu7sr+mFQ0byX7Ew=
-k8s.io/utils v0.0.0-20200324210504-a9aa75ae1b89/go.mod h1:sZAwmy6armz5eXlNoLmJcl4F1QuKu7sr+mFQ0byX7Ew=
 k8s.io/utils v0.0.0-20200729134348-d5654de09c73/go.mod h1:jPW/WVKK9YHAvNhRxK0md/EJ228hCsBRufyofKtW8HA=
+k8s.io/utils v0.0.0-20211208161948-7d6a63dca704 h1:ZKMMxTvduyf5WUtREOqg5LiXaN1KO/+0oOQPRFrClpo=
+k8s.io/utils v0.0.0-20211208161948-7d6a63dca704/go.mod h1:jPW/WVKK9YHAvNhRxK0md/EJ228hCsBRufyofKtW8HA=
 rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8=
-rsc.io/letsencrypt v0.0.3/go.mod h1:buyQKZ6IXrRnB7TdkHP0RyEybLx18HHyOSoTyoOLqNY=
-sigs.k8s.io/controller-runtime v0.6.0/go.mod h1:CpYf5pdNY/B352A1TFLAS2JVSlnGQ5O2cftPHndTroo=
-sigs.k8s.io/controller-tools v0.2.4/go.mod h1:m/ztfQNocGYBgTTCmFdnK94uVvgxeZeE3LtJvd/jIzA=
-sigs.k8s.io/controller-tools v0.3.0/go.mod h1:enhtKGfxZD1GFEoMgP8Fdbu+uKQ/cq1/WGJhdVChfvI=
-sigs.k8s.io/kubebuilder v1.0.9-0.20200618125005-36aa113dbe99/go.mod h1:FGPx0hvP73+bapzWoy5ePuhAJYgJjrFbPxgvWyortM0=
-sigs.k8s.io/kustomize v2.0.3+incompatible/go.mod h1:MkjgH3RdOWrievjo6c9T245dYlB5QeXV4WCbnt/PEpU=
-sigs.k8s.io/structured-merge-diff v0.0.0-20190525122527-15d366b2352e/go.mod h1:wWxsB5ozmmv/SG7nM11ayaAW51xMvak/t1r0CSlcokI=
-sigs.k8s.io/structured-merge-diff/v3 v3.0.0-20200116222232-67a7b8c61874/go.mod h1:PlARxl6Hbt/+BC80dRLi1qAmnMqwqDg62YvvVkZjemw=
+rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0=
+rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA=
 sigs.k8s.io/structured-merge-diff/v4 v4.0.1/go.mod h1:bJZC9H9iH24zzfZ/41RGcq60oK1F7G282QMXDPYydCw=
-sigs.k8s.io/structured-merge-diff/v4 v4.0.2/go.mod h1:bJZC9H9iH24zzfZ/41RGcq60oK1F7G282QMXDPYydCw=
+sigs.k8s.io/structured-merge-diff/v4 v4.2.1 h1:bKCqE9GvQ5tiVHn5rfn1r+yao3aLQEaLzkkmAkf+A6Y=
+sigs.k8s.io/structured-merge-diff/v4 v4.2.1/go.mod h1:j/nl6xW8vLS49O8YvXW1ocPhZawJtm+Yrr7PPRQ0Vg4=
 sigs.k8s.io/yaml v1.1.0/go.mod h1:UJmg0vDUVViEyp3mgSv9WPwZCDxu4rQW1olrI1uml+o=
 sigs.k8s.io/yaml v1.2.0/go.mod h1:yfXDCHCao9+ENCvLSE62v9VSji2MKu5jeNfTrofGhJc=
-vbom.ml/util v0.0.0-20160121211510-db5cfe13f5cc/go.mod h1:so/NYdZXCz+E3ZpW0uAoCj6uzU2+8OWDFv/HxUSs7kI=
+sigs.k8s.io/yaml v1.3.0 h1:a2VclLzOGrwOHDiV8EfBGhvjHvP46CtW5j6POvhYGGo=
+sigs.k8s.io/yaml v1.3.0/go.mod h1:GeOyir5tyXNByN85N/dRIT9es5UQNerPYEKK56eTBm8=
diff --git a/central-controller/src/reg_cluster/ref-schemas/v1.yaml b/central-controller/src/reg_cluster/ref-schemas/v1.yaml
new file mode 100644 (file)
index 0000000..a79697f
--- /dev/null
@@ -0,0 +1,129 @@
+name: emco-base
+resources:
+#emco-clm
+  - name: clusterProvider
+  - name: cluster
+    parent: clusterProvider
+  - name: clusterLabel
+    parent: cluster
+  - name: clusterKv
+    parent: cluster
+  - name: clusterSyncObject
+    parent: clusterProvider
+#emco-dcm
+  - name: logicalCloud
+    parent: project
+  - name: clusterReference
+    parent: logicalCloud
+    references:
+      - name: cluster
+  - name: clusterQuota
+    parent: logicalCloud
+  - name: logicalCloudKv
+    parent: logicalCloud
+  - name: userPermission
+    parent: logicalCloud
+#emco-dtc
+  - name: trafficGroupIntent
+    parent: deploymentIntentGroup
+  - name: inboundServerIntent
+    parent: trafficGroupIntent
+    references:
+      - name: app
+  - name: inboundClientsIntent
+    parent: inboundServerIntent
+    references:
+      - name: app
+#emco-gac
+  - name: genericK8sIntent
+    parent: deploymentIntentGroup
+  - name: genericResource
+    parent: genericK8sIntent
+    references:
+      - name: app
+  - name: customization
+    parent: genericResource
+    references:
+      - name: cluster
+#emco-hpa-plc
+  - name: hpaIntent
+    parent: deploymentIntentGroup
+    references:
+      - name: app
+  - name: hpaConsumer
+    parent: hpaIntent
+  - name: hpaResource
+    parent: hpaConsumer
+#emco-ncm
+  - name: providerNetwork
+    parent: cluster
+  - name: network
+    parent: cluster
+#emco-orchestrator
+  - name: controllerGroup.controller
+  - name: project
+  - name: compositeApp.compositeAppVersion
+    parent: project
+  - name: app
+    parent: compositeAppVersion
+  - name: compositeProfile
+    parent: compositeAppVersion
+  - name: appProfile
+    parent: compositeProfile
+    references:
+      - name: app
+  - name: deploymentIntentGroup
+    parent: compositeAppVersion
+    references:
+      - name: logicalCloud
+      - name: compositeProfile
+  - name: groupIntent
+    parent: deploymentIntentGroup
+    references:
+      - name: controller
+        type: map
+        map: intent
+        fixedKv:
+          controllerGroup: orchestrator
+        filterKeys:
+          - genericPlacementIntent
+  - name: genericPlacementIntent
+    parent: deploymentIntentGroup
+  - name: genericAppPlacementIntent
+    parent: genericPlacementIntent
+    references:
+      - name: app
+      - name: cluster
+        type: many
+  - name: appDependency
+    parent: app
+#emco-ovnaction
+  - name: netControllerIntent
+    parent: deploymentIntentGroup
+  - name: workloadIntent
+    parent: netControllerIntent
+    references:
+      - name: app
+  - name: interfaceIntent
+    parent: workloadIntent
+#emco-sfc
+  - name: sfcIntent
+    parent: deploymentIntentGroup
+  - name: sfcLink
+    parent: sfcIntent
+    references:
+      - name: app
+  - name: sfcClientSelector
+    parent: sfcIntent
+  - name: sfcProviderNetwork
+    parent: sfcIntent
+#emco-sfc-client
+  - name: sfcClientIntent
+    parent: deploymentIntentGroup
+    references:
+      - name: sfcIntent
+      - name: app
+        commonKey: compositeAppVersion
+#emco-workflowmgr
+  - name: workflowIntent
+    parent: deploymentIntentGroup
index 6db636b..0d86272 100644 (file)
@@ -1,21 +1,38 @@
 package main
 
 import (
+       "context"
        "encoding/base64"
-       "github.com/open-ness/EMCO/src/orchestrator/pkg/infra/db"
-       rsync "github.com/open-ness/EMCO/src/rsync/pkg/db"
+       "flag"
        pkgerrors "github.com/pkg/errors"
+       "gitlab.com/project-emco/core/emco-base/src/orchestrator/pkg/infra/db"
+       rsync "gitlab.com/project-emco/core/emco-base/src/rsync/pkg/db"
        "io/ioutil"
+       metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
+       "k8s.io/client-go/kubernetes"
+       "k8s.io/client-go/tools/clientcmd"
        "log"
        "math/rand"
+       "os"
        "time"
 )
 
+const (
+       defaultUsername  = "scc"
+       defaultNamespace = "sdewan-system"
+       defaultKey       = "userPassword"
+)
+
 func registerCluster(provider_name string, cluster_name string, kubeconfig_file string) error {
        content, err := ioutil.ReadFile(kubeconfig_file)
 
        ccc := rsync.NewCloudConfigClient()
 
+       config, _ := ccc.GetCloudConfig(provider_name, cluster_name, "0", "default")
+       if config.Config != "" {
+               ccc.DeleteCloudConfig(provider_name, cluster_name, "0", "default")
+       }
+
        _, err = ccc.CreateCloudConfig(provider_name, cluster_name, "0", "default", base64.StdEncoding.EncodeToString(content))
        if err != nil {
                return pkgerrors.Wrap(err, "Error creating cloud config")
@@ -27,8 +44,32 @@ func registerCluster(provider_name string, cluster_name string, kubeconfig_file
 func main() {
        rand.Seed(time.Now().UnixNano())
 
+       var mongo_secret, mongo_data_secret, kubeconfig_path *string
+       mongo_secret = flag.String("mongoSecret", "mongo-secret", "secret name for mongo access")
+       mongo_data_secret = flag.String("mongoDataSecret", "mongo-data-secret", "secret name for mongo encryption")
+       kubeconfig_path = flag.String("kubeconfigPath", "admin.conf", "path for kubeconfig")
+       flag.Parse()
+
+       cfg, err := clientcmd.BuildConfigFromFlags("", *kubeconfig_path)
+       if err != nil {
+               log.Println("Error in getting kubeconfig")
+               log.Println(err)
+               log.Fatalln("Exiting...")
+       }
+       clientset, _ := kubernetes.NewForConfig(cfg)
+       mongoSecret, errs := clientset.CoreV1().Secrets(defaultNamespace).Get(context.Background(), *mongo_secret, metav1.GetOptions{})
+       mongoDataSecret, errs := clientset.CoreV1().Secrets(defaultNamespace).Get(context.Background(), *mongo_data_secret, metav1.GetOptions{})
+       if errs != nil {
+               log.Println(errs)
+               log.Fatalln("Exiting...")
+       }
+
+       os.Setenv("DB_EMCO_USERNAME", defaultUsername)
+       os.Setenv("DB_EMCO_PASSWORD", string(mongoSecret.Data[defaultKey]))
+       os.Setenv("EMCO_DATA_KEY", string(mongoDataSecret.Data["key"]))
+
        // Initialize the mongodb
-       err := db.InitializeDatabaseConnection("scc")
+       err = db.InitializeDatabaseConnection("scc")
        if err != nil {
                log.Println("Unable to initialize database connection...")
                log.Println(err)
@@ -38,5 +79,5 @@ func main() {
        provider_name := "akraino_scc"
        cluster_name := "local"
        // Register cluster kubeconfig
-       registerCluster(provider_name, cluster_name, "admin.conf")
+       registerCluster(provider_name, cluster_name, *kubeconfig_path)
 }
index d92289c..8dad3ac 100644 (file)
@@ -4,7 +4,7 @@
 export GO111MODULE=on
 
 all: clean
-       CGO_ENABLED=1 GOOS=linux GOARCH=amd64 \
+       CGO_ENABLED=0 GOOS=linux GOARCH=amd64 \
        go build -tags rsync -o ./rsync ./cmd/main.go
 
 # The following is done this way as each patch on CI runs build and each merge runs deploy. So for build we don't need to build binary and hence
index 64f80da..d528b7c 100644 (file)
@@ -4,69 +4,30 @@
 package main
 
 import (
-       "fmt"
-       "log"
        "math/rand"
-       "net"
-       "strings"
+       "os"
+       "os/signal"
        "time"
 
-       register "github.com/open-ness/EMCO/src/rsync/pkg/grpc"
-       installpb "github.com/open-ness/EMCO/src/rsync/pkg/grpc/installapp"
-       "github.com/open-ness/EMCO/src/rsync/pkg/grpc/installappserver"
-       readynotifypb "github.com/open-ness/EMCO/src/rsync/pkg/grpc/readynotify"
-       "github.com/open-ness/EMCO/src/rsync/pkg/grpc/readynotifyserver"
+       register "gitlab.com/project-emco/core/emco-base/src/orchestrator/pkg/grpc"
+       log "gitlab.com/project-emco/core/emco-base/src/orchestrator/pkg/infra/logutils"
+       installpb "gitlab.com/project-emco/core/emco-base/src/rsync/pkg/grpc/installapp"
+       "gitlab.com/project-emco/core/emco-base/src/rsync/pkg/grpc/installappserver"
+       readynotifypb "gitlab.com/project-emco/core/emco-base/src/rsync/pkg/grpc/readynotify"
+       "gitlab.com/project-emco/core/emco-base/src/rsync/pkg/grpc/readynotifyserver"
+       updatepb "gitlab.com/project-emco/core/emco-base/src/rsync/pkg/grpc/updateapp"
+       "gitlab.com/project-emco/core/emco-base/src/rsync/pkg/grpc/updateappserver"
 
-       "github.com/open-ness/EMCO/src/orchestrator/pkg/infra/config"
-       contextDb "github.com/open-ness/EMCO/src/orchestrator/pkg/infra/contextdb"
-       "github.com/open-ness/EMCO/src/orchestrator/pkg/infra/db"
+       contextDb "gitlab.com/project-emco/core/emco-base/src/orchestrator/pkg/infra/contextdb"
+       "gitlab.com/project-emco/core/emco-base/src/orchestrator/pkg/infra/db"
+       "gitlab.com/project-emco/core/emco-base/src/rsync/pkg/context"
        "google.golang.org/grpc"
-       "google.golang.org/grpc/credentials"
-       "google.golang.org/grpc/testdata"
 )
 
-func startGrpcServer() error {
-       var tls bool
-
-       if strings.Contains(config.GetConfiguration().GrpcEnableTLS, "enable") {
-               tls = true
-       } else {
-               tls = false
-       }
-       certFile := config.GetConfiguration().GrpcServerCert
-       keyFile := config.GetConfiguration().GrpcServerKey
-
-       _, port := register.GetServerHostPort()
-
-       lis, err := net.Listen("tcp", fmt.Sprintf(":%d", port))
-       if err != nil {
-               log.Fatalf("Could not listen to port: %v", err)
-       }
-       var opts []grpc.ServerOption
-       if tls {
-               if certFile == "" {
-                       certFile = testdata.Path("server.pem")
-               }
-               if keyFile == "" {
-                       keyFile = testdata.Path("server.key")
-               }
-               creds, err := credentials.NewServerTLSFromFile(certFile, keyFile)
-               if err != nil {
-                       log.Fatalf("Could not generate credentials %v", err)
-               }
-               opts = []grpc.ServerOption{grpc.Creds(creds)}
-       }
-
-       grpcServer := grpc.NewServer(opts...)
+func RegisterRsyncServices(grpcServer *grpc.Server, srv interface{}) {
        installpb.RegisterInstallappServer(grpcServer, installappserver.NewInstallAppServer())
        readynotifypb.RegisterReadyNotifyServer(grpcServer, readynotifyserver.NewReadyNotifyServer())
-
-       log.Println("Starting rsync gRPC Server")
-       err = grpcServer.Serve(lis)
-       if err != nil {
-               log.Fatalf("rsync grpc server is not serving %v", err)
-       }
-       return err
+       updatepb.RegisterUpdateappServer(grpcServer, updateappserver.NewUpdateAppServer())
 }
 
 func main() {
@@ -76,21 +37,36 @@ func main() {
        // Initialize the mongodb
        err := db.InitializeDatabaseConnection("scc")
        if err != nil {
-               log.Println("Unable to initialize mongo database connection...")
-               log.Println(err)
-               log.Fatalln("Exiting...")
+               log.Error("Unable to initialize mongo database connection", log.Fields{"Error": err})
+               os.Exit(1)
        }
 
        // Initialize contextdb
        err = contextDb.InitializeContextDatabase()
        if err != nil {
-               log.Println("Unable to initialize etcd database connection...")
-               log.Println(err)
-               log.Fatalln("Exiting...")
+               log.Error("Unable to initialize etcd database connection", log.Fields{"Error": err})
+               os.Exit(1)
        }
 
-       err = startGrpcServer()
+       go func() {
+               err := register.StartGrpcServer("rsync", "RSYNC_NAME", 9031,
+                       RegisterRsyncServices, nil)
+               if err != nil {
+                       log.Error("GRPC server failed to start", log.Fields{"Error": err})
+                       os.Exit(1)
+               }
+       }()
+
+       err = context.RestoreActiveContext()
        if err != nil {
-               log.Fatalf("GRPC server failed to start")
+               log.Error("RestoreActiveContext failed", log.Fields{"Error": err})
        }
+
+       connectionsClose := make(chan struct{})
+
+       c := make(chan os.Signal, 1)
+       signal.Notify(c, os.Interrupt)
+       <-c
+       close(connectionsClose)
+
 }
diff --git a/central-controller/src/rsync/coverage.html b/central-controller/src/rsync/coverage.html
deleted file mode 100644 (file)
index 2ba9ccd..0000000
+++ /dev/null
@@ -1,213 +0,0 @@
-
-<!DOCTYPE html>
-<html>
-       <head>
-               <meta http-equiv="Content-Type" content="text/html; charset=utf-8">
-               <title>readynotifyserver: Go Coverage Report</title>
-               <style>
-                       body {
-                               background: black;
-                               color: rgb(80, 80, 80);
-                       }
-                       body, pre, #legend span {
-                               font-family: Menlo, monospace;
-                               font-weight: bold;
-                       }
-                       #topbar {
-                               background: black;
-                               position: fixed;
-                               top: 0; left: 0; right: 0;
-                               height: 42px;
-                               border-bottom: 1px solid rgb(80, 80, 80);
-                       }
-                       #content {
-                               margin-top: 50px;
-                       }
-                       #nav, #legend {
-                               float: left;
-                               margin-left: 10px;
-                       }
-                       #legend {
-                               margin-top: 12px;
-                       }
-                       #nav {
-                               margin-top: 10px;
-                       }
-                       #legend span {
-                               margin: 0 5px;
-                       }
-                       .cov0 { color: rgb(192, 0, 0) }
-.cov1 { color: rgb(128, 128, 128) }
-.cov2 { color: rgb(116, 140, 131) }
-.cov3 { color: rgb(104, 152, 134) }
-.cov4 { color: rgb(92, 164, 137) }
-.cov5 { color: rgb(80, 176, 140) }
-.cov6 { color: rgb(68, 188, 143) }
-.cov7 { color: rgb(56, 200, 146) }
-.cov8 { color: rgb(44, 212, 149) }
-.cov9 { color: rgb(32, 224, 152) }
-.cov10 { color: rgb(20, 236, 155) }
-
-               </style>
-       </head>
-       <body>
-               <div id="topbar">
-                       <div id="nav">
-                               <select id="files">
-                               
-                               <option value="file0">github.com/open-ness/EMCO/src/rsync/pkg/grpc/readynotifyserver/readynotifyserver.go (69.4%)</option>
-                               
-                               </select>
-                       </div>
-                       <div id="legend">
-                               <span>not tracked</span>
-                       
-                               <span class="cov0">no coverage</span>
-                               <span class="cov1">low coverage</span>
-                               <span class="cov2">*</span>
-                               <span class="cov3">*</span>
-                               <span class="cov4">*</span>
-                               <span class="cov5">*</span>
-                               <span class="cov6">*</span>
-                               <span class="cov7">*</span>
-                               <span class="cov8">*</span>
-                               <span class="cov9">*</span>
-                               <span class="cov10">high coverage</span>
-                       
-                       </div>
-               </div>
-               <div id="content">
-               
-               <pre class="file" id="file0" style="display: none">// SPDX-License-Identifier: Apache-2.0
-// Copyright (c) 2020-2021 Intel Corporation
-
-package readynotifyserver
-
-import (
-        "context"
-        "log"
-        "sync"
-
-        "github.com/open-ness/EMCO/src/orchestrator/pkg/infra/logutils"
-        pb "github.com/open-ness/EMCO/src/rsync/pkg/grpc/readynotify"
-)
-
-// readyNotifyServer will be initialized by NewReadyNotifyServer() and
-// its lifecycle is valid until all the clients unsubscribed the stream notification channel
-type readyNotifyServer struct {
-        name string
-        // alertNotify contains the map of "appContextID" and "map of client name and stream server"
-        // For Ex: map[12345687:map[[dtc:st1] [dcm:st2]] 456785369:map[[ncm:st3] [dtc:st4]]]
-        alertNotify   map[string]map[string]pb.ReadyNotify_AlertServer
-        streamChannel map[pb.ReadyNotify_AlertServer]chan int
-        mutex         sync.Mutex
-}
-
-var notifServer *readyNotifyServer
-
-// Alert gets notified when the subscriber subscribes for an appcontext event notification
-func (s *readyNotifyServer) Alert(topic *pb.Topic, stream pb.ReadyNotify_AlertServer) error <span class="cov4" title="2">{
-        client := topic.GetClientName()
-        appContextID := topic.GetAppContext()
-        log.Printf("[ReadyNotify gRPC] Received an Alert subscription request (%s, %s)", client, appContextID)
-
-        // Adding the appContextID entry to the map
-        s.mutex.Lock()
-        if len(s.alertNotify[appContextID]) == 0 </span><span class="cov1" title="1">{
-                s.alertNotify[appContextID] = make(map[string]pb.ReadyNotify_AlertServer)
-        }</span>
-        <span class="cov4" title="2">s.alertNotify[appContextID][client] = stream
-        s.streamChannel[stream] = make(chan int)
-        c := s.streamChannel[stream]
-        s.mutex.Unlock()
-
-        // Keep stream open
-        for </span><span class="cov4" title="2">{
-                select </span>{
-                case &lt;-c:<span class="cov4" title="2">
-                        log.Printf("[ReadyNotify gRPC] stop channel got triggered for the client = %s\n", client)
-                        return nil</span>
-                }
-        }
-}
-
-//SendAppContextNotification sends appcontext back to the subscriber if pending
-func SendAppContextNotification(appContextID string) error <span class="cov0" title="0">{
-        streams := notifServer.alertNotify[appContextID]
-        var err error = nil
-        for _, stream := range streams </span><span class="cov0" title="0">{
-                err := stream.Send(&amp;pb.Notification{AppContext: appContextID})
-                if err != nil </span><span class="cov0" title="0">{
-                        logutils.Error("[ReadyNotify gRPC] Notification back to client failed to be sent", logutils.Fields{"err": err})
-                        // return pkgerrors.New("Notification failed")
-                }</span> else<span class="cov0" title="0"> {
-                        logutils.Info("[ReadyNotify gRPC] Notified the subscriber about appContext status changes", logutils.Fields{"appContextID": appContextID})
-                }</span>
-        }
-        <span class="cov0" title="0">return err</span>
-}
-
-// Unsubscribe will be called when the subscriber wants to terminate the stream
-func (s *readyNotifyServer) Unsubscribe(ctx context.Context, topic *pb.Topic) (*pb.UnsubscribeResponse, error) <span class="cov7" title="3">{
-
-        s.mutex.Lock()
-        defer s.mutex.Unlock()
-        for appContextID, clientStreamMap := range s.alertNotify </span><span class="cov10" title="5">{
-                if appContextID == topic.GetAppContext() </span><span class="cov7" title="3">{
-                        stream := clientStreamMap[topic.ClientName]
-                        s.streamChannel[stream] &lt;- 1
-
-                        delete(clientStreamMap, topic.ClientName)
-                        delete(s.streamChannel, stream)
-                        // Delete the outer map's appcontextIDs if there is no inner map contents
-                        if len(clientStreamMap) == 0 </span><span class="cov4" title="2">{
-                                delete(s.alertNotify, appContextID)
-                        }</span>
-                }
-        }
-
-        <span class="cov7" title="3">return &amp;pb.UnsubscribeResponse{}, nil</span>
-}
-
-// NewReadyNotifyServer will create a new readyNotifyServer and destroys the previous one
-func NewReadyNotifyServer() *readyNotifyServer <span class="cov0" title="0">{
-        s := &amp;readyNotifyServer{
-                name:          "readyNotifyServer",
-                alertNotify:   make(map[string](map[string]pb.ReadyNotify_AlertServer)),
-                streamChannel: make(map[pb.ReadyNotify_AlertServer]chan int),
-        }
-        notifServer = s
-        return s
-}</span>
-</pre>
-               
-               </div>
-       </body>
-       <script>
-       (function() {
-               var files = document.getElementById('files');
-               var visible;
-               files.addEventListener('change', onChange, false);
-               function select(part) {
-                       if (visible)
-                               visible.style.display = 'none';
-                       visible = document.getElementById(part);
-                       if (!visible)
-                               return;
-                       files.value = part;
-                       visible.style.display = 'block';
-                       location.hash = part;
-               }
-               function onChange() {
-                       select(files.value);
-                       window.scrollTo(0, 0);
-               }
-               if (location.hash != "") {
-                       select(location.hash.substr(1));
-               }
-               if (!visible) {
-                       select("file0");
-               }
-       })();
-       </script>
-</html>
index 8482dec..91c38d1 100644 (file)
-module github.com/open-ness/EMCO/src/rsync
+module gitlab.com/project-emco/core/emco-base/src/rsync
 
 go 1.17
 
 require (
+       github.com/fluxcd/go-git-providers v0.5.4
+       github.com/fluxcd/kustomize-controller/api v0.21.1
+       github.com/fluxcd/source-controller/api v0.21.2
        github.com/ghodss/yaml v1.0.0
-       github.com/golang/mock v1.3.1
-       github.com/golang/protobuf v1.4.2
-       github.com/jonboulle/clockwork v0.1.0
-       github.com/open-ness/EMCO/src/monitor v0.0.0-00010101000000-000000000000
-       github.com/open-ness/EMCO/src/orchestrator v0.0.0-00010101000000-000000000000
+       github.com/golang/mock v1.6.0
+       github.com/golang/protobuf v1.5.2
+       github.com/jonboulle/clockwork v0.2.2
        github.com/pkg/errors v0.9.1
-       github.com/sirupsen/logrus v1.7.0
-       golang.org/x/net v0.0.0-20200707034311-ab3426394381
-       golang.org/x/sync v0.0.0-20201207232520-09787c993a3a
-       google.golang.org/grpc v1.28.0
-       google.golang.org/protobuf v1.24.0
-       k8s.io/api v0.20.2
-       k8s.io/apiextensions-apiserver v0.20.2
-       k8s.io/apimachinery v0.20.2
-       k8s.io/cli-runtime v0.20.2
-       k8s.io/client-go v12.0.0+incompatible
-       k8s.io/kube-openapi v0.0.0-20201113171705-d219536bb9fd
-       k8s.io/kubectl v0.20.2
+       gitlab.com/project-emco/core/emco-base/src/monitor v0.0.0-00010101000000-000000000000
+       gitlab.com/project-emco/core/emco-base/src/orchestrator v0.0.0-00010101000000-000000000000
+       golang.org/x/net v0.0.0-20220127200216-cd36cc0744dd
+       golang.org/x/sync v0.0.0-20210220032951-036812b2e83c
+       google.golang.org/grpc v1.43.0
+       google.golang.org/protobuf v1.27.1
+       k8s.io/api v0.23.3
+       k8s.io/apiextensions-apiserver v0.23.3
+       k8s.io/apimachinery v0.23.3
+       k8s.io/cli-runtime v0.23.3
+       k8s.io/client-go v0.23.3
+       k8s.io/kube-openapi v0.0.0-20220124234850-424119656bbf
+       k8s.io/kubectl v0.23.3
 )
 
 require (
+       github.com/Azure/go-ansiterm v0.0.0-20210617225240-d185dfc1b5a1 // indirect
+       github.com/MakeNowJust/heredoc v0.0.0-20170808103936-bb23615498cd // indirect
        github.com/PuerkitoBio/purell v1.1.1 // indirect
        github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578 // indirect
+       github.com/chai2010/gettext-go v0.0.0-20160711120539-c6fed771bfd5 // indirect
        github.com/coreos/go-semver v0.3.0 // indirect
        github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e // indirect
        github.com/coreos/pkg v0.0.0-20180928190104-399ea9e2e55f // indirect
        github.com/davecgh/go-spew v1.1.1 // indirect
-       github.com/emicklei/go-restful v2.9.5+incompatible // indirect
-       github.com/evanphx/json-patch v4.9.0+incompatible // indirect
+       github.com/evanphx/json-patch v4.12.0+incompatible // indirect
        github.com/exponent-io/jsonpath v0.0.0-20151013193312-d6023ce2651d // indirect
-       github.com/go-logr/logr v0.2.1 // indirect
-       github.com/go-openapi/jsonpointer v0.19.3 // indirect
-       github.com/go-openapi/jsonreference v0.19.3 // indirect
-       github.com/go-openapi/spec v0.19.4 // indirect
-       github.com/go-openapi/swag v0.19.5 // indirect
+       github.com/fluxcd/pkg/apis/acl v0.0.3 // indirect
+       github.com/fluxcd/pkg/apis/kustomize v0.3.1 // indirect
+       github.com/fluxcd/pkg/apis/meta v0.10.2 // indirect
+       github.com/fluxcd/pkg/runtime v0.12.5 // indirect
+       github.com/fvbommel/sortorder v1.0.1 // indirect
+       github.com/go-errors/errors v1.0.1 // indirect
+       github.com/go-logr/logr v1.2.2 // indirect
+       github.com/go-openapi/jsonpointer v0.19.5 // indirect
+       github.com/go-openapi/jsonreference v0.19.5 // indirect
+       github.com/go-openapi/swag v0.19.14 // indirect
        github.com/go-stack/stack v1.8.0 // indirect
-       github.com/gogo/protobuf v1.3.1 // indirect
+       github.com/gogo/protobuf v1.3.2 // indirect
        github.com/golang/snappy v0.0.1 // indirect
-       github.com/google/btree v1.0.0 // indirect
-       github.com/google/go-cmp v0.4.0 // indirect
-       github.com/google/gofuzz v1.1.0 // indirect
-       github.com/google/uuid v1.1.1 // indirect
-       github.com/googleapis/gnostic v0.4.1 // indirect
-       github.com/gregjones/httpcache v0.0.0-20180305231024-9cad4c3443a7 // indirect
-       github.com/grpc-ecosystem/go-grpc-middleware v1.1.0 // indirect
-       github.com/grpc-ecosystem/grpc-gateway v1.12.1 // indirect
-       github.com/hashicorp/golang-lru v0.5.4 // indirect
-       github.com/imdario/mergo v0.3.11 // indirect
+       github.com/google/btree v1.0.1 // indirect
+       github.com/google/go-cmp v0.5.6 // indirect
+       github.com/google/go-github/v41 v41.0.0 // indirect
+       github.com/google/go-querystring v1.1.0 // indirect
+       github.com/google/gofuzz v1.2.0 // indirect
+       github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510 // indirect
+       github.com/google/uuid v1.1.2 // indirect
+       github.com/googleapis/gnostic v0.5.5 // indirect
+       github.com/gregjones/httpcache v0.0.0-20190611155906-901d90724c79 // indirect
+       github.com/imdario/mergo v0.3.12 // indirect
        github.com/inconshreveable/mousetrap v1.0.0 // indirect
-       github.com/json-iterator/go v1.1.10 // indirect
+       github.com/josharian/intern v1.0.0 // indirect
+       github.com/json-iterator/go v1.1.12 // indirect
+       github.com/klauspost/compress v1.13.6 // indirect
+       github.com/kr/pretty v0.2.1 // indirect
        github.com/liggitt/tabwriter v0.0.0-20181228230101-89fcab3d43de // indirect
-       github.com/mailru/easyjson v0.7.0 // indirect
+       github.com/mailru/easyjson v0.7.6 // indirect
+       github.com/mitchellh/go-wordwrap v1.0.0 // indirect
+       github.com/moby/spdystream v0.2.0 // indirect
+       github.com/moby/term v0.0.0-20210610120745-9d4ed1856297 // indirect
        github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
-       github.com/modern-go/reflect2 v1.0.1 // indirect
-       github.com/onsi/ginkgo v1.12.0 // indirect
-       github.com/onsi/gomega v1.9.0 // indirect
+       github.com/modern-go/reflect2 v1.0.2 // indirect
+       github.com/monochromegane/go-gitignore v0.0.0-20200626010858-205db1a8cc00 // indirect
        github.com/peterbourgon/diskv v2.0.1+incompatible // indirect
-       github.com/spf13/cobra v1.1.1 // indirect
+       github.com/pmezard/go-difflib v1.0.0 // indirect
+       github.com/russross/blackfriday v1.5.2 // indirect
+       github.com/sirupsen/logrus v1.8.1 // indirect
+       github.com/spf13/cobra v1.2.1 // indirect
        github.com/spf13/pflag v1.0.5 // indirect
        github.com/stretchr/testify v1.7.0 // indirect
-       github.com/xdg/scram v0.0.0-20180814205039-7eeb5667e42c // indirect
-       github.com/xdg/stringprep v1.0.0 // indirect
-       go.etcd.io/etcd v0.5.0-alpha.5.0.20200819165624-17cef6e3e9d5 // indirect
-       go.mongodb.org/mongo-driver v1.1.2 // indirect
-       go.uber.org/atomic v1.6.0 // indirect
-       go.uber.org/multierr v1.5.0 // indirect
-       go.uber.org/zap v1.14.1 // indirect
-       golang.org/x/crypto v0.0.0-20201221181555-eec23a3978ad // indirect
-       golang.org/x/oauth2 v0.0.0-20191202225959-858c2ad4c8b6 // indirect
-       golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c // indirect
-       golang.org/x/term v0.0.0-20201117132131-f5c789dd3221 // indirect
-       golang.org/x/text v0.3.3 // indirect
-       golang.org/x/time v0.0.0-20191024005414-555d28b269f0 // indirect
-       google.golang.org/appengine v1.6.5 // indirect
-       google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013 // indirect
+       github.com/tidwall/gjson v1.14.0 // indirect
+       github.com/tidwall/match v1.1.1 // indirect
+       github.com/tidwall/pretty v1.2.0 // indirect
+       github.com/xdg-go/pbkdf2 v1.0.0 // indirect
+       github.com/xdg-go/scram v1.0.2 // indirect
+       github.com/xdg-go/stringprep v1.0.2 // indirect
+       github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f // indirect
+       github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415 // indirect
+       github.com/xeipuuv/gojsonschema v1.2.0 // indirect
+       github.com/xlab/treeprint v0.0.0-20181112141820-a009c3971eca // indirect
+       github.com/youmark/pkcs8 v0.0.0-20181117223130-1be2e3e5546d // indirect
+       go.etcd.io/etcd v0.0.0-00010101000000-000000000000 // indirect
+       go.mongodb.org/mongo-driver v1.8.4 // indirect
+       go.starlark.net v0.0.0-20200306205701-8dd3e2ee1dd5 // indirect
+       go.uber.org/atomic v1.7.0 // indirect
+       go.uber.org/multierr v1.6.0 // indirect
+       go.uber.org/zap v1.19.1 // indirect
+       golang.org/x/crypto v0.0.0-20211215153901-e495a2d5b3d3 // indirect
+       golang.org/x/oauth2 v0.0.0-20210819190943-2bc19b11175f // indirect
+       golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e // indirect
+       golang.org/x/term v0.0.0-20210927222741-03fcf44c2211 // indirect
+       golang.org/x/text v0.3.7 // indirect
+       golang.org/x/time v0.0.0-20210723032227-1f47c861a9ac // indirect
+       google.golang.org/appengine v1.6.7 // indirect
+       google.golang.org/genproto v0.0.0-20210831024726-fe130286e0e2 // indirect
        gopkg.in/inf.v0 v0.9.1 // indirect
-       gopkg.in/yaml.v2 v2.3.0 // indirect
-       k8s.io/klog/v2 v2.4.0 // indirect
-       k8s.io/utils v0.0.0-20200729134348-d5654de09c73 // indirect
-       sigs.k8s.io/controller-runtime v0.6.0 // indirect
-       sigs.k8s.io/kustomize v2.0.3+incompatible // indirect
-       sigs.k8s.io/structured-merge-diff/v4 v4.0.2 // indirect
-       sigs.k8s.io/yaml v1.2.0 // indirect
+       gopkg.in/yaml.v2 v2.4.0 // indirect
+       gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b // indirect
+       k8s.io/component-base v0.23.3 // indirect
+       k8s.io/klog/v2 v2.30.0 // indirect
+       k8s.io/utils v0.0.0-20211208161948-7d6a63dca704 // indirect
+       sigs.k8s.io/controller-runtime v0.11.1 // indirect
+       sigs.k8s.io/json v0.0.0-20211208200746-9f7c6b3444d2 // indirect
+       sigs.k8s.io/kustomize/api v0.10.1 // indirect
+       sigs.k8s.io/kustomize/kyaml v0.13.0 // indirect
+       sigs.k8s.io/structured-merge-diff/v4 v4.2.1 // indirect
+       sigs.k8s.io/yaml v1.3.0 // indirect
 )
 
 replace (
-       github.com/Sirupsen/logrus => github.com/sirupsen/logrus v1.7.0
        github.com/docker/distribution => github.com/docker/distribution v0.0.0-20191216044856-a8371794149d
        github.com/docker/docker => github.com/moby/moby v17.12.0-ce-rc1.0.20200618181300-9dc6525e6118+incompatible
-       github.com/open-ness/EMCO/src/monitor => ../monitor
-       github.com/open-ness/EMCO/src/orchestrator => ../vendor/github.com/open-ness/EMCO/src/orchestrator
-       github.com/open-ness/EMCO/src/rsync => ../rsync
+       gitlab.com/project-emco/core/emco-base/src/monitor => ../monitor
+       gitlab.com/project-emco/core/emco-base/src/orchestrator => ../vendor/gitlab.com/project-emco/core/emco-base/src/orchestrator
+       gitlab.com/project-emco/core/emco-base/src/rsync => ../rsync
        go.etcd.io/etcd => go.etcd.io/etcd v0.5.0-alpha.5.0.20200819165624-17cef6e3e9d5 // 17cef6e3e9d5 is the SHA for git tag v3.4.12
-       helm.sh/helm/v3 => helm.sh/helm/v3 v3.5.3
-       k8s.io/api => k8s.io/api v0.19.4
-       k8s.io/apiextensions-apiserver => k8s.io/apiextensions-apiserver v0.19.4
-       k8s.io/apimachinery => k8s.io/apimachinery v0.19.4
-       k8s.io/apiserver => k8s.io/apiserver v0.19.4
-       k8s.io/cli-runtime => k8s.io/cli-runtime v0.19.4
-       k8s.io/client-go => k8s.io/client-go v0.19.4
-       k8s.io/cloud-provider => k8s.io/cloud-provider v0.19.4
-       k8s.io/cluster-bootstrap => k8s.io/cluster-bootstrap v0.19.4
-       k8s.io/code-generator => k8s.io/code-generator v0.19.4
-       k8s.io/component-base => k8s.io/component-base v0.19.4
-       k8s.io/cri-api => k8s.io/cri-api v0.19.4
-       k8s.io/csi-translation-lib => k8s.io/csi-translation-lib v0.19.4
-       k8s.io/kube-aggregator => k8s.io/kube-aggregator v0.19.4
-       k8s.io/kube-controller-manager => k8s.io/kube-controller-manager v0.19.4
-       k8s.io/kube-proxy => k8s.io/kube-proxy v0.19.4
-       k8s.io/kube-scheduler => k8s.io/kube-scheduler v0.19.4
-       k8s.io/kubectl => k8s.io/kubectl v0.19.4
-       k8s.io/kubelet => k8s.io/kubelet v0.19.4
-       k8s.io/kubernetes => github.com/kubernetes/kubernetes v1.19.4
-       k8s.io/legacy-cloud-providers => k8s.io/legacy-cloud-providers v0.19.4
-       k8s.io/metrics => k8s.io/metrics v0.19.4
-       k8s.io/sample-apiserver => k8s.io/sample-apiserver v0.19.4
+       google.golang.org/grpc => google.golang.org/grpc v1.29.0
 )
index 5b31456..4a2a034 100644 (file)
-bazil.org/fuse v0.0.0-20160811212531-371fbbdaa898/go.mod h1:Xbm+BRKSBEpa4q4hTSxohYNQpsxXPbPry4JJWOB3LB8=
-cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
 cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
-cloud.google.com/go v0.37.4/go.mod h1:NHPJ89PdicEuT9hdPXMROBD91xc5uRDxsMtSB16k7hw=
 cloud.google.com/go v0.38.0/go.mod h1:990N+gfupTy94rShfmMCWGDn0LpTmnzTp2qbd1dvSRU=
 cloud.google.com/go v0.44.1/go.mod h1:iSa0KzasP4Uvy3f1mN/7PiObzGgflwredwwASm/v6AU=
 cloud.google.com/go v0.44.2/go.mod h1:60680Gw3Yr4ikxnPRS/oxxkBccT6SA1yMk63TGekxKY=
 cloud.google.com/go v0.45.1/go.mod h1:RpBamKRgapWJb87xiFSdk4g1CME7QZg3uwTez+TSTjc=
 cloud.google.com/go v0.46.3/go.mod h1:a6bKKbmY7er1mI7TEI4lsAkts/mkhTSZK8w33B4RAg0=
-cloud.google.com/go v0.49.0/go.mod h1:hGvAdzcWNbyuxS3nWhD7H2cIJxjRRTRLQVB0bdputVY=
-cloud.google.com/go v0.51.0/go.mod h1:hWtGJ6gnXH+KgDv+V0zFGDvpi07n3z8ZNj3T1RW0Gcw=
+cloud.google.com/go v0.50.0/go.mod h1:r9sluTvynVuxRIOHXQEHMFffphuXHOMZMycpNR5e6To=
+cloud.google.com/go v0.52.0/go.mod h1:pXajvRH/6o3+F9jDHZWQ5PbGhn+o8w9qiu/CffaVdO4=
+cloud.google.com/go v0.53.0/go.mod h1:fp/UouUEsRkN6ryDKNW/Upv/JBKnv6WDthjR6+vze6M=
+cloud.google.com/go v0.54.0/go.mod h1:1rq2OEkV3YMf6n/9ZvGWI3GWw0VoqH/1x2nd8Is/bPc=
+cloud.google.com/go v0.56.0/go.mod h1:jr7tqZxxKOVYizybht9+26Z/gUq7tiRzu+ACVAMbKVk=
+cloud.google.com/go v0.57.0/go.mod h1:oXiQ6Rzq3RAkkY7N6t3TcE6jE+CIBBbA36lwQ1JyzZs=
+cloud.google.com/go v0.62.0/go.mod h1:jmCYTdRCQuc1PHIIJ/maLInMho30T/Y0M4hTdTShOYc=
+cloud.google.com/go v0.65.0/go.mod h1:O5N8zS7uWy9vkA9vayVHs65eM1ubvY4h553ofrNHObY=
+cloud.google.com/go v0.72.0/go.mod h1:M+5Vjvlc2wnp6tjzE102Dw08nGShTscUx2nZMufOKPI=
+cloud.google.com/go v0.74.0/go.mod h1:VV1xSbzvo+9QJOxLDaJfTjx5e+MePCpCWwvftOeQmWk=
+cloud.google.com/go v0.78.0/go.mod h1:QjdrLG0uq+YwhjoVOLsS1t7TW8fs36kLs4XO5R5ECHg=
+cloud.google.com/go v0.79.0/go.mod h1:3bzgcEeQlzbuEAYu4mrWhKqWjmpprinYgKJLgKHnbb8=
+cloud.google.com/go v0.81.0/go.mod h1:mk/AM35KwGk/Nm2YSeZbxXdrNK3KZOYHmLkOqC2V6E0=
 cloud.google.com/go/bigquery v1.0.1/go.mod h1:i/xbL2UlR5RvWAURpBYZTtm/cXjCha9lbfbpx4poX+o=
 cloud.google.com/go/bigquery v1.3.0/go.mod h1:PjpwJnslEMmckchkHFfq+HTD2DmtT67aNFKH1/VBDHE=
+cloud.google.com/go/bigquery v1.4.0/go.mod h1:S8dzgnTigyfTmLBfrtrhyYhwRxG72rYxvftPBK2Dvzc=
+cloud.google.com/go/bigquery v1.5.0/go.mod h1:snEHRnqQbz117VIFhE8bmtwIDY80NLUZUMb4Nv6dBIg=
+cloud.google.com/go/bigquery v1.7.0/go.mod h1://okPTzCYNXSlb24MZs83e2Do+h+VXtc4gLoIoXIAPc=
+cloud.google.com/go/bigquery v1.8.0/go.mod h1:J5hqkt3O0uAFnINi6JXValWIb1v0goeZM77hZzJN/fQ=
 cloud.google.com/go/datastore v1.0.0/go.mod h1:LXYbyblFSglQ5pkeyhO+Qmw7ukd3C+pD7TKLgZqpHYE=
+cloud.google.com/go/datastore v1.1.0/go.mod h1:umbIZjpQpHh4hmRpGhH4tLFup+FVzqBi1b3c64qFpCk=
 cloud.google.com/go/firestore v1.1.0/go.mod h1:ulACoGHTpvq5r8rxGJ4ddJZBZqakUQqClKRT5SZwBmk=
 cloud.google.com/go/pubsub v1.0.1/go.mod h1:R0Gpsv3s54REJCy4fxDixWD93lHJMoZTyQ2kNxGRt3I=
+cloud.google.com/go/pubsub v1.1.0/go.mod h1:EwwdRX2sKPjnvnqCa270oGRyludottCI76h+R3AArQw=
+cloud.google.com/go/pubsub v1.2.0/go.mod h1:jhfEVHT8odbXTkndysNHCcx0awwzvfOlguIAii9o8iA=
+cloud.google.com/go/pubsub v1.3.1/go.mod h1:i+ucay31+CNRpDW4Lu78I4xXG+O1r/MAHgjpRVR+TSU=
 cloud.google.com/go/storage v1.0.0/go.mod h1:IhtSnM/ZTZV8YYJWCY8RULGVqBDmpoyjwiyrjsg+URw=
-cloud.google.com/go/storage v1.3.0/go.mod h1:9IAwXhoyBJ7z9LcAwkj0/7NnPzYaPeZxxVp3zm+5IqA=
-contrib.go.opencensus.io/exporter/ocagent v0.6.0/go.mod h1:zmKjrJcdo0aYcVS7bmEeSEBLPA9YJp5bjrofdU3pIXs=
+cloud.google.com/go/storage v1.5.0/go.mod h1:tpKbwo567HUNpVclU5sGELwQWBDZ8gh0ZeosJ0Rtdos=
+cloud.google.com/go/storage v1.6.0/go.mod h1:N7U0C8pVQ/+NIKOBQyamJIeKQKkZ+mxpohlUTyfDhBk=
+cloud.google.com/go/storage v1.8.0/go.mod h1:Wv1Oy7z6Yz3DshWRJFhqM/UCfaWIRTdp0RXyy7KQOVs=
+cloud.google.com/go/storage v1.10.0/go.mod h1:FLPqc6j+Ki4BU591ie1oL6qBQGu2Bl/tZ9ullr3+Kg0=
 dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU=
-github.com/Azure/azure-pipeline-go v0.2.1/go.mod h1:UGSo8XybXnIGZ3epmeBw7Jdz+HiUVpqIlpz/HKHylF4=
-github.com/Azure/azure-pipeline-go v0.2.2/go.mod h1:4rQ/NZncSvGqNkkOsNpOU1tgoNuIlp9AfUH5G1tvCHc=
 github.com/Azure/azure-sdk-for-go v16.2.1+incompatible/go.mod h1:9XXNKU+eRnpl9moKnB4QOLf1HestfXbmab5FXxiDBjc=
-github.com/Azure/azure-sdk-for-go v23.2.0+incompatible/go.mod h1:9XXNKU+eRnpl9moKnB4QOLf1HestfXbmab5FXxiDBjc=
-github.com/Azure/azure-sdk-for-go v36.1.0+incompatible/go.mod h1:9XXNKU+eRnpl9moKnB4QOLf1HestfXbmab5FXxiDBjc=
-github.com/Azure/azure-storage-blob-go v0.8.0/go.mod h1:lPI3aLPpuLTeUwh1sViKXFxwl2B6teiRqI0deQUvsw0=
-github.com/Azure/go-ansiterm v0.0.0-20170929234023-d6e3b3328b78/go.mod h1:LmzpDX56iTiv29bbRTIsUNlaFfuhWRQBWjQdVyAevI8=
+github.com/Azure/go-ansiterm v0.0.0-20210608223527-2377c96fe795/go.mod h1:LmzpDX56iTiv29bbRTIsUNlaFfuhWRQBWjQdVyAevI8=
+github.com/Azure/go-ansiterm v0.0.0-20210617225240-d185dfc1b5a1 h1:UQHMgLO+TxOElx5B5HZ4hJQsoJ/PvUvKRhJHDQXO8P8=
+github.com/Azure/go-ansiterm v0.0.0-20210617225240-d185dfc1b5a1/go.mod h1:xomTg63KZ2rFqZQzSB4Vz2SUXa1BpHTVz9L5PTmPC4E=
 github.com/Azure/go-autorest v10.8.1+incompatible/go.mod h1:r+4oMnoxhatjLLJ6zxSWATqVooLgysK6ZNox3g/xq24=
-github.com/Azure/go-autorest v11.2.8+incompatible/go.mod h1:r+4oMnoxhatjLLJ6zxSWATqVooLgysK6ZNox3g/xq24=
-github.com/Azure/go-autorest/autorest v0.9.0/go.mod h1:xyHB1BMZT0cuDHU7I0+g046+BFDTQ8rEZB0s4Yfa6bI=
-github.com/Azure/go-autorest/autorest v0.9.3-0.20191028180845-3492b2aff503/go.mod h1:xyHB1BMZT0cuDHU7I0+g046+BFDTQ8rEZB0s4Yfa6bI=
-github.com/Azure/go-autorest/autorest v0.9.6/go.mod h1:/FALq9T/kS7b5J5qsQ+RSTUdAmGFqi0vUdVNNx8q630=
-github.com/Azure/go-autorest/autorest/adal v0.5.0/go.mod h1:8Z9fGy2MpX0PvDjB1pEgQTmVqjGhiHBW7RJJEciWzS0=
-github.com/Azure/go-autorest/autorest/adal v0.8.1-0.20191028180845-3492b2aff503/go.mod h1:Z6vX6WXXuyieHAXwMj0S6HY6e6wcHn37qQMBQlvY3lc=
-github.com/Azure/go-autorest/autorest/adal v0.8.2/go.mod h1:ZjhuQClTqx435SRJ2iMlOxPYt3d2C/T/7TiQCVZSn3Q=
-github.com/Azure/go-autorest/autorest/date v0.1.0/go.mod h1:plvfp3oPSKwf2DNjlBjWF/7vwR+cUD/ELuzDCXwHUVA=
-github.com/Azure/go-autorest/autorest/date v0.2.0/go.mod h1:vcORJHLJEh643/Ioh9+vPmf1Ij9AEBM5FuBIXLmIy0g=
-github.com/Azure/go-autorest/autorest/mocks v0.1.0/go.mod h1:OTyCOPRA2IgIlWxVYxBee2F5Gr4kF2zd2J5cFRaIDN0=
-github.com/Azure/go-autorest/autorest/mocks v0.2.0/go.mod h1:OTyCOPRA2IgIlWxVYxBee2F5Gr4kF2zd2J5cFRaIDN0=
-github.com/Azure/go-autorest/autorest/mocks v0.3.0/go.mod h1:a8FDP3DYzQ4RYfVAxAN3SVSiiO77gL2j2ronKKP0syM=
-github.com/Azure/go-autorest/autorest/to v0.3.1-0.20191028180845-3492b2aff503/go.mod h1:MgwOyqaIuKdG4TL/2ywSsIWKAfJfgHDo8ObuUk3t5sA=
-github.com/Azure/go-autorest/autorest/validation v0.2.1-0.20191028180845-3492b2aff503/go.mod h1:3EEqHnBxQGHXRYq3HT1WyXAvT7LLY3tl70hw6tQIbjI=
-github.com/Azure/go-autorest/logger v0.1.0/go.mod h1:oExouG+K6PryycPJfVSxi/koC6LSNgds39diKLz7Vrc=
-github.com/Azure/go-autorest/tracing v0.5.0/go.mod h1:r/s2XiOKccPW3HrqB+W0TQzfbtp2fGCgRFtBroKn4Dk=
-github.com/BurntSushi/toml v0.3.1 h1:WXkYYl6Yr3qBf1K79EBnL4mak0OimBfB0XUf9Vl28OQ=
+github.com/Azure/go-autorest v14.2.0+incompatible/go.mod h1:r+4oMnoxhatjLLJ6zxSWATqVooLgysK6ZNox3g/xq24=
+github.com/Azure/go-autorest/autorest v0.11.18/go.mod h1:dSiJPy22c3u0OtOKDNttNgqpNFY/GeWa7GH/Pz56QRA=
+github.com/Azure/go-autorest/autorest/adal v0.9.13/go.mod h1:W/MM4U6nLxnIskrw4UwWzlHfGjwUS50aOsc/I3yuU8M=
+github.com/Azure/go-autorest/autorest/date v0.3.0/go.mod h1:BI0uouVdmngYNUzGWeSYnokU+TrmwEsOqdt8Y6sso74=
+github.com/Azure/go-autorest/autorest/mocks v0.4.1/go.mod h1:LTp+uSrOhSkaKrUy935gNZuuIPPVsHlr9DSOxSayd+k=
+github.com/Azure/go-autorest/logger v0.2.1/go.mod h1:T9E3cAhj2VqvPOtCYAvby9aBXkZmbF5NWuPV8+WeEW8=
+github.com/Azure/go-autorest/tracing v0.6.0/go.mod h1:+vhtPC754Xsa23ID7GlGsrdKBpUA79WCAKPPZVC2DeU=
 github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
 github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo=
-github.com/DATA-DOG/go-sqlmock v1.5.0/go.mod h1:f/Ixk793poVmq4qj/V1dPUg2JEAKC73Q5eFN3EC/SaM=
-github.com/DataDog/datadog-go v3.2.0+incompatible/go.mod h1:LButxg5PwREeZtORoXG3tL4fMGNddJ+vMq1mwgfaqoQ=
-github.com/Knetic/govaluate v3.0.1-0.20171022003610-9aa49832a739+incompatible/go.mod h1:r7JcOSlj0wfOMncg0iLm8Leh48TZaKVeNIfJntJ2wa0=
+github.com/MakeNowJust/heredoc v0.0.0-20170808103936-bb23615498cd h1:sjQovDkwrZp8u+gxLtPgKGjk5hCxuy2hrRejBTA9xFU=
 github.com/MakeNowJust/heredoc v0.0.0-20170808103936-bb23615498cd/go.mod h1:64YHyfSL2R96J44Nlwm39UHepQbyR5q10x7iYa1ks2E=
-github.com/Masterminds/goutils v1.1.1/go.mod h1:8cTjp+g8YejhMuvIA5y2vz3BpJxksy863GQaJW2MFNU=
-github.com/Masterminds/semver/v3 v3.1.1/go.mod h1:VPu/7SZ7ePZ3QOrcuXROw5FAcLl4a0cBrbBpGY/8hQs=
-github.com/Masterminds/sprig/v3 v3.2.2/go.mod h1:UoaO7Yp8KlPnJIYWTFkMaqPUYKTfGFPhxNuwnnxkKlk=
-github.com/Masterminds/squirrel v1.5.0/go.mod h1:NNaOrjSoIDfDA40n7sr2tPNZRfjzjA400rg+riTZj10=
-github.com/Masterminds/vcs v1.13.1/go.mod h1:N09YCmOQr6RLxC6UNHzuVwAdodYbbnycGHSmwVJjcKA=
-github.com/Microsoft/go-winio v0.4.11/go.mod h1:VhR8bwka0BXejwEJY73c50VrPtXAaKcyvVC4A4RozmA=
-github.com/Microsoft/go-winio v0.4.15-0.20190919025122-fc70bd9a86b5/go.mod h1:tTuCMEN+UleMWgg9dVx4Hu52b1bJo+59jBh3ajtinzw=
-github.com/Microsoft/go-winio v0.4.16-0.20201130162521-d1ffc52c7331/go.mod h1:XB6nPKklQyQ7GC9LdcBEcBl8PF76WugXOPRXwdLnMv0=
+github.com/Microsoft/go-winio v0.4.14/go.mod h1:qXqCSQ3Xa7+6tgxaGTIe4Kpcdsi+P8jBhyzoq1bpyYA=
 github.com/Microsoft/go-winio v0.4.16/go.mod h1:XB6nPKklQyQ7GC9LdcBEcBl8PF76WugXOPRXwdLnMv0=
-github.com/Microsoft/hcsshim v0.8.9/go.mod h1:5692vkUqntj1idxauYlpoINNKeqCiG6Sg38RRsjT5y8=
-github.com/Microsoft/hcsshim v0.8.14/go.mod h1:NtVKoYxQuTLx6gEq0L96c9Ju4JbRJ4nY2ow3VK6a9Lg=
 github.com/NYTimes/gziphandler v0.0.0-20170623195520-56545f4a5d46/go.mod h1:3wb06e3pkSAbeQ52E9H9iFoQsEEwGN64994WTCIhntQ=
 github.com/NYTimes/gziphandler v1.1.1/go.mod h1:n/CVRwUEOgIxrgPvAQhUUr9oeUtvrhMomdKFjzJNB0c=
-github.com/Nvveen/Gotty v0.0.0-20120604004816-cd527374f1e5/go.mod h1:lmUJ/7eu/Q8D7ML55dXQrVaamCz2vxCfdQBasLZfHKk=
 github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU=
-github.com/OneOfOne/xxhash v1.2.6/go.mod h1:eZbhyaAYD41SGSSsnmcpxVoRiQ/MPUTjUdIIOT9Um7Q=
-github.com/PuerkitoBio/purell v1.0.0/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbtSwDGJws/X0=
-github.com/PuerkitoBio/purell v1.1.0/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbtSwDGJws/X0=
+github.com/ProtonMail/go-crypto v0.0.0-20210428141323-04723f9f07d7/go.mod h1:z4/9nQmJSSwwds7ejkxaJwO37dru3geImFUdJlaLzQo=
 github.com/PuerkitoBio/purell v1.1.1 h1:WEQqlqaGbrPkxLJWfBwQmfEAE1Z7ONdDLqrN38tNFfI=
 github.com/PuerkitoBio/purell v1.1.1/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbtSwDGJws/X0=
-github.com/PuerkitoBio/urlesc v0.0.0-20160726150825-5bd2802263f2/go.mod h1:uGdkoq3SwY9Y+13GIhn11/XLaGBb4BfwItxLd5jeuXE=
 github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578 h1:d+Bc7a5rLufV/sSk/8dngufqelfh6jnri85riMAaF/M=
 github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578/go.mod h1:uGdkoq3SwY9Y+13GIhn11/XLaGBb4BfwItxLd5jeuXE=
 github.com/Shopify/logrus-bugsnag v0.0.0-20171204204709-577dee27f20d/go.mod h1:HI8ITrYtUY+O+ZhtlqUnD8+KwNPOyugEhfP9fdUIaEQ=
-github.com/Shopify/sarama v1.19.0/go.mod h1:FVkBWblsNy7DGZRfXLU0O9RCGt5g3g3yEuWXgklEdEo=
-github.com/Shopify/toxiproxy v2.1.4+incompatible/go.mod h1:OXgGpZ6Cli1/URJOF1DMxUHB2q5Ap20/P/eIdh4G0pI=
-github.com/VividCortex/gohistogram v1.0.0/go.mod h1:Pf5mBqqDxYaXu3hDrrU+w6nw50o/4+TcAqDqk/vUH7g=
-github.com/afex/hystrix-go v0.0.0-20180502004556-fa1af6a1f4f5/go.mod h1:SkGFH1ia65gfNATL8TAiHDNxPzPdmEL5uirI2Uyuz6c=
-github.com/agnivade/levenshtein v1.0.1/go.mod h1:CURSv5d9Uaml+FovSIICkLbAUZ9S4RqaHDIsdSBg7lM=
+github.com/acomagu/bufpipe v1.0.3/go.mod h1:mxdxdup/WdsKVreO5GpW4+M/1CE2sMG4jeGJ2sYmHc4=
 github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
 github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
 github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=
 github.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=
 github.com/alecthomas/units v0.0.0-20190924025748-f65c72e2690d/go.mod h1:rBZYJk541a8SKzHPHnH3zbiI+7dagKZ0cgpgrD7Fyho=
-github.com/aliyun/aliyun-oss-go-sdk v2.0.4+incompatible/go.mod h1:T/Aws4fEfogEE9v+HPhhw+CntffsBHJ8nXQCwKr0/g8=
-github.com/andreyvit/diff v0.0.0-20170406064948-c7f18ee00883/go.mod h1:rCTlJbsFo29Kk6CurOXKm700vrz8f0KW0JNfpkRJY/8=
-github.com/antihax/optional v0.0.0-20180407024304-ca021399b1a6/go.mod h1:V8iCPQYkqmusNa815XgQio277wI47sdRh1dUOLdyC6Q=
-github.com/apache/thrift v0.12.0/go.mod h1:cp2SuWMxlEZw2r+iP2GNCdIi4C1qmUzdZFSVb+bacwQ=
-github.com/apache/thrift v0.13.0/go.mod h1:cp2SuWMxlEZw2r+iP2GNCdIi4C1qmUzdZFSVb+bacwQ=
+github.com/anmitsu/go-shlex v0.0.0-20161002113705-648efa622239/go.mod h1:2FmKhYUyUczH0OGQWaF5ceTx0UBShxjsH6f8oGKYe2c=
+github.com/antihax/optional v1.0.0/go.mod h1:uupD/76wgC+ih3iEmQUL+0Ugr19nfwCT1kdvxnR2qWY=
+github.com/antlr/antlr4/runtime/Go/antlr v0.0.0-20210826220005-b48c857c3a0e/go.mod h1:F7bn7fEU90QkQ3tnmaTx3LTKLEDqnwWODIYppRQ5hnY=
 github.com/armon/circbuf v0.0.0-20150827004946-bbbad097214e/go.mod h1:3U/XgcO3hCbHZ8TKRvWD2dDTCfh9M9ya+I9JpbB7O8o=
 github.com/armon/consul-api v0.0.0-20180202201655-eb2c6b5be1b6/go.mod h1:grANhF5doyWs3UAsr3K4I6qtAmlQcZDesFNEHPZAzj8=
 github.com/armon/go-metrics v0.0.0-20180917152333-f0300d1749da/go.mod h1:Q73ZrmVTwzkszR9V5SSuryQ31EELlFMUz1kKyl939pY=
-github.com/armon/go-metrics v0.3.0/go.mod h1:zXjbSimjXTd7vOpY8B0/2LpvNvDoXBuplAD+gJD3GYs=
 github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8=
-github.com/armon/go-radix v1.0.0/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8=
-github.com/aryann/difflib v0.0.0-20170710044230-e206f873d14a/go.mod h1:DAHtR1m6lCRdSC2Tm3DSWRPvIPr6xNKyeHdqDQSQT+A=
-github.com/asaskevich/govalidator v0.0.0-20180720115003-f9ffefc3facf/go.mod h1:lB+ZfQJz7igIIfQNfa7Ml4HSf2uFQQRzpGGRXenZAgY=
+github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5/go.mod h1:wHh0iHkYZB8zMSxRWpUBQtwG5a7fFgvEO+odwuTv2gs=
 github.com/asaskevich/govalidator v0.0.0-20190424111038-f61b66f89f4a/go.mod h1:lB+ZfQJz7igIIfQNfa7Ml4HSf2uFQQRzpGGRXenZAgY=
-github.com/asaskevich/govalidator v0.0.0-20200428143746-21a406dcc535/go.mod h1:oGkLhpf+kjZl6xBf758TQhh5XrAeiJv/7FRz/2spLIg=
-github.com/aws/aws-lambda-go v1.13.3/go.mod h1:4UKl9IzQMoD+QF79YdCuzCwp8VbmG4VAQwij/eHl5CU=
 github.com/aws/aws-sdk-go v1.15.11/go.mod h1:mFuSZ37Z9YOHbQEwBWztmVzqXrEkub65tZoCYDt7FT0=
-github.com/aws/aws-sdk-go v1.17.7/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo=
-github.com/aws/aws-sdk-go v1.25.48/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo=
-github.com/aws/aws-sdk-go v1.27.0/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo=
-github.com/aws/aws-sdk-go-v2 v0.18.0/go.mod h1:JWVYvqSMppoMJC0x5wdwiImzgXTI9FuZwxzkQq9wy+g=
-github.com/baiyubin/aliyun-sts-go-sdk v0.0.0-20180326062324-cfa1a18b161f/go.mod h1:AuiFmCCPBSrqvVMvuqFuk0qogytodnVFVSN5CeJB8Gc=
+github.com/benbjohnson/clock v1.0.3/go.mod h1:bGMdMPoPVvcYyt1gHDf4J2KE153Yf9BuiUKYMaxlTDM=
+github.com/benbjohnson/clock v1.1.0 h1:Q92kusRqC1XV2MjkWETPvjJVqKetz1OzxZB7mHJLju8=
+github.com/benbjohnson/clock v1.1.0/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA=
 github.com/beorn7/perks v0.0.0-20160804104726-4c0e84591b9a/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q=
 github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q=
 github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8=
 github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM=
 github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw=
 github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs=
-github.com/bitly/go-hostpool v0.0.0-20171023180738-a3a6125de932/go.mod h1:NOuUCSz6Q9T7+igc/hlvDOUdtWKryOrtFyIVABv/p7k=
 github.com/bitly/go-simplejson v0.5.0/go.mod h1:cXHtHw4XUPsvGaxgjIAn8PhEWG9NfngEKAMDJEczWVA=
 github.com/bketelsen/crypt v0.0.3-0.20200106085610-5cbc8cc4026c/go.mod h1:MKsuJmJgSg28kpZDP6UIiPt0e0Oz0kqKNGyRaWEPv84=
-github.com/blang/semver v3.5.0+incompatible/go.mod h1:kRBLl5iJ+tD4TcOOxsy/0fnwebNt5EWlYSAyrTnjyyk=
+github.com/bketelsen/crypt v0.0.4/go.mod h1:aI6NrJ0pMGgvZKL1iVgXLnfIFJtfV+bKCoqOes/6LfM=
 github.com/blang/semver v3.5.1+incompatible/go.mod h1:kRBLl5iJ+tD4TcOOxsy/0fnwebNt5EWlYSAyrTnjyyk=
 github.com/bmizerany/assert v0.0.0-20160611221934-b7ed37b82869/go.mod h1:Ekp36dRnpXw/yCqJaO+ZrUyxD+3VXMFFr56k5XYrpB4=
-github.com/bradfitz/gomemcache v0.0.0-20190913173617-a41fca850d0b/go.mod h1:H0wQNHz2YrLsuXOZozoeDmnHXkNCRmMW0gwFWDfEZDA=
-github.com/brancz/gojsontoyaml v0.0.0-20191212081931-bf2969bbd742/go.mod h1:IyUJYN1gvWjtLF5ZuygmxbnsAyP3aJS6cHzIuZY50B0=
-github.com/brancz/kube-rbac-proxy v0.5.0/go.mod h1:cL2VjiIFGS90Cjh5ZZ8+It6tMcBt8rwvuw2J6Mamnl0=
 github.com/bshuster-repo/logrus-logstash-hook v0.4.1/go.mod h1:zsTqEiSzDgAa/8GZR7E1qaXrhYNDKBYy5/dWPTIflbk=
 github.com/bugsnag/bugsnag-go v0.0.0-20141110184014-b1d153021fcd/go.mod h1:2oa8nejYd4cQ/b0hMIopN0lCRxU0bueqREvZLWFrtK8=
 github.com/bugsnag/osext v0.0.0-20130617224835-0dd3f918b21b/go.mod h1:obH5gd0BsqsP2LwDJ9aOkm/6J86V6lyAXCoQWGw3K50=
 github.com/bugsnag/panicwrap v0.0.0-20151223152923-e2c28503fcd0/go.mod h1:D/8v3kj0zr8ZAKg1AQ6crr+5VwKN5eIywRkfhyM/+dE=
-github.com/campoy/embedmd v1.0.0/go.mod h1:oxyr9RCiSXg0M3VJ3ks0UGfp98BpSSGr0kpiX3MzVl8=
-github.com/casbin/casbin/v2 v2.1.2/go.mod h1:YcPU1XXisHhLzuxH9coDNf2FbKpjGlbCg3n9yuLkIJQ=
-github.com/cenkalti/backoff v0.0.0-20181003080854-62661b46c409/go.mod h1:90ReRw6GdpyfrHakVjL/QHaoyV4aDUVVkXQJJJ3NXXM=
-github.com/cenkalti/backoff v2.2.1+incompatible/go.mod h1:90ReRw6GdpyfrHakVjL/QHaoyV4aDUVVkXQJJJ3NXXM=
 github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
-github.com/cespare/xxhash v0.0.0-20181017004759-096ff4a8a059/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc=
+github.com/certifi/gocertifi v0.0.0-20191021191039-0944d244cd40/go.mod h1:sGbDF6GwGcLpkNXPUTkMRoywsNa/ol15pxFe6ERfguA=
+github.com/certifi/gocertifi v0.0.0-20200922220541-2c3bb06c6054 h1:uH66TXeswKn5PW5zdZ39xEwfS9an067BirqA+P4QaLI=
+github.com/certifi/gocertifi v0.0.0-20200922220541-2c3bb06c6054/go.mod h1:sGbDF6GwGcLpkNXPUTkMRoywsNa/ol15pxFe6ERfguA=
 github.com/cespare/xxhash v1.1.0 h1:a6HrQnmkObjyL+Gs60czilIUGqrzKutQD6XZog3p+ko=
 github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc=
-github.com/cespare/xxhash/v2 v2.1.0/go.mod h1:dgIUBU3pDso/gPgZ1osOZ0iQf77oPR28Tjxl5dIMyVM=
 github.com/cespare/xxhash/v2 v2.1.1 h1:6MnRN8NT7+YBpUIWxHtefFZOKTAPgGjpQSxqLNn0+qY=
 github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
+github.com/chai2010/gettext-go v0.0.0-20160711120539-c6fed771bfd5 h1:7aWHqerlJ41y6FOsEUvknqgXnGmJyJSbjhAWq5pO4F8=
 github.com/chai2010/gettext-go v0.0.0-20160711120539-c6fed771bfd5/go.mod h1:/iP1qXHoty45bqomnu2LM+VVyAEdWN+vtSHGlQgyxbw=
 github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI=
 github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI=
 github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU=
-github.com/cilium/ebpf v0.0.0-20200110133405-4032b1d8aae3/go.mod h1:MA5e5Lr8slmEg9bt0VpxxWqJlO4iwu3FBdHUzV7wQVg=
-github.com/circonus-labs/circonus-gometrics v2.3.1+incompatible/go.mod h1:nmEj6Dob7S7YxXgwXpfOuvO54S+tGdZdw9fuRZt25Ag=
-github.com/circonus-labs/circonusllhist v0.1.3/go.mod h1:kMXHVDlOchFAehlya5ePtbp5jckzBHf4XRpQvBOLI+I=
-github.com/clbanning/x2j v0.0.0-20191024224557-825249438eec/go.mod h1:jMjuTZXRI4dUb/I5gc9Hdhagfvm9+RyrPryS/auMzxE=
-github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
 github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc=
-github.com/cockroachdb/apd v1.1.0/go.mod h1:8Sl8LxpKi29FqWXR16WEFZRNSz3SoPzUzeMeY4+DwBQ=
-github.com/cockroachdb/cockroach-go v0.0.0-20181001143604-e0a95dfd547c/go.mod h1:XGLbWH/ujMcbPbhZq52Nv6UrCghb1yGn//133kEsvDk=
-github.com/cockroachdb/datadriven v0.0.0-20190809214429-80d97fb3cbaa h1:OaNxuTZr7kxeODyLWsRMC+OD03aFUH+mW6r2d+MWa5Y=
 github.com/cockroachdb/datadriven v0.0.0-20190809214429-80d97fb3cbaa/go.mod h1:zn76sxSg3SzpJ0PPJaLDCu+Bu0Lg3sKTORVIj19EIF8=
-github.com/codahale/hdrhistogram v0.0.0-20161010025455-3a0bb77429bd/go.mod h1:sE/e/2PUdi/liOCUjSTXgM1o87ZssimdTWN964YiIeI=
-github.com/containerd/cgroups v0.0.0-20190919134610-bf292b21730f/go.mod h1:OApqhQ4XNSNC13gXIwDjhOQxjWa/NxkwZXJ1EvqT0ko=
-github.com/containerd/cgroups v0.0.0-20200531161412-0dbf7f05ba59/go.mod h1:pA0z1pT8KYB3TCXK/ocprsh7MAkoW8bZVzPdih9snmM=
-github.com/containerd/console v0.0.0-20180822173158-c12b1e7919c1/go.mod h1:Tj/on1eG8kiEhd0+fhSDzsPAFESxzBBvdyEgyryXffw=
-github.com/containerd/containerd v1.2.7/go.mod h1:bC6axHOhabU15QhwfG7w5PipXdVtMXFTttgp+kVtyUA=
-github.com/containerd/containerd v1.3.2/go.mod h1:bC6axHOhabU15QhwfG7w5PipXdVtMXFTttgp+kVtyUA=
-github.com/containerd/containerd v1.4.3/go.mod h1:bC6axHOhabU15QhwfG7w5PipXdVtMXFTttgp+kVtyUA=
-github.com/containerd/continuity v0.0.0-20190426062206-aaeac12a7ffc/go.mod h1:GL3xCUCBDV3CZiTSEKksMWbLE66hEyuu9qyDOOqM47Y=
-github.com/containerd/continuity v0.0.0-20200413184840-d3ef23f19fbb/go.mod h1:Dq467ZllaHgAtVp4p1xUQWBrFXR9s/wyoTpG8zOJGkY=
-github.com/containerd/continuity v0.0.0-20201208142359-180525291bb7/go.mod h1:kR3BEg7bDFaEddKm54WSmrol1fKWDU1nKYkgrcgZT7Y=
-github.com/containerd/fifo v0.0.0-20190226154929-a9fb20d87448/go.mod h1:ODA38xgv3Kuk8dQz2ZQXpnv/UZZUHUCL7pnLehbXgQI=
-github.com/containerd/go-runc v0.0.0-20180907222934-5a6d9f37cfa3/go.mod h1:IV7qH3hrUgRmyYrtgEeGWJfWbgcHL9CSRruz2Vqcph0=
-github.com/containerd/ttrpc v0.0.0-20190828154514-0e0f228740de/go.mod h1:PvCDdDGpgqzQIzDW1TphrGLssLDZp2GuS+X5DkEJB8o=
-github.com/containerd/ttrpc v1.0.1/go.mod h1:UAxOpgT9ziI0gJrmKvgcZivgxOp8iFPSk8httJEt98Y=
-github.com/containerd/typeurl v0.0.0-20180627222232-a93fcdb778cd/go.mod h1:Cm3kwCdlkCfMSHURc+r6fwoGH6/F1hH3S4sg0rLFWPc=
+github.com/cockroachdb/datadriven v0.0.0-20200714090401-bf6692d28da5 h1:xD/lrqdvwsc+O2bjSSi3YqY73Ke3LAiSCx49aCesA0E=
+github.com/cockroachdb/datadriven v0.0.0-20200714090401-bf6692d28da5/go.mod h1:h6jFvWxBdQXxjopDMZyH2UVceIRfR84bdzbkoKrsWNo=
+github.com/cockroachdb/errors v1.2.4 h1:Lap807SXTH5tri2TivECb/4abUkMZC9zRoLarvcKDqs=
+github.com/cockroachdb/errors v1.2.4/go.mod h1:rQD95gz6FARkaKkQXUksEje/d9a6wBJoCr5oaCLELYA=
+github.com/cockroachdb/logtags v0.0.0-20190617123548-eb05cc24525f h1:o/kfcElHqOiXqcou5a3rIlMc7oJbMQkeLk0VQJ7zgqY=
+github.com/cockroachdb/logtags v0.0.0-20190617123548-eb05cc24525f/go.mod h1:i/u985jwjWRlyHXQbwatDASoW0RMlZ/3i9yJHE2xLkI=
 github.com/coreos/bbolt v1.3.2/go.mod h1:iRUV2dpdMOn7Bo10OQBFzIJO9kkE559Wcmn+qkEiiKk=
 github.com/coreos/etcd v3.3.10+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE=
 github.com/coreos/etcd v3.3.13+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE=
-github.com/coreos/go-etcd v2.0.0+incompatible/go.mod h1:Jez6KQU2B/sWsbdaef3ED8NzMklzPG4d5KIOhIy30Tk=
 github.com/coreos/go-oidc v2.1.0+incompatible/go.mod h1:CgnwVTmzoESiwO9qyAFEMiHoZ1nMCKZlZ9V6mm3/LKc=
 github.com/coreos/go-semver v0.2.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk=
 github.com/coreos/go-semver v0.3.0 h1:wkHLiw0WNATZnSG7epLsujiMCgPAc9xhjJ4tgnAxmfM=
@@ -175,841 +128,646 @@ github.com/coreos/go-semver v0.3.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3Ee
 github.com/coreos/go-systemd v0.0.0-20180511133405-39ca1b05acc7/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4=
 github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e h1:Wf6HqHfScWJN9/ZjdUKyjop4mf3Qdd+1TvvltAvM3m8=
 github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4=
-github.com/coreos/go-systemd/v22 v22.0.0/go.mod h1:xO0FLkIi5MaZafQlIrOotqXZ90ih+1atmu1JpKERPPk=
+github.com/coreos/go-systemd/v22 v22.3.2/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc=
 github.com/coreos/pkg v0.0.0-20160727233714-3ac0863d7acf/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA=
 github.com/coreos/pkg v0.0.0-20180928190104-399ea9e2e55f h1:lBNOc5arjvs8E5mO2tbpBpLoyyu8B6e44T7hJy6potg=
 github.com/coreos/pkg v0.0.0-20180928190104-399ea9e2e55f/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA=
-github.com/coreos/prometheus-operator v0.38.1-0.20200424145508-7e176fda06cc/go.mod h1:erio69w1R/aC14D5nfvAXSlE8FT8jt2Hnavc50Dp33A=
-github.com/cpuguy83/go-md2man v1.0.10/go.mod h1:SmD6nW6nTyfqj6ABTjUi3V3JVMnlJmwcJI5acqYI6dE=
-github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU=
 github.com/cpuguy83/go-md2man/v2 v2.0.0/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU=
 github.com/creack/pty v1.1.7/go.mod h1:lj5s0c3V2DBrqTV7llrYr5NG6My20zk30Fl46Y7DoTY=
-github.com/cyphar/filepath-securejoin v0.2.2/go.mod h1:FpkQEhXnPnOthhzymB7CGsFk2G9VLXONKD9G7QGMM+4=
-github.com/cznic/b v0.0.0-20180115125044-35e9bbe41f07/go.mod h1:URriBxXwVq5ijiJ12C7iIZqlA69nTlI+LgI6/pwftG8=
-github.com/cznic/fileutil v0.0.0-20180108211300-6a051e75936f/go.mod h1:8S58EK26zhXSxzv7NQFpnliaOQsmDUxvoQO3rt154Vg=
-github.com/cznic/golex v0.0.0-20170803123110-4ab7c5e190e4/go.mod h1:+bmmJDNmKlhWNG+gwWCkaBoTy39Fs+bzRxVBzoTQbIc=
-github.com/cznic/internal v0.0.0-20180608152220-f44710a21d00/go.mod h1:olo7eAdKwJdXxb55TKGLiJ6xt1H0/tiiRCWKVLmtjY4=
-github.com/cznic/lldb v1.1.0/go.mod h1:FIZVUmYUVhPwRiPzL8nD/mpFcJ/G7SSXjjXYG4uRI3A=
-github.com/cznic/mathutil v0.0.0-20180504122225-ca4c9f2c1369/go.mod h1:e6NPNENfs9mPDVNRekM7lKScauxd5kXTr1Mfyig6TDM=
-github.com/cznic/ql v1.2.0/go.mod h1:FbpzhyZrqr0PVlK6ury+PoW3T0ODUV22OeWIxcaOrSE=
-github.com/cznic/sortutil v0.0.0-20150617083342-4c7342852e65/go.mod h1:q2w6Bg5jeox1B+QkJ6Wp/+Vn0G/bo3f1uY7Fn3vivIQ=
-github.com/cznic/strutil v0.0.0-20171016134553-529a34b1c186/go.mod h1:AHHPPPXTw0h6pVabbcbyGRK1DckRn7r/STdZEeIDzZc=
-github.com/cznic/zappy v0.0.0-20160723133515-2533cb5b45cc/go.mod h1:Y1SNZ4dRUOKXshKUbwUapqNncRrho4mkjQebgEHZLj8=
-github.com/davecgh/go-spew v0.0.0-20151105211317-5215b55f46b2/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
+github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
+github.com/creack/pty v1.1.11 h1:07n33Z8lZxZ2qwegKbObQohDhXDQxiMMz1NOUGYlesw=
+github.com/creack/pty v1.1.11/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
 github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
 github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
 github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
 github.com/daviddengcn/go-colortext v0.0.0-20160507010035-511bcaf42ccd/go.mod h1:dv4zxwHi5C/8AeI+4gX4dCWOIvNi7I6JCSX0HvlKPgE=
-github.com/deislabs/oras v0.10.0/go.mod h1:N1UzE7rBa9qLyN4l8IlBTxc2PkrRcKgWQ3HTJvRnJRE=
-github.com/denisenkom/go-mssqldb v0.0.0-20190515213511-eb9f6a1743f3/go.mod h1:zAg7JM8CkOJ43xKXIj7eRO9kmWm/TW578qo+oDO6tuM=
-github.com/denisenkom/go-mssqldb v0.0.0-20191001013358-cfbb681360f0/go.mod h1:xbL0rPBG9cCiLr28tMa8zpbdarY27NDyej4t/EjAShU=
 github.com/denverdino/aliyungo v0.0.0-20190125010748-a747050bb1ba/go.mod h1:dV8lFg6daOBZbT6/BDGIz6Y3WFGn8juu6G+CQ6LHtl0=
 github.com/dgrijalva/jwt-go v0.0.0-20170104182250-a601269ab70c/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ=
 github.com/dgrijalva/jwt-go v3.2.0+incompatible h1:7qlOGliEKZXTDg6OTjfoBKDXWrumCAMpl/TFQ4/5kLM=
 github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ=
 github.com/dgryski/go-sip13 v0.0.0-20181026042036-e10d5fee7954/go.mod h1:vAd38F8PWV+bWy6jNmig1y/TA+kYO4g3RSRF0IAv0no=
-github.com/dgryski/go-sip13 v0.0.0-20190329191031-25c5027a8c7b/go.mod h1:vAd38F8PWV+bWy6jNmig1y/TA+kYO4g3RSRF0IAv0no=
-github.com/dhui/dktest v0.3.0/go.mod h1:cyzIUfGsBEbZ6BT7tnXqAShHSXCZhSNmFl70sZ7c1yc=
 github.com/dnaeon/go-vcr v1.0.1/go.mod h1:aBB1+wY4s93YsC3HHjMBMrwTj2R9FHDzUr9KyGc8n1E=
-github.com/docker/cli v0.0.0-20200130152716-5d0cf8839492/go.mod h1:JLrzqnKDaYBop7H2jaqPtU4hHvMKP+vjCwu2uszcLI8=
-github.com/docker/cli v20.10.3+incompatible/go.mod h1:JLrzqnKDaYBop7H2jaqPtU4hHvMKP+vjCwu2uszcLI8=
 github.com/docker/distribution v0.0.0-20191216044856-a8371794149d/go.mod h1:0+TTO4EOBfRPhZXAeF1Vu+W3hHZ8eLp8PgKVZlcvtFY=
-github.com/docker/docker-credential-helpers v0.6.3/go.mod h1:WRaJzqw3CTB9bk10avuGsjVBZsD05qeibJ1/TYlvc0Y=
-github.com/docker/go-connections v0.4.0/go.mod h1:Gbd7IOopHjR8Iph03tsViu4nIes5XhDvyHbTtUxmeec=
-github.com/docker/go-events v0.0.0-20190806004212-e31b211e4f1c/go.mod h1:Uw6UezgYA44ePAFQYUehOuCzmy5zmg/+nl2ZfMWGkpA=
 github.com/docker/go-metrics v0.0.0-20180209012529-399ea8c73916/go.mod h1:/u0gXw0Gay3ceNrsHubL3BtdOL2fHf93USgMTe0W5dI=
-github.com/docker/go-units v0.3.3/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk=
-github.com/docker/go-units v0.4.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk=
 github.com/docker/libtrust v0.0.0-20150114040149-fa567046d9b1/go.mod h1:cyGadeNEkKy96OOhEzfZl+yxihPEzKnqJwvfuSUqbZE=
-github.com/docker/spdystream v0.0.0-20160310174837-449fdfce4d96/go.mod h1:Qh8CwZgvJUkLughtfhJv5dyTYa91l1fOUCrgjqmcifM=
 github.com/docopt/docopt-go v0.0.0-20180111231733-ee0de3bc6815/go.mod h1:WwZ+bS3ebgob9U8Nd0kOddGdZWjyMGR8Wziv+TBNwSE=
 github.com/dustin/go-humanize v0.0.0-20171111073723-bb3d318650d4/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk=
 github.com/dustin/go-humanize v1.0.0 h1:VSnTsYCnlFHaM2/igO1h6X3HA71jcobQuxemgkq4zYo=
 github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk=
-github.com/eapache/go-resiliency v1.1.0/go.mod h1:kFI+JgMyC7bLPUVY133qvEBtVayf5mFgVsvEsIPBvNs=
-github.com/eapache/go-xerial-snappy v0.0.0-20180814174437-776d5712da21/go.mod h1:+020luEh2TKB4/GOp8oxxtq0Daoen/Cii55CzbTV6DU=
-github.com/eapache/queue v1.1.0/go.mod h1:6eCeP0CKFpHLu8blIFXhExK/dRa7WDZfr6jVFPTqq+I=
-github.com/edsrzf/mmap-go v0.0.0-20170320065105-0bce6a688712/go.mod h1:YO35OhQPt3KJa3ryjFM5Bs14WD66h8eGKpfaBNrHW5M=
-github.com/edsrzf/mmap-go v1.0.0/go.mod h1:YO35OhQPt3KJa3ryjFM5Bs14WD66h8eGKpfaBNrHW5M=
-github.com/elastic/go-sysinfo v1.0.1/go.mod h1:O/D5m1VpYLwGjCYzEt63g3Z1uO3jXfwyzzjiW90t8cY=
-github.com/elastic/go-sysinfo v1.1.1/go.mod h1:i1ZYdU10oLNfRzq4vq62BEwD2fH8KaWh6eh0ikPT9F0=
-github.com/elastic/go-windows v1.0.0/go.mod h1:TsU0Nrp7/y3+VwE82FoZF8gC/XFg/Elz6CcloAxnPgU=
-github.com/elastic/go-windows v1.0.1/go.mod h1:FoVvqWSun28vaDQPbj2Elfc0JahhPB7WQEGa3c814Ss=
+github.com/elazarl/goproxy v0.0.0-20180725130230-947c36da3153 h1:yUdfgN0XgIJw7foRItutHYUIhlcKzcSf5vDpdhQAKTc=
 github.com/elazarl/goproxy v0.0.0-20180725130230-947c36da3153/go.mod h1:/Zj4wYkgs4iZTTu3o/KG3Itv/qCCa8VVMlb3i9OVuzc=
 github.com/emicklei/go-restful v0.0.0-20170410110728-ff4f55a20633/go.mod h1:otzb+WCGbkyDHkqmQmT5YD2WR4BBwUdeQoFo8l/7tVs=
-github.com/emicklei/go-restful v2.9.5+incompatible h1:spTtZBk5DYEvbxMVutUuTyh1Ao2r4iyvLdACqsl/Ljk=
 github.com/emicklei/go-restful v2.9.5+incompatible/go.mod h1:otzb+WCGbkyDHkqmQmT5YD2WR4BBwUdeQoFo8l/7tVs=
-github.com/envoyproxy/go-control-plane v0.6.9/go.mod h1:SBwIajubJHhxtWwsL9s8ss4safvEdbitLhGGK48rN6g=
-github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
-github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
+github.com/emirpasic/gods v1.12.0/go.mod h1:YfzfFFoVP/catgzJb4IKIqXjX78Ha8FMSDh3ymbK86o=
 github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98=
 github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c=
-github.com/evanphx/json-patch v4.1.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk=
-github.com/evanphx/json-patch v4.5.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk=
-github.com/evanphx/json-patch v4.9.0+incompatible h1:kLcOMZeuLAJvL2BPWLMIj5oaZQobrkAqrL+WFZwQses=
-github.com/evanphx/json-patch v4.9.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk=
+github.com/evanphx/json-patch v0.5.2/go.mod h1:ZWS5hhDbVDyob71nXKNL0+PWn6ToqBHMikGIFbs31qQ=
+github.com/evanphx/json-patch v4.11.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk=
+github.com/evanphx/json-patch v4.12.0+incompatible h1:4onqiflcdA9EOZ4RxV643DvftH5pOlLGNtQ5lPWQu84=
+github.com/evanphx/json-patch v4.12.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk=
 github.com/exponent-io/jsonpath v0.0.0-20151013193312-d6023ce2651d h1:105gxyaGwCFad8crR9dcMQWvV9Hvulu6hwUh4tWPJnM=
 github.com/exponent-io/jsonpath v0.0.0-20151013193312-d6023ce2651d/go.mod h1:ZZMPRZwes7CROmyNKgQzC3XPs6L/G2EJLHddWejkmf4=
-github.com/facette/natsort v0.0.0-20181210072756-2cd4dd1e2dcb/go.mod h1:bH6Xx7IW64qjjJq8M2u4dxNaBiDfKK+z/3eGDpXEQhc=
 github.com/fatih/camelcase v1.0.0/go.mod h1:yN2Sb0lFhZJUdVvtELVWefmrXpuZESvPmqwoZc+/fpc=
 github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4=
-github.com/fatih/structtag v1.1.0/go.mod h1:mBJUNpUnHmRKrKlQQlmCrh5PuhftFbNv8Ys4/aAZl94=
-github.com/fortytw2/leaktest v1.3.0/go.mod h1:jDsjWgpAGjm2CA7WthBh/CdZYEPF31XHquHwclZch5g=
-github.com/franela/goblin v0.0.0-20200105215937-c9ffbefa60db/go.mod h1:7dvUGVsVBjqR7JHJk0brhHOZYGmfBYOrK0ZhYMEtBr4=
-github.com/franela/goreq v0.0.0-20171204163338-bcd34c9993f8/go.mod h1:ZhphrRTfi2rbfLwlschooIH4+wKKDR4Pdxhh+TRoA20=
+github.com/felixge/httpsnoop v1.0.1/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U=
+github.com/fluxcd/go-git-providers v0.5.4 h1:MnByjsmXa8rMt2hTmhmtbocq7YIsTlwZKrj9lAsob4Q=
+github.com/fluxcd/go-git-providers v0.5.4/go.mod h1:4jTHTmSx3rFGnG78KUVgFYeG6vWFnKwUSr2mi31tvp8=
+github.com/fluxcd/kustomize-controller/api v0.21.1 h1:Abusz7ZxwD7bdWCsXLefowOi3e5DqPk5T+BvdbOYpK8=
+github.com/fluxcd/kustomize-controller/api v0.21.1/go.mod h1:LhESmzZMC//KGeSSDE31ZTw/J9CCXbuJpb4DwvL28kM=
+github.com/fluxcd/pkg/apis/acl v0.0.3 h1:Lw0ZHdpnO4G7Zy9KjrzwwBmDZQuy4qEjaU/RvA6k1lc=
+github.com/fluxcd/pkg/apis/acl v0.0.3/go.mod h1:XPts6lRJ9C9fIF9xVWofmQwftvhY25n1ps7W9xw0XLU=
+github.com/fluxcd/pkg/apis/kustomize v0.3.1 h1:wmb5D9e1+Rr3/5O3235ERuj+h2VKUArVfYYk68QKP+w=
+github.com/fluxcd/pkg/apis/kustomize v0.3.1/go.mod h1:k2HSRd68UwgNmOYBPOd6WbX6a2MH2X/Jeh7e3s3PFPc=
+github.com/fluxcd/pkg/apis/meta v0.10.2 h1:pnDBBEvfs4HaKiVAYgz+e/AQ8dLvcgmVfSeBroZ/KKI=
+github.com/fluxcd/pkg/apis/meta v0.10.2/go.mod h1:KQ2er9xa6koy7uoPMZjIjNudB5p4tXs+w0GO6fRcy7I=
+github.com/fluxcd/pkg/runtime v0.12.5 h1:/8+0UBnSHbO9DVG9IFTjc37lwofsixGbs5WpHso8n5s=
+github.com/fluxcd/pkg/runtime v0.12.5/go.mod h1:gspNvhAqodZgSmK1ZhMtvARBf/NGAlxmaZaIOHkJYsc=
+github.com/fluxcd/source-controller/api v0.21.2 h1:J0S5NN4V8FPLrkSMXIUoUvj1X/RuTpVJSjIRF414wmc=
+github.com/fluxcd/source-controller/api v0.21.2/go.mod h1:Ab2qDmAUz6ZCp8UaHYLYzxyFrC1FQqEqjxiROb/Rdiw=
+github.com/flynn/go-shlex v0.0.0-20150515145356-3f9db97f8568/go.mod h1:xEzjJPgXI435gkrCt3MPfRiAkVrwSbHsst4LCFVfpJc=
+github.com/form3tech-oss/jwt-go v3.2.2+incompatible/go.mod h1:pbq4aXjuKjdthFRnoDwaVPLA+WlJuPGy+QneDUgJi2k=
+github.com/form3tech-oss/jwt-go v3.2.3+incompatible/go.mod h1:pbq4aXjuKjdthFRnoDwaVPLA+WlJuPGy+QneDUgJi2k=
 github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
 github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ=
-github.com/fsouza/fake-gcs-server v1.7.0/go.mod h1:5XIRs4YvwNbNoz+1JF8j6KLAyDh7RHGAyAK3EP2EsNk=
+github.com/fsnotify/fsnotify v1.5.1 h1:mZcQUHVQUQWoPXXtuf9yuEXKudkV2sx1E06UadKWpgI=
+github.com/fsnotify/fsnotify v1.5.1/go.mod h1:T3375wBYaZdLLcVNkcVbzGHY7f1l/uK5T5Ai1i3InKU=
+github.com/fvbommel/sortorder v1.0.1 h1:dSnXLt4mJYH25uDDGa3biZNQsozaUWDSWeKJ0qqFfzE=
+github.com/fvbommel/sortorder v1.0.1/go.mod h1:uk88iVf1ovNn1iLfgUVU2F9o5eO30ui720w+kxuqRs0=
 github.com/garyburd/redigo v0.0.0-20150301180006-535138d7bcd7/go.mod h1:NR3MbYisc3/PwhQ00EMzDiPmrwpPxAn5GI05/YaO1SY=
-github.com/ghodss/yaml v0.0.0-20150909031657-73d445a93680/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04=
+github.com/getkin/kin-openapi v0.76.0/go.mod h1:660oXbgy5JFMKreazJaQTw7o+X00qeSyhcnluiMv+Xg=
+github.com/getsentry/raven-go v0.2.0 h1:no+xWJRb5ZI7eE8TWgIq1jLulQiIoLG0IfYxv5JYMGs=
+github.com/getsentry/raven-go v0.2.0/go.mod h1:KungGk8q33+aIAZUIVWZDr2OfAEBsO49PX4NzFV5kcQ=
 github.com/ghodss/yaml v1.0.0 h1:wQHKEahhL6wmXdzwWG11gIVCkOv05bNOh+Rxn0yngAk=
 github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04=
-github.com/globalsign/mgo v0.0.0-20180905125535-1ca0a4f7cbcb/go.mod h1:xkRDCp4j0OGD1HRkm4kmhM+pmpv3AKq5SU7GMg4oO/Q=
-github.com/globalsign/mgo v0.0.0-20181015135952-eeefdecb41b8/go.mod h1:xkRDCp4j0OGD1HRkm4kmhM+pmpv3AKq5SU7GMg4oO/Q=
-github.com/go-bindata/go-bindata/v3 v3.1.3/go.mod h1:1/zrpXsLD8YDIbhZRqXzm1Ghc7NhEvIN9+Z6R5/xH4I=
+github.com/gliderlabs/ssh v0.2.2/go.mod h1:U7qILu1NlMHj9FlMhZLlkCdDnU1DBEAqr0aevW3Awn0=
+github.com/go-errors/errors v1.0.1 h1:LUHzmkK3GUKUrL/1gfBUxAHzcev3apQlezX/+O7ma6w=
+github.com/go-errors/errors v1.0.1/go.mod h1:f4zRHt4oKfwPJE5k8C9vpYG+aDHdBFUsgrm6/TyX73Q=
+github.com/go-git/gcfg v1.5.0/go.mod h1:5m20vg6GwYabIxaOonVkTdrILxQMpEShl1xiMF4ua+E=
+github.com/go-git/go-billy/v5 v5.2.0/go.mod h1:pmpqyWchKfYfrkb/UVH4otLvyi/5gJlGI4Hb3ZqZ3W0=
+github.com/go-git/go-billy/v5 v5.3.1/go.mod h1:pmpqyWchKfYfrkb/UVH4otLvyi/5gJlGI4Hb3ZqZ3W0=
+github.com/go-git/go-git-fixtures/v4 v4.2.1/go.mod h1:K8zd3kDUAykwTdDCr+I0per6Y6vMiRR/nnVTBtavnB0=
+github.com/go-git/go-git/v5 v5.4.2/go.mod h1:gQ1kArt6d+n+BGd+/B/I74HwRTLhth2+zti4ihgckDc=
 github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU=
 github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8=
+github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8=
 github.com/go-ini/ini v1.25.4/go.mod h1:ByCAeIL28uOIIG0E3PJtZPDL8WnHpFKFOtgjp+3Ies8=
 github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as=
 github.com/go-kit/kit v0.9.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as=
-github.com/go-kit/kit v0.10.0/go.mod h1:xUsJbQ/Fp4kEt7AFgCuvyX4a71u8h9jB8tj/ORgOZ7o=
+github.com/go-kit/log v0.1.0/go.mod h1:zbhenjAZHb184qTLMA9ZjW7ThYL0H2mk7Q6pNt4vbaY=
 github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE=
 github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk=
 github.com/go-logfmt/logfmt v0.5.0/go.mod h1:wCYkCAKZfumFQihp8CzCvQ3paCTfi41vtzG1KdI/P7A=
 github.com/go-logr/logr v0.1.0/go.mod h1:ixOQHD9gLJUVQQ2ZOR7zLEifBX6tGkNJF4QyIY7sIas=
 github.com/go-logr/logr v0.2.0/go.mod h1:z6/tIYblkpsD+a4lm/fGIIU9mZ+XfAiaFtq7xTgseGU=
-github.com/go-logr/logr v0.2.1 h1:fV3MLmabKIZ383XifUjFSwcoGee0v9qgPp8wy5svibE=
-github.com/go-logr/logr v0.2.1/go.mod h1:z6/tIYblkpsD+a4lm/fGIIU9mZ+XfAiaFtq7xTgseGU=
-github.com/go-logr/zapr v0.1.0/go.mod h1:tabnROwaDl0UNxkVeFRbY8bwB37GwRv0P8lg6aAiEnk=
-github.com/go-logr/zapr v0.1.1/go.mod h1:tabnROwaDl0UNxkVeFRbY8bwB37GwRv0P8lg6aAiEnk=
-github.com/go-logr/zapr v0.2.0/go.mod h1:qhKdvif7YF5GI9NWEpyxTSSBdGmzkNguibrdCNVPunU=
-github.com/go-openapi/analysis v0.0.0-20180825180245-b006789cd277/go.mod h1:k70tL6pCuVxPJOHXQ+wIac1FUrvNkHolPie/cLEU6hI=
-github.com/go-openapi/analysis v0.17.0/go.mod h1:IowGgpVeD0vNm45So8nr+IcQ3pxVtpRoBWb8PVZO0ik=
-github.com/go-openapi/analysis v0.17.2/go.mod h1:IowGgpVeD0vNm45So8nr+IcQ3pxVtpRoBWb8PVZO0ik=
-github.com/go-openapi/analysis v0.18.0/go.mod h1:IowGgpVeD0vNm45So8nr+IcQ3pxVtpRoBWb8PVZO0ik=
-github.com/go-openapi/analysis v0.19.2/go.mod h1:3P1osvZa9jKjb8ed2TPng3f0i/UY9snX6gxi44djMjk=
-github.com/go-openapi/analysis v0.19.5/go.mod h1:hkEAkxagaIvIP7VTn8ygJNkd4kAYON2rCu0v0ObL0AU=
-github.com/go-openapi/errors v0.17.0/go.mod h1:LcZQpmvG4wyF5j4IhA73wkLFQg+QJXOQHVjmcZxhka0=
-github.com/go-openapi/errors v0.17.2/go.mod h1:LcZQpmvG4wyF5j4IhA73wkLFQg+QJXOQHVjmcZxhka0=
-github.com/go-openapi/errors v0.18.0/go.mod h1:LcZQpmvG4wyF5j4IhA73wkLFQg+QJXOQHVjmcZxhka0=
-github.com/go-openapi/errors v0.19.2/go.mod h1:qX0BLWsyaKfvhluLejVpVNwNRdXZhEbTA4kxxpKBC94=
-github.com/go-openapi/jsonpointer v0.0.0-20160704185906-46af16f9f7b1/go.mod h1:+35s3my2LFTysnkMfxsJBAMHj/DoqoB9knIWoYG/Vk0=
-github.com/go-openapi/jsonpointer v0.17.0/go.mod h1:cOnomiV+CVVwFLk0A/MExoFMjwdsUdVpsRhURCKh+3M=
-github.com/go-openapi/jsonpointer v0.17.2/go.mod h1:cOnomiV+CVVwFLk0A/MExoFMjwdsUdVpsRhURCKh+3M=
-github.com/go-openapi/jsonpointer v0.18.0/go.mod h1:cOnomiV+CVVwFLk0A/MExoFMjwdsUdVpsRhURCKh+3M=
-github.com/go-openapi/jsonpointer v0.19.2/go.mod h1:3akKfEdA7DF1sugOqz1dVQHBcuDBPKZGEoHC/NkiQRg=
-github.com/go-openapi/jsonpointer v0.19.3 h1:gihV7YNZK1iK6Tgwwsxo2rJbD1GTbdm72325Bq8FI3w=
+github.com/go-logr/logr v1.2.0/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A=
+github.com/go-logr/logr v1.2.2 h1:ahHml/yUpnlb96Rp8HCvtYVPY8ZYpxq3g7UYchIYwbs=
+github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A=
+github.com/go-logr/zapr v1.2.0/go.mod h1:Qa4Bsj2Vb+FAVeAKsLD8RLQ+YRJB8YDmOAKxaBQf7Ro=
+github.com/go-logr/zapr v1.2.2/go.mod h1:eIauM6P8qSvTw5o2ez6UEAfGjQKrxQTl5EoK+Qa2oG4=
 github.com/go-openapi/jsonpointer v0.19.3/go.mod h1:Pl9vOtqEWErmShwVjC8pYs9cog34VGT37dQOVbmoatg=
-github.com/go-openapi/jsonreference v0.0.0-20160704190145-13c6e3589ad9/go.mod h1:W3Z9FmVs9qj+KR4zFKmDPGiLdk1D9Rlm7cyMvf57TTg=
-github.com/go-openapi/jsonreference v0.17.0/go.mod h1:g4xxGn04lDIRh0GJb5QlpE3HfopLOL6uZrK/VgnsK9I=
-github.com/go-openapi/jsonreference v0.17.2/go.mod h1:g4xxGn04lDIRh0GJb5QlpE3HfopLOL6uZrK/VgnsK9I=
-github.com/go-openapi/jsonreference v0.18.0/go.mod h1:g4xxGn04lDIRh0GJb5QlpE3HfopLOL6uZrK/VgnsK9I=
-github.com/go-openapi/jsonreference v0.19.2/go.mod h1:jMjeRr2HHw6nAVajTXJ4eiUwohSTlpa0o73RUL1owJc=
-github.com/go-openapi/jsonreference v0.19.3 h1:5cxNfTy0UVC3X8JL5ymxzyoUZmo8iZb+jeTWn7tUa8o=
+github.com/go-openapi/jsonpointer v0.19.5 h1:gZr+CIYByUqjcgeLXnQu2gHYQC9o73G2XUeOFYEICuY=
+github.com/go-openapi/jsonpointer v0.19.5/go.mod h1:Pl9vOtqEWErmShwVjC8pYs9cog34VGT37dQOVbmoatg=
 github.com/go-openapi/jsonreference v0.19.3/go.mod h1:rjx6GuL8TTa9VaixXglHmQmIL98+wF9xc8zWvFonSJ8=
-github.com/go-openapi/loads v0.17.0/go.mod h1:72tmFy5wsWx89uEVddd0RjRWPZm92WRLhf7AC+0+OOU=
-github.com/go-openapi/loads v0.17.2/go.mod h1:72tmFy5wsWx89uEVddd0RjRWPZm92WRLhf7AC+0+OOU=
-github.com/go-openapi/loads v0.18.0/go.mod h1:72tmFy5wsWx89uEVddd0RjRWPZm92WRLhf7AC+0+OOU=
-github.com/go-openapi/loads v0.19.0/go.mod h1:72tmFy5wsWx89uEVddd0RjRWPZm92WRLhf7AC+0+OOU=
-github.com/go-openapi/loads v0.19.2/go.mod h1:QAskZPMX5V0C2gvfkGZzJlINuP7Hx/4+ix5jWFxsNPs=
-github.com/go-openapi/loads v0.19.4/go.mod h1:zZVHonKd8DXyxyw4yfnVjPzBjIQcLt0CCsn0N0ZrQsk=
-github.com/go-openapi/runtime v0.0.0-20180920151709-4f900dc2ade9/go.mod h1:6v9a6LTXWQCdL8k1AO3cvqx5OtZY/Y9wKTgaoP6YRfA=
-github.com/go-openapi/runtime v0.18.0/go.mod h1:uI6pHuxWYTy94zZxgcwJkUWa9wbIlhteGfloI10GD4U=
-github.com/go-openapi/runtime v0.19.0/go.mod h1:OwNfisksmmaZse4+gpV3Ne9AyMOlP1lt4sK4FXt0O64=
-github.com/go-openapi/runtime v0.19.4/go.mod h1:X277bwSUBxVlCYR3r7xgZZGKVvBd/29gLDlFGtJ8NL4=
-github.com/go-openapi/spec v0.0.0-20160808142527-6aced65f8501/go.mod h1:J8+jY1nAiCcj+friV/PDoE1/3eeccG9LYBs0tYvLOWc=
-github.com/go-openapi/spec v0.17.0/go.mod h1:XkF/MOi14NmjsfZ8VtAKf8pIlbZzyoTvZsdfssdxcBI=
-github.com/go-openapi/spec v0.17.2/go.mod h1:XkF/MOi14NmjsfZ8VtAKf8pIlbZzyoTvZsdfssdxcBI=
-github.com/go-openapi/spec v0.18.0/go.mod h1:XkF/MOi14NmjsfZ8VtAKf8pIlbZzyoTvZsdfssdxcBI=
-github.com/go-openapi/spec v0.19.2/go.mod h1:sCxk3jxKgioEJikev4fgkNmwS+3kuYdJtcsZsD5zxMY=
-github.com/go-openapi/spec v0.19.3/go.mod h1:FpwSN1ksY1eteniUU7X0N/BgJ7a4WvBFVA8Lj9mJglo=
-github.com/go-openapi/spec v0.19.4 h1:ixzUSnHTd6hCemgtAJgluaTSGYpLNpJY4mA2DIkdOAo=
-github.com/go-openapi/spec v0.19.4/go.mod h1:FpwSN1ksY1eteniUU7X0N/BgJ7a4WvBFVA8Lj9mJglo=
-github.com/go-openapi/strfmt v0.17.0/go.mod h1:P82hnJI0CXkErkXi8IKjPbNBM6lV6+5pLP5l494TcyU=
-github.com/go-openapi/strfmt v0.17.2/go.mod h1:P82hnJI0CXkErkXi8IKjPbNBM6lV6+5pLP5l494TcyU=
-github.com/go-openapi/strfmt v0.18.0/go.mod h1:P82hnJI0CXkErkXi8IKjPbNBM6lV6+5pLP5l494TcyU=
-github.com/go-openapi/strfmt v0.19.0/go.mod h1:+uW+93UVvGGq2qGaZxdDeJqSAqBqBdl+ZPMF/cC8nDY=
-github.com/go-openapi/strfmt v0.19.2/go.mod h1:0yX7dbo8mKIvc3XSKp7MNfxw4JytCfCD6+bY1AVL9LU=
-github.com/go-openapi/strfmt v0.19.3/go.mod h1:0yX7dbo8mKIvc3XSKp7MNfxw4JytCfCD6+bY1AVL9LU=
-github.com/go-openapi/swag v0.0.0-20160704191624-1d0bd113de87/go.mod h1:DXUve3Dpr1UfpPtxFw+EFuQ41HhCWZfha5jSVRG7C7I=
-github.com/go-openapi/swag v0.17.0/go.mod h1:AByQ+nYG6gQg71GINrmuDXCPWdL640yX49/kXLo40Tg=
-github.com/go-openapi/swag v0.17.2/go.mod h1:AByQ+nYG6gQg71GINrmuDXCPWdL640yX49/kXLo40Tg=
-github.com/go-openapi/swag v0.18.0/go.mod h1:AByQ+nYG6gQg71GINrmuDXCPWdL640yX49/kXLo40Tg=
-github.com/go-openapi/swag v0.19.2/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh66Z9tfKk=
-github.com/go-openapi/swag v0.19.5 h1:lTz6Ys4CmqqCQmZPBlbQENR1/GucA2bzYTE12Pw4tFY=
+github.com/go-openapi/jsonreference v0.19.5 h1:1WJP/wi4OjB4iV8KVbH73rQaoialJrqv8gitZLxGLtM=
+github.com/go-openapi/jsonreference v0.19.5/go.mod h1:RdybgQwPxbL4UEjuAruzK1x3nE69AqPYEJeo/TWfEeg=
 github.com/go-openapi/swag v0.19.5/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh66Z9tfKk=
-github.com/go-openapi/validate v0.17.2/go.mod h1:Uh4HdOzKt19xGIGm1qHf/ofbX1YQ4Y+MYsct2VUrAJ4=
-github.com/go-openapi/validate v0.18.0/go.mod h1:Uh4HdOzKt19xGIGm1qHf/ofbX1YQ4Y+MYsct2VUrAJ4=
-github.com/go-openapi/validate v0.19.2/go.mod h1:1tRCw7m3jtI8eNWEEliiAqUIcBztB2KDnRCRMUi7GTA=
-github.com/go-openapi/validate v0.19.5/go.mod h1:8DJv2CVJQ6kGNpFW6eV9N3JviE1C85nY1c2z52x1Gk4=
-github.com/go-sql-driver/mysql v1.4.0/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w=
-github.com/go-sql-driver/mysql v1.4.1/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w=
+github.com/go-openapi/swag v0.19.14 h1:gm3vOOXfiuw5i9p5N9xJvfjvuofpyvLA9Wr6QfK5Fng=
+github.com/go-openapi/swag v0.19.14/go.mod h1:QYRuS/SOXUCsnplDa677K7+DxSOj6IPNl/eQntq43wQ=
 github.com/go-stack/stack v1.8.0 h1:5SgMzNM5HxrEjV0ww2lTmX6E2Izsfxas4+YHWRs3Lsk=
 github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY=
-github.com/gobuffalo/envy v1.6.5/go.mod h1:N+GkhhZ/93bGZc6ZKhJLP6+m+tCNPKwgSpH9kaifseQ=
-github.com/gobuffalo/envy v1.7.0/go.mod h1:n7DRkBerg/aorDM8kbduw5dN3oXGswK5liaSCx4T5NI=
-github.com/gobuffalo/envy v1.7.1/go.mod h1:FurDp9+EDPE4aIUS3ZLyD+7/9fpx7YRt/ukY6jIHf0w=
-github.com/gobuffalo/flect v0.1.5/go.mod h1:W3K3X9ksuZfir8f/LrfVtWmCDQFfayuylOJ7sz/Fj80=
-github.com/gobuffalo/flect v0.2.0/go.mod h1:W3K3X9ksuZfir8f/LrfVtWmCDQFfayuylOJ7sz/Fj80=
-github.com/gobuffalo/flect v0.2.1/go.mod h1:vmkQwuZYhN5Pc4ljYQZzP+1sq+NEkK+lh20jmEmX3jc=
-github.com/gobuffalo/logger v1.0.1/go.mod h1:2zbswyIUa45I+c+FLXuWl9zSWEiVuthsk8ze5s8JvPs=
-github.com/gobuffalo/packd v0.3.0/go.mod h1:zC7QkmNkYVGKPw4tHpBQ+ml7W/3tIebgeo1b36chA3Q=
-github.com/gobuffalo/packr/v2 v2.7.1/go.mod h1:qYEvAazPaVxy7Y7KR0W8qYEE+RymX74kETFqjFoFlOc=
-github.com/gobwas/glob v0.2.3/go.mod h1:d3Ez4x06l9bZtSvzIay5+Yzi0fmZzPgnTbPcKjJAkT8=
-github.com/gocql/gocql v0.0.0-20190301043612-f6df8288f9b4/go.mod h1:4Fw1eo5iaEhDUs8XyuhSVCVy52Jq3L+/3GJgYkwc+/0=
-github.com/godbus/dbus v0.0.0-20190422162347-ade71ed3457e/go.mod h1:bBOAhwG1umN6/6ZUMtDFBMQR8jRg9O75tm9K00oMsK4=
-github.com/godbus/dbus/v5 v5.0.3/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA=
-github.com/godror/godror v0.13.3/go.mod h1:2ouUT4kdhUBk7TAkHWD4SN0CdI0pgEQbo8FVHhbSKWg=
-github.com/gofrs/flock v0.8.0/go.mod h1:F1TvTiK9OcQqauNUHlbJvyl9Qa1QvF/gOUDKA14jxHU=
-github.com/gogo/googleapis v1.1.0/go.mod h1:gf4bu3Q80BeJ6H1S1vYPm8/ELATdvryBaNFGgqEef3s=
+github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0/go.mod h1:fyg7847qk6SyHyPtNmDHnmrv/HOrqktSC+C9fM+CJOE=
+github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA=
 github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=
-github.com/gogo/protobuf v1.2.0/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=
 github.com/gogo/protobuf v1.2.1/go.mod h1:hp+jE20tsWTFYpLwKvXlhS1hjn+gTNwPg2I6zVXpSg4=
-github.com/gogo/protobuf v1.2.2-0.20190730201129-28a6bbf47e48/go.mod h1:SlYgWuQ5SjCEi6WLHjHCa1yvBfUnHcTbrrZtXPKa29o=
-github.com/gogo/protobuf v1.3.1 h1:DqDEcV5aeaTmdFBePNpYsp3FlcVH/2ISVVM9Qf8PSls=
 github.com/gogo/protobuf v1.3.1/go.mod h1:SlYgWuQ5SjCEi6WLHjHCa1yvBfUnHcTbrrZtXPKa29o=
-github.com/golang-migrate/migrate/v4 v4.6.2/go.mod h1:JYi6reN3+Z734VZ0akNuyOJNcrg45ZL7LDBMW3WGJL0=
-github.com/golang-sql/civil v0.0.0-20190719163853-cb61b32ac6fe/go.mod h1:8vg3r2VgvsThLBIFL93Qb5yWzgyZWhEmBwUJWevAkK0=
+github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q=
+github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q=
 github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
+github.com/golang/glog v1.0.0/go.mod h1:EWib/APOK0SL3dFbYqvxE3UYd8E6s1ouQ7iEp/0LWV4=
 github.com/golang/groupcache v0.0.0-20160516000752-02826c3e7903/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
 github.com/golang/groupcache v0.0.0-20190129154638-5b532d6fd5ef/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
 github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
-github.com/golang/groupcache v0.0.0-20191027212112-611e8accdfc9/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
-github.com/golang/groupcache v0.0.0-20191227052852-215e87163ea7 h1:5ZkaAPbicIKTF2I64qf5Fh8Aa83Q/dnOafMYV0OMwjA=
 github.com/golang/groupcache v0.0.0-20191227052852-215e87163ea7/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
+github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
+github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da h1:oI5xCqsCo564l8iNU+DwB5epxmsaqB+rhGL0m5jtYqE=
+github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
 github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
 github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
-github.com/golang/mock v1.3.1 h1:qGJ6qTW+x6xX/my+8YUVl4WNpX9B7+/l2tRsHGZ7f2s=
 github.com/golang/mock v1.3.1/go.mod h1:sBzyDLLjw3U8JLTeZvSv8jJB+tU5PVekmnlKIyFUx0Y=
-github.com/golang/protobuf v0.0.0-20161109072736-4bd1920723d7/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
+github.com/golang/mock v1.4.0/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw=
+github.com/golang/mock v1.4.1/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw=
+github.com/golang/mock v1.4.3/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw=
+github.com/golang/mock v1.4.4/go.mod h1:l3mdAwkq5BuhzHwde/uurv3sEJeZMXNpwsxVWU71h+4=
+github.com/golang/mock v1.5.0/go.mod h1:CWnOUgYIOo4TcNZ0wHX3YZCqsaM1I1Jvs6v3mP3KVu8=
+github.com/golang/mock v1.6.0 h1:ErTB+efbowRARo13NNdxyJji2egdxLGQhRaY+DUumQc=
+github.com/golang/mock v1.6.0/go.mod h1:p6yTPP+5HYm5mzsMV8JkE6ZKdX+/wYM6Hr+LicevLPs=
+github.com/golang/protobuf v1.0.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
 github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
 github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
 github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
 github.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw=
+github.com/golang/protobuf v1.3.4/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw=
+github.com/golang/protobuf v1.3.5/go.mod h1:6O5/vntMXwX2lRkT1hjjk0nAC1IDOTvTlVgjlRvqsdk=
 github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8=
 github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA=
 github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs=
 github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w=
 github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0=
 github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QDs8UjoX8=
-github.com/golang/protobuf v1.4.2 h1:+Z5KGCizgyZCbGh1KZqA0fcLLkwbsjIzS4aV2v7wJX0=
 github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=
-github.com/golang/snappy v0.0.0-20170215233205-553a64147049/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
-github.com/golang/snappy v0.0.0-20180518054509-2e65f85255db/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
+github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=
+github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk=
+github.com/golang/protobuf v1.5.1/go.mod h1:DopwsBzvsk0Fs44TXzsVbJyPhcCPeIwnvohx4u74HPM=
+github.com/golang/protobuf v1.5.2 h1:ROPKBNFfQgOUMifHyP+KYbvpjbdoFNs+aK7DXlji0Tw=
+github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY=
 github.com/golang/snappy v0.0.1 h1:Qgr9rKW7uDUkrbSmQeiDsGa8SjGyCOGtuasMWwvp2P4=
 github.com/golang/snappy v0.0.1/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
-github.com/golangplus/bytes v0.0.0-20160111154220-45c989fe5450/go.mod h1:Bk6SMAONeMXrxql8uvOKuAZSu8aM5RUGv+1C6IJaEho=
-github.com/golangplus/fmt v0.0.0-20150411045040-2a5d6d7d2995/go.mod h1:lJgMEyOkYFkPcDKwRXegd+iM6E7matEszMG5HhwytU8=
 github.com/golangplus/testing v0.0.0-20180327235837-af21d9c3145e/go.mod h1:0AA//k/eakGydO4jKRoRL2j92ZKSzTgj9tclaCrvXHk=
 github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
-github.com/google/btree v1.0.0 h1:0udJVsspx3VBr5FwtLhQQtuAsVc79tTq0ocGIPAU6qo=
 github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
+github.com/google/btree v1.0.1 h1:gK4Kx5IaGY9CD5sPJ36FHiBJ6ZXl0kilRiiCj+jdYp4=
+github.com/google/btree v1.0.1/go.mod h1:xXMiIv4Fb/0kKde4SpL7qlzvu5cMJDRkFDxJfI9uaxA=
+github.com/google/cel-go v0.9.0/go.mod h1:U7ayypeSkw23szu4GaQTPJGx66c20mx8JklMSxrmI1w=
+github.com/google/cel-spec v0.6.0/go.mod h1:Nwjgxy5CbjlPrtCWjeDjUyKMl8w41YBYGjsyDdqk0xA=
 github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M=
 github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
 github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
-github.com/google/go-cmp v0.4.0 h1:xsAVV57WRhGj6kEIi8ReJzQlHHqcBYCElAvkovg3B/4=
 github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
-github.com/google/go-github v17.0.0+incompatible/go.mod h1:zLgOLi98H3fifZn+44m+umXrS52loVEgC2AApnigrVQ=
-github.com/google/go-querystring v1.0.0/go.mod h1:odCYkC5MyYFN7vkCjXpyrEuKhc/BUO6wN/zVPAxq5ck=
-github.com/google/gofuzz v0.0.0-20161122191042-44d81051d367/go.mod h1:HP5RmnzzSNb993RKQDq4+1A4ia9nllfqcQFTQJedwGI=
+github.com/google/go-cmp v0.4.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
+github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
+github.com/google/go-cmp v0.5.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
+github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
+github.com/google/go-cmp v0.5.3/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
+github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
+github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
+github.com/google/go-cmp v0.5.6 h1:BKbKCqvP6I+rmFHt06ZmyQtvB8xAkWdhFyr0ZUNZcxQ=
+github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
+github.com/google/go-github/v41 v41.0.0 h1:HseJrM2JFf2vfiZJ8anY2hqBjdfY1Vlj/K27ueww4gg=
+github.com/google/go-github/v41 v41.0.0/go.mod h1:XgmCA5H323A9rtgExdTcnDkcqp6S30AVACCBDOonIxg=
+github.com/google/go-querystring v1.1.0 h1:AnCroh3fv4ZBgVIf1Iwtovgjaw/GiKJo8M8yD/fhyJ8=
+github.com/google/go-querystring v1.1.0/go.mod h1:Kcdr2DB4koayq7X8pmAG4sNG59So17icRSOU623lUBU=
 github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
-github.com/google/gofuzz v1.1.0 h1:Hsa8mG0dQ46ij8Sl2AYJDUv1oA9/d6Vk+3LG99Oe02g=
 github.com/google/gofuzz v1.1.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
+github.com/google/gofuzz v1.2.0 h1:xRy4A+RhZaiKjJ1bPfwQ8sedCA+YS2YcCHW6ec7JMi0=
+github.com/google/gofuzz v1.2.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
 github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs=
+github.com/google/martian/v3 v3.0.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0=
+github.com/google/martian/v3 v3.1.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0=
 github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc=
 github.com/google/pprof v0.0.0-20190515194954-54271f7e092f/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc=
-github.com/google/pprof v0.0.0-20190723021845-34ac40c74b70/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc=
 github.com/google/pprof v0.0.0-20191218002539-d4f498aebedc/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=
+github.com/google/pprof v0.0.0-20200212024743-f11f1df84d12/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=
+github.com/google/pprof v0.0.0-20200229191704-1ebb73c60ed3/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=
+github.com/google/pprof v0.0.0-20200430221834-fc25d7d30c6d/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=
+github.com/google/pprof v0.0.0-20200708004538-1a94d8640e99/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=
+github.com/google/pprof v0.0.0-20201023163331-3e6fc7fc9c4c/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
+github.com/google/pprof v0.0.0-20201203190320-1bf35d6f28c2/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
+github.com/google/pprof v0.0.0-20210122040257-d980be63207e/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
+github.com/google/pprof v0.0.0-20210226084205-cbba55b83ad5/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
 github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI=
+github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510 h1:El6M4kTTCOh6aBiKaUGG7oYTSPP8MxqL4YI3kZKwcP4=
 github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510/go.mod h1:pupxD2MaaD3pAXIBCelhxNneeOaAeabZDe5s4K6zSpQ=
 github.com/google/uuid v1.0.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
-github.com/google/uuid v1.1.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
-github.com/google/uuid v1.1.1 h1:Gkbcsh/GbpXz7lPftLA3P6TYMwjCLYm83jiFQZF/3gY=
 github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
-github.com/googleapis/gax-go v2.0.2+incompatible/go.mod h1:SFVmujtThgffbyetf+mdk2eWhX2bMyUtNHzFKcPA9HY=
+github.com/google/uuid v1.1.2 h1:EVhdT+1Kseyi1/pUmXKaFxYsDNy9RQYkMWRH68J/W7Y=
+github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
 github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg=
 github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk=
-github.com/googleapis/gnostic v0.0.0-20170729233727-0c5108395e2d/go.mod h1:sJBsCZ4ayReDTBIg8b9dl28c5xFWyhBTVRp3pOg5EKY=
-github.com/googleapis/gnostic v0.3.1/go.mod h1:on+2t9HRStVgn95RSsFWFz+6Q0Snyqv1awfrALZdbtU=
-github.com/googleapis/gnostic v0.4.1 h1:DLJCy1n/vrD4HPjOvYcT8aYQXpPIzoRZONaYwyycI+I=
-github.com/googleapis/gnostic v0.4.1/go.mod h1:LRhVm6pbyptWbWbuZ38d1eyptfvIytN3ir6b65WBswg=
-github.com/gophercloud/gophercloud v0.2.0/go.mod h1:vxM41WHh5uqHVBMZHzuwNOHh8XEoIEcSTewFxm1c5g8=
-github.com/gophercloud/gophercloud v0.3.0/go.mod h1:vxM41WHh5uqHVBMZHzuwNOHh8XEoIEcSTewFxm1c5g8=
-github.com/gophercloud/gophercloud v0.6.0/go.mod h1:GICNByuaEBibcjmjvI7QvYJSZEbGkcYwAR7EZK2WMqM=
+github.com/googleapis/gnostic v0.5.1/go.mod h1:6U4PtQXGIEt/Z3h5MAT7FNofLnw9vXk2cUuW7uA/OeU=
+github.com/googleapis/gnostic v0.5.5 h1:9fHAtK0uDfpveeqqo1hkEZJcFvYXAiCN3UutL8F9xHw=
+github.com/googleapis/gnostic v0.5.5/go.mod h1:7+EbHbldMins07ALC74bsA81Ovc97DwqyJO1AENw9kA=
 github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY=
-github.com/gopherjs/gopherjs v0.0.0-20191106031601-ce3c9ade29de/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY=
-github.com/gorilla/context v1.1.1/go.mod h1:kBGZzfjB9CEq2AlWe17Uuf7NDRt0dE0s8S51q0aT7Yg=
 github.com/gorilla/handlers v0.0.0-20150720190736-60c7bfde3e33/go.mod h1:Qkdc/uu4tH4g6mTK6auzZ766c4CA0Ng8+o/OAirnOIQ=
-github.com/gorilla/mux v1.6.2/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs=
-github.com/gorilla/mux v1.7.1/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs=
 github.com/gorilla/mux v1.7.2/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs=
-github.com/gorilla/mux v1.7.3/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs=
+github.com/gorilla/mux v1.8.0/go.mod h1:DVbg23sWSpFRCP0SfiEN6jmj59UnW/n46BH5rLB71So=
 github.com/gorilla/websocket v0.0.0-20170926233335-4201258b820c/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ=
 github.com/gorilla/websocket v1.4.0/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ=
 github.com/gorilla/websocket v1.4.2 h1:+/TMaTYc4QFitKJxsQ7Yye35DkWvkdLcvGKqM+x0Ufc=
 github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
-github.com/gosuri/uitable v0.0.4/go.mod h1:tKR86bXuXPZazfOTG1FIzvjIdXzd0mo4Vtn16vt0PJo=
-github.com/gregjones/httpcache v0.0.0-20180305231024-9cad4c3443a7 h1:pdN6V1QBWetyv/0+wjACpqVH+eVULgEjkurDLq3goeM=
 github.com/gregjones/httpcache v0.0.0-20180305231024-9cad4c3443a7/go.mod h1:FecbI9+v66THATjSRHfNgh1IVFe/9kFxbXtjV0ctIMA=
+github.com/gregjones/httpcache v0.0.0-20190611155906-901d90724c79 h1:+ngKgrYPPJrOjhax5N+uePQ0Fh1Z7PheYoUI/0nzkPA=
+github.com/gregjones/httpcache v0.0.0-20190611155906-901d90724c79/go.mod h1:FecbI9+v66THATjSRHfNgh1IVFe/9kFxbXtjV0ctIMA=
 github.com/grpc-ecosystem/go-grpc-middleware v1.0.0/go.mod h1:FiyG127CGDf3tlThmgyCl78X/SZQqEOJBCDaAfeWzPs=
 github.com/grpc-ecosystem/go-grpc-middleware v1.0.1-0.20190118093823-f849b5445de4/go.mod h1:FiyG127CGDf3tlThmgyCl78X/SZQqEOJBCDaAfeWzPs=
-github.com/grpc-ecosystem/go-grpc-middleware v1.1.0 h1:THDBEeQ9xZ8JEaCLyLQqXMMdRqNr0QAUJTIkQAUtFjg=
-github.com/grpc-ecosystem/go-grpc-middleware v1.1.0/go.mod h1:f5nM7jw/oeRSadq3xCzHAvxcr8HZnzsqU6ILg/0NiiE=
+github.com/grpc-ecosystem/go-grpc-middleware v1.3.0 h1:+9834+KizmvFV7pXQGSXQTsaWhq2GjuNUt0aUU0YBYw=
+github.com/grpc-ecosystem/go-grpc-middleware v1.3.0/go.mod h1:z0ButlSOZa5vEBq9m2m2hlwIgKw+rp3sdCBRoJY+30Y=
 github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0 h1:Ovs26xHkKqVztRpIrF/92BcuyuQ/YW4NSIpoGtfXNho=
 github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0/go.mod h1:8NvIoxWQoOIhqOTXgfV/d3M/q6VIi02HzZEHgUlZvzk=
 github.com/grpc-ecosystem/grpc-gateway v1.9.0/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY=
-github.com/grpc-ecosystem/grpc-gateway v1.9.4/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY=
 github.com/grpc-ecosystem/grpc-gateway v1.9.5/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY=
-github.com/grpc-ecosystem/grpc-gateway v1.12.1 h1:zCy2xE9ablevUOrUZc3Dl72Dt+ya2FNAvC2yLYMHzi4=
-github.com/grpc-ecosystem/grpc-gateway v1.12.1/go.mod h1:8XEsbTttt/W+VvjtQhLACqCisSPWTxCZ7sBRjU6iH9c=
-github.com/grpc-ecosystem/grpc-health-probe v0.2.1-0.20181220223928-2bf0a5b182db/go.mod h1:uBKkC2RbarFsvS5jMJHpVhTLvGlGQj9JJwkaePE3FWI=
-github.com/hailocab/go-hostpool v0.0.0-20160125115350-e80d13ce29ed/go.mod h1:tMWxXQ9wFIaZeTI9F+hmhFiGpFmhOHzyShyFUhRm0H4=
+github.com/grpc-ecosystem/grpc-gateway v1.16.0 h1:gmcG1KaJ57LophUzW0Hy8NmPhnMZb4M0+kPpLofRdBo=
+github.com/grpc-ecosystem/grpc-gateway v1.16.0/go.mod h1:BDjrQk3hbvj6Nolgz8mAMFbcEtjT1g+wF4CSlocrBnw=
 github.com/hashicorp/consul/api v1.1.0/go.mod h1:VmuI/Lkw1nC05EYQWNKwWGbkg+FbDBtguAZLlVdkD9Q=
-github.com/hashicorp/consul/api v1.3.0/go.mod h1:MmDNSzIMUjNpY/mQ398R4bk2FnqQLoPndWW5VkKPlCE=
 github.com/hashicorp/consul/sdk v0.1.1/go.mod h1:VKf9jXwCTEY1QZP2MOLRhb5i/I/ssyNV1vwHyQBF0x8=
-github.com/hashicorp/consul/sdk v0.3.0/go.mod h1:VKf9jXwCTEY1QZP2MOLRhb5i/I/ssyNV1vwHyQBF0x8=
 github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4=
-github.com/hashicorp/go-cleanhttp v0.5.0/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80=
 github.com/hashicorp/go-cleanhttp v0.5.1/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80=
+github.com/hashicorp/go-hclog v0.9.2/go.mod h1:5CU+agLiy3J7N7QjHK5d05KxGsuXiQLrjA0H7acj2lQ=
 github.com/hashicorp/go-immutable-radix v1.0.0/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60=
-github.com/hashicorp/go-immutable-radix v1.1.0/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60=
 github.com/hashicorp/go-msgpack v0.5.3/go.mod h1:ahLV/dePpqEmjfWmKiqvPkv/twdG7iPBM1vqhUKIvfM=
-github.com/hashicorp/go-msgpack v0.5.5/go.mod h1:ahLV/dePpqEmjfWmKiqvPkv/twdG7iPBM1vqhUKIvfM=
 github.com/hashicorp/go-multierror v1.0.0/go.mod h1:dHtQlpGsu+cZNNAkkCN/P3hoUDHhCYQXV3UM06sGGrk=
-github.com/hashicorp/go-retryablehttp v0.5.3/go.mod h1:9B5zBasrRhHXnJnui7y6sL7es7NDiJgTc6Er0maI1Xs=
+github.com/hashicorp/go-multierror v1.1.1/go.mod h1:iw975J/qwKPdAO1clOe2L8331t/9/fmwbPZ6JB6eMoM=
+github.com/hashicorp/go-retryablehttp v0.6.8/go.mod h1:vAew36LZh98gCBJNLH42IQ1ER/9wtLZZ8meHqQvEYWY=
 github.com/hashicorp/go-rootcerts v1.0.0/go.mod h1:K6zTfqpRlCUIjkwsN4Z+hiSfzSTQa6eBIzfwKfwNnHU=
-github.com/hashicorp/go-rootcerts v1.0.1/go.mod h1:pqUvnprVnM5bf7AOirdbb01K4ccR319Vf4pU3K5EGc8=
 github.com/hashicorp/go-sockaddr v1.0.0/go.mod h1:7Xibr9yA9JjQq1JpNB2Vw7kxv8xerXegt+ozgdvDeDU=
-github.com/hashicorp/go-sockaddr v1.0.2/go.mod h1:rB4wwRAUzs07qva3c5SdrY/NEtAUjGlgmH/UkBUC97A=
 github.com/hashicorp/go-syslog v1.0.0/go.mod h1:qPfqrKkXGihmCqbJM2mZgkZGvKG1dFdvsLplgctolz4=
 github.com/hashicorp/go-uuid v1.0.0/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro=
 github.com/hashicorp/go-uuid v1.0.1/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro=
-github.com/hashicorp/go-version v1.1.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA=
-github.com/hashicorp/go-version v1.2.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA=
 github.com/hashicorp/go.net v0.0.1/go.mod h1:hjKkEWcCURg++eb33jQU7oqQcI9XDCnUzHA0oac0k90=
 github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
 github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
-github.com/hashicorp/golang-lru v0.5.3/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4=
-github.com/hashicorp/golang-lru v0.5.4 h1:YDjusn29QI/Das2iO9M0BHnIbxPeyuCHsjMW+lJfyTc=
-github.com/hashicorp/golang-lru v0.5.4/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4=
 github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ=
 github.com/hashicorp/logutils v1.0.0/go.mod h1:QIAnNjmIWmVIIkWDTG1z5v++HQmx9WQRO+LraFDTW64=
 github.com/hashicorp/mdns v1.0.0/go.mod h1:tL+uN++7HEJ6SQLQ2/p+z2pH24WQKWjBPkE0mNTz8vQ=
 github.com/hashicorp/memberlist v0.1.3/go.mod h1:ajVTdAv/9Im8oMAAj5G31PhhMCZJV2pPBoIllUwCN7I=
-github.com/hashicorp/memberlist v0.1.4/go.mod h1:ajVTdAv/9Im8oMAAj5G31PhhMCZJV2pPBoIllUwCN7I=
-github.com/hashicorp/memberlist v0.1.5/go.mod h1:ajVTdAv/9Im8oMAAj5G31PhhMCZJV2pPBoIllUwCN7I=
 github.com/hashicorp/serf v0.8.2/go.mod h1:6hOLApaqBFA1NXqRQAsxw9QxuDEvNxSQRwA/JwenrHc=
-github.com/hashicorp/serf v0.8.5/go.mod h1:UpNcs7fFbpKIyZaUuSW6EPiH+eZC7OuyFD+wc1oal+k=
-github.com/hpcloud/tail v1.0.0 h1:nfCOvKYfkgYP8hkirhJocXT2+zOD8yUNjXaWfTlyFKI=
 github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU=
-github.com/huandu/xstrings v1.3.1/go.mod h1:y5/lhBue+AyNmUVz9RLU9xbLR0o4KIIExikq4ovT0aE=
-github.com/hudl/fargo v1.3.0/go.mod h1:y3CKSmjA+wD2gak7sUSXTAoopbhU08POFhmITJgmKTg=
-github.com/iancoleman/strcase v0.0.0-20190422225806-e506e3ef7365/go.mod h1:SK73tn/9oHe+/Y0h39VT4UCxmurVJkR5NA7kMEAOgSE=
 github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc=
+github.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc=
 github.com/imdario/mergo v0.3.5/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJh5FfA=
-github.com/imdario/mergo v0.3.6/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJh5FfA=
-github.com/imdario/mergo v0.3.7/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJh5FfA=
-github.com/imdario/mergo v0.3.8/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJh5FfA=
-github.com/imdario/mergo v0.3.9/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJh5FfA=
-github.com/imdario/mergo v0.3.11 h1:3tnifQM4i+fbajXKBHXWEH+KvNHqojZ778UH75j3bGA=
-github.com/imdario/mergo v0.3.11/go.mod h1:jmQim1M+e3UYxmgPu/WyfjB3N3VflVyUjjjwH0dnCYA=
+github.com/imdario/mergo v0.3.12 h1:b6R2BslTbIEToALKP7LxUvijTsNI9TAe80pLWN2g/HU=
+github.com/imdario/mergo v0.3.12/go.mod h1:jmQim1M+e3UYxmgPu/WyfjB3N3VflVyUjjjwH0dnCYA=
 github.com/inconshreveable/mousetrap v1.0.0 h1:Z8tu5sraLXCXIcARxBp/8cbvlwVa7Z1NHg9XEKhtSvM=
 github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8=
-github.com/influxdata/influxdb v1.7.7/go.mod h1:qZna6X/4elxqT3yI9iZYdZrWWdeFOOprn86kgg4+IzY=
-github.com/influxdata/influxdb1-client v0.0.0-20191209144304-8bf82d3c094d/go.mod h1:qj24IKcXYK6Iy9ceXlo3Tc+vtHo9lIhSX5JddghvEPo=
-github.com/jackc/fake v0.0.0-20150926172116-812a484cc733/go.mod h1:WrMFNQdiFJ80sQsxDoMokWK1W5TQtxBFNpzWTD84ibQ=
-github.com/jackc/pgx v3.2.0+incompatible/go.mod h1:0ZGrqGqkRlliWnWB4zKnWtjbSWbGkVEFm4TeybAXq+I=
-github.com/jessevdk/go-flags v0.0.0-20180331124232-1c38ed7ad0cc/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI=
+github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99/go.mod h1:1lJo3i6rXxKeerYnT8Nvf0QmHCRC1n8sfWVwXF2Frvo=
 github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI=
+github.com/jessevdk/go-flags v1.5.0/go.mod h1:Fw0T6WPc1dYxT4mKEZRfG5kJhaTDP9pj1c2EWnYs/m4=
 github.com/jmespath/go-jmespath v0.0.0-20160202185014-0b12d6b521d8/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k=
 github.com/jmespath/go-jmespath v0.0.0-20160803190731-bd40a432e4c7/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k=
-github.com/jmespath/go-jmespath v0.0.0-20180206201540-c2b33e8439af/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k=
-github.com/jmoiron/sqlx v1.2.0/go.mod h1:1FEQNm3xlJgrMD+FBdI9+xvCksHtbpVBBw5dYhBSsks=
-github.com/joefitzgerald/rainbow-reporter v0.1.0/go.mod h1:481CNgqmVHQZzdIbN52CupLJyoVwB10FQ/IQlF1pdL8=
-github.com/joeshaw/multierror v0.0.0-20140124173710-69b34d4ec901/go.mod h1:Z86h9688Y0wesXCyonoVr47MasHilkuLMqGhRZ4Hpak=
-github.com/joho/godotenv v1.3.0/go.mod h1:7hK45KPybAkOC6peb+G5yklZfMxEjkZhHbwpqxOKXbg=
-github.com/jonboulle/clockwork v0.1.0 h1:VKV+ZcuP6l3yW9doeqz6ziZGgcynBVQO+obU0+0hcPo=
 github.com/jonboulle/clockwork v0.1.0/go.mod h1:Ii8DK3G1RaLaWxj9trq07+26W01tbo22gdxWY5EU2bo=
+github.com/jonboulle/clockwork v0.2.2 h1:UOGuzwb1PwsrDAObMuhUnj0p5ULPj8V/xJ7Kx9qUBdQ=
+github.com/jonboulle/clockwork v0.2.2/go.mod h1:Pkfl5aHPm1nk2H9h0bjmnJD/BcgbGXUBGnn1kMkgxc8=
+github.com/josharian/intern v1.0.0 h1:vlS4z54oSdjm0bgjRigI+G1HpF+tI+9rE5LLzOg8HmY=
+github.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFFd8Hwg//Y=
 github.com/jpillora/backoff v1.0.0/go.mod h1:J/6gKK9jxlEcS3zixgDgUAsiuZ7yrSoa/FX5e0EB2j4=
-github.com/json-iterator/go v0.0.0-20180612202835-f2b4162afba3/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU=
 github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU=
 github.com/json-iterator/go v1.1.7/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
-github.com/json-iterator/go v1.1.8/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
-github.com/json-iterator/go v1.1.9/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
-github.com/json-iterator/go v1.1.10 h1:Kz6Cvnvv2wGdaG/V8yMvfkmNiXq9Ya2KUv4rouJJr68=
 github.com/json-iterator/go v1.1.10/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
-github.com/jsonnet-bundler/jsonnet-bundler v0.3.1/go.mod h1:/by7P/OoohkI3q4CgSFqcoFsVY+IaNbzOVDknEsKDeU=
+github.com/json-iterator/go v1.1.11/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
+github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM=
+github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo=
 github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU=
 github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/XSXhF0NWZEnDohbsk=
 github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU=
 github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w=
 github.com/julienschmidt/httprouter v1.3.0/go.mod h1:JR6WtHb+2LUe8TCKY3cZOxFyyO8IZAc4RVcycCCAKdM=
-github.com/kardianos/osext v0.0.0-20190222173326-2bc1f35cddc0/go.mod h1:1NbS8ALrpOvjt0rHPNLyCIeMtbizbir8U//inJ+zuB8=
+github.com/k0kubun/colorstring v0.0.0-20150214042306-9440f1994b88/go.mod h1:3w7q1U84EfirKl04SVQ/s7nPm1ZPhiXd34z40TNz36k=
+github.com/k0kubun/pp v2.3.0+incompatible/go.mod h1:GWse8YhT0p8pT4ir3ZgBbfZild3tgzSScAn6HmfYukg=
+github.com/kevinburke/ssh_config v0.0.0-20201106050909-4977a11b4351/go.mod h1:CT57kijsi8u/K/BOFA39wgDQJ9CxiF4nAY/ojJ6r6mM=
 github.com/kisielk/errcheck v1.1.0/go.mod h1:EZBBE59ingxPouuu3KfxchcWSUPOHkagtvWXihfKN4Q=
 github.com/kisielk/errcheck v1.2.0/go.mod h1:/BMXB+zMLi60iA8Vv6Ksmxu/1UDYcXs4uQLJ+jE2L00=
+github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8=
 github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
+github.com/klauspost/compress v1.13.6 h1:P76CopJELS0TiO2mebmnzgWaajssP/EszplttgQxcgc=
+github.com/klauspost/compress v1.13.6/go.mod h1:/3/Vjq9QcHkK5uEr5lBEmyoZ1iFhe47etQ6QUkpK6sk=
 github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
-github.com/konsorten/go-windows-terminal-sequences v1.0.2/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
 github.com/konsorten/go-windows-terminal-sequences v1.0.3/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
+github.com/kr/fs v0.1.0/go.mod h1:FFnZGqtBN9Gxj7eW1uZ42v5BccTP0vu6NEaFoC2HwRg=
 github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc=
 github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
-github.com/kr/pretty v0.2.0 h1:s5hAObm+yFO5uHYt5dYjxi2rXrsnmRpJx4OYvIWUaQs=
 github.com/kr/pretty v0.2.0/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI=
+github.com/kr/pretty v0.2.1 h1:Fmg33tUaq4/8ym9TJN1x7sLJnHVwhP33CNkpYV/7rwI=
+github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI=
 github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
-github.com/kr/pty v1.1.5/go.mod h1:9r2w37qlBe7rQ6e1fg1S/9xpWHSnaqNdHD3WcMdbPDA=
-github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE=
 github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
-github.com/kshvakov/clickhouse v1.3.5/go.mod h1:DMzX7FxRymoNkVgizH0DWAL8Cur7wHLgx3MUnGwJqpE=
-github.com/kylelemons/godebug v0.0.0-20160406211939-eadb3ce320cb/go.mod h1:B69LEHPfb2qLo0BaaOLcbitczOKLWTsrBG9LczfCD4k=
-github.com/kylelemons/godebug v0.0.0-20170820004349-d65d576e9348/go.mod h1:B69LEHPfb2qLo0BaaOLcbitczOKLWTsrBG9LczfCD4k=
-github.com/lann/builder v0.0.0-20180802200727-47ae307949d0/go.mod h1:dXGbAdH5GtBTC4WfIxhKZfyBF/HBFgRZSWwZ9g/He9o=
-github.com/lann/ps v0.0.0-20150810152359-62de8c46ede0/go.mod h1:vmVJ0l/dxyfGW6FmdpVm2joNMFikkuWg0EoCKLGUMNw=
-github.com/leanovate/gopter v0.2.4/go.mod h1:gNcbPWNEWRe4lm+bycKqxUYoH5uoVje5SkOJ3uoLer8=
-github.com/lib/pq v1.0.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo=
-github.com/lib/pq v1.2.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo=
-github.com/lib/pq v1.9.0/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o=
+github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
+github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
+github.com/ktrysmt/go-bitbucket v0.9.34/go.mod h1:FWxy2UK7GlK5b0NSJGc5hPqnssVlkNnsChvyuOf/Xno=
 github.com/liggitt/tabwriter v0.0.0-20181228230101-89fcab3d43de h1:9TO3cAIGXtEhnIaL+V+BEER86oLrvS+kWobKpbJuye0=
 github.com/liggitt/tabwriter v0.0.0-20181228230101-89fcab3d43de/go.mod h1:zAbeS9B/r2mtpb6U+EI2rYA5OAXxsYw6wTamcNW+zcE=
-github.com/lightstep/lightstep-tracer-common/golang/gogo v0.0.0-20190605223551-bc2310a04743/go.mod h1:qklhhLq1aX+mtWk9cPHPzaBjWImj5ULL6C7HFJtXQMM=
-github.com/lightstep/lightstep-tracer-go v0.18.0/go.mod h1:jlF1pusYV4pidLvZ+XD0UBX0ZE6WURAspgAczcDHrL4=
-github.com/lightstep/lightstep-tracer-go v0.18.1/go.mod h1:jlF1pusYV4pidLvZ+XD0UBX0ZE6WURAspgAczcDHrL4=
 github.com/lithammer/dedent v1.1.0/go.mod h1:jrXYCQtgg0nJiN+StA2KgR7w6CiQNv9Fd/Z9BP0jIOc=
-github.com/lovoo/gcloud-opentracing v0.3.0/go.mod h1:ZFqk2y38kMDDikZPAK7ynTTGuyt17nSPdS3K5e+ZTBY=
-github.com/lyft/protoc-gen-validate v0.0.13/go.mod h1:XbGvPuh87YZc5TdIa2/I4pLk0QoUACkjt2znoq26NVQ=
 github.com/magiconair/properties v1.8.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ=
 github.com/magiconair/properties v1.8.1/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ=
-github.com/mailru/easyjson v0.0.0-20160728113105-d5b7844b561a/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc=
-github.com/mailru/easyjson v0.0.0-20180823135443-60711f1a8329/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc=
-github.com/mailru/easyjson v0.0.0-20190312143242-1de009706dbe/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc=
+github.com/magiconair/properties v1.8.5/go.mod h1:y3VJvCyxH9uVvJTWEGAELF3aiYNyPKd5NZ3oSwXrF60=
 github.com/mailru/easyjson v0.0.0-20190614124828-94de47d64c63/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc=
 github.com/mailru/easyjson v0.0.0-20190626092158-b2ccc519800e/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc=
-github.com/mailru/easyjson v0.7.0 h1:aizVhC/NAAcKWb+5QsU1iNOZb4Yws5UO2I+aIprQITM=
 github.com/mailru/easyjson v0.7.0/go.mod h1:KAzv3t3aY1NaHWoQz1+4F1ccyAH66Jk7yos7ldAVICs=
-github.com/markbates/inflect v1.0.4/go.mod h1:1fR9+pO2KHEO9ZRtto13gDwwZaAKstQzferVeWqbgNs=
+github.com/mailru/easyjson v0.7.6 h1:8yTIVnZgCoiM1TgqoeTl+LfU5Jg6/xL3QhGQnimLYnA=
+github.com/mailru/easyjson v0.7.6/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc=
 github.com/marstr/guid v1.1.0/go.mod h1:74gB1z2wpxxInTG6yaqA7KrtM0NZ+RbrcqDvYHefzho=
+github.com/matryer/is v1.2.0/go.mod h1:2fLPjFQM9rhQ15aVEtbuwhJinnOqrmgXPNdZsdwlWXA=
 github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU=
-github.com/mattn/go-colorable v0.1.2/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE=
-github.com/mattn/go-ieproxy v0.0.0-20190610004146-91bb50d98149/go.mod h1:31jz6HNzdxOmlERGGEc4v/dMssOfmp2p5bT/okiKFFc=
-github.com/mattn/go-ieproxy v0.0.0-20190702010315-6dee0af9227d/go.mod h1:31jz6HNzdxOmlERGGEc4v/dMssOfmp2p5bT/okiKFFc=
-github.com/mattn/go-ieproxy v0.0.0-20191113090002-7c0f6868bffe/go.mod h1:pYabZ6IHcRpFh7vIaLfK7rdcWgFEb3SFJ6/gNWuh88E=
 github.com/mattn/go-isatty v0.0.3/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4=
 github.com/mattn/go-isatty v0.0.4/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4=
-github.com/mattn/go-isatty v0.0.6/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s=
-github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s=
-github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU=
-github.com/mattn/go-oci8 v0.0.7/go.mod h1:wjDx6Xm9q7dFtHJvIlrI99JytznLw5wQ4R+9mNXJwGI=
 github.com/mattn/go-runewidth v0.0.2/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU=
-github.com/mattn/go-runewidth v0.0.4/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU=
-github.com/mattn/go-runewidth v0.0.6/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI=
-github.com/mattn/go-shellwords v1.0.10/go.mod h1:EZzvwXDESEeg03EKmM+RmDnNOPKG4lLtQsUlTZDWQ8Y=
-github.com/mattn/go-sqlite3 v1.9.0/go.mod h1:FPy6KqzDD04eiIsT53CuJW3U88zkxoIYsOqkbpncsNc=
-github.com/mattn/go-sqlite3 v1.10.0/go.mod h1:FPy6KqzDD04eiIsT53CuJW3U88zkxoIYsOqkbpncsNc=
-github.com/mattn/go-sqlite3 v1.12.0/go.mod h1:FPy6KqzDD04eiIsT53CuJW3U88zkxoIYsOqkbpncsNc=
+github.com/mattn/go-runewidth v0.0.7/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI=
 github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0=
 github.com/matttproud/golang_protobuf_extensions v1.0.2-0.20181231171920-c182affec369 h1:I0XW9+e1XWDxdcEniV4rQAIOPUGDq67JSCiRCgGCZLI=
 github.com/matttproud/golang_protobuf_extensions v1.0.2-0.20181231171920-c182affec369/go.mod h1:BSXmuO+STAnVfrANrmjBb36TMTDstsz7MSK+HVaYKv4=
-github.com/maxbrunsfeld/counterfeiter/v6 v6.2.2/go.mod h1:eD9eIE7cdwcMi9rYluz88Jz2VyhSmden33/aXg4oVIY=
 github.com/miekg/dns v1.0.14/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg=
-github.com/miekg/dns v1.1.15/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg=
-github.com/miekg/dns v1.1.22/go.mod h1:bPDLeHnStXmXAq1m/Ch/hvfNHr14JKNPMBo3VZKjuso=
-github.com/mikefarah/yaml/v2 v2.4.0/go.mod h1:ahVqZF4n1W4NqwvVnZzC4es67xsW9uR/RRf2RRxieJU=
-github.com/mikefarah/yq/v2 v2.4.1/go.mod h1:i8SYf1XdgUvY2OFwSqGAtWOOgimD2McJ6iutoxRm4k0=
-github.com/minio/minio-go/v6 v6.0.49/go.mod h1:qD0lajrGW49lKZLtXKtCB4X/qkMf0a5tBvN2PaZg7Gg=
-github.com/minio/sha256-simd v0.1.1/go.mod h1:B5e1o+1/KgNmWrSQK08Y6Z1Vb5pwIktudl0J58iy0KM=
 github.com/mitchellh/cli v1.0.0/go.mod h1:hNIlj7HEI86fIcpObd7a0FcrxTWetlwJDGcceTlRvqc=
-github.com/mitchellh/copystructure v1.0.0/go.mod h1:SNtv71yrdKgLRyLFxmLdkAbkKEFWgYaq1OVrnRcwhnw=
 github.com/mitchellh/go-homedir v1.0.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0=
 github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0=
 github.com/mitchellh/go-testing-interface v1.0.0/go.mod h1:kRemZodwjscx+RGhAo8eIhFbs2+BFgRtFPeD/KE+zxI=
+github.com/mitchellh/go-wordwrap v1.0.0 h1:6GlHJ/LTGMrIJbwgdqdl2eEH8o+Exx/0m8ir9Gns0u4=
 github.com/mitchellh/go-wordwrap v1.0.0/go.mod h1:ZXFpozHsX6DPmq2I0TCekCxypsnAUbP2oI0UX1GXzOo=
 github.com/mitchellh/gox v0.4.0/go.mod h1:Sd9lOJ0+aimLBi73mGofS1ycjY8lL3uZM3JPS42BGNg=
-github.com/mitchellh/hashstructure v0.0.0-20170609045927-2bca23e0e452/go.mod h1:QjSHrPWS+BGUVBYkbTZWEnOh3G1DutKwClXU/ABz6AQ=
 github.com/mitchellh/iochan v1.0.0/go.mod h1:JwYml1nuB7xOzsp52dPpHFffvOCDupsG0QubkSMEySY=
 github.com/mitchellh/mapstructure v0.0.0-20160808181253-ca63d7c062ee/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y=
+github.com/mitchellh/mapstructure v0.0.0-20180220230111-00c29f56e238/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y=
 github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y=
+github.com/mitchellh/mapstructure v1.4.1/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo=
 github.com/mitchellh/osext v0.0.0-20151018003038-5e2d6d41470f/go.mod h1:OkQIRizQZAeMln+1tSwduZz7+Af5oFlKirV/MSYes2A=
-github.com/mitchellh/reflectwalk v1.0.0/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw=
-github.com/moby/moby v17.12.0-ce-rc1.0.20200618181300-9dc6525e6118+incompatible/go.mod h1:fDXVQ6+S340veQPv35CzDahGBmHsiclFwfEygB/TWMc=
-github.com/moby/term v0.0.0-20200312100748-672ec06f55cd/go.mod h1:DdlQx2hp0Ss5/fLikoLlEeIYiATotOjgB//nb973jeo=
+github.com/moby/spdystream v0.2.0 h1:cjW1zVyyoiM0T7b6UoySUFqzXMoqRckQtXwGPiBhOM8=
+github.com/moby/spdystream v0.2.0/go.mod h1:f7i0iNDQJ059oMTcWxx8MA/zKFIuD/lY+0GqbN2Wy8c=
+github.com/moby/term v0.0.0-20210610120745-9d4ed1856297 h1:yH0SvLzcbZxcJXho2yh7CqdENGMQe73Cw3woZBpPli0=
+github.com/moby/term v0.0.0-20210610120745-9d4ed1856297/go.mod h1:vgPCkQMyxTZ7IDy8SXRufE172gr8+K/JE/7hHFxHW3A=
 github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
 github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg=
 github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
-github.com/modern-go/reflect2 v0.0.0-20180320133207-05fbef0ca5da/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
 github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
-github.com/modern-go/reflect2 v1.0.1 h1:9f412s+6RmYXLWZSEzVVgPGK7C2PphHj5RJrvfx9AWI=
 github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
-github.com/morikuni/aec v0.0.0-20170113033406-39771216ff4c/go.mod h1:BbKIizmSmc5MMPqRYbxO4ZU0S0+P200+tUnFx7PXmsc=
-github.com/morikuni/aec v1.0.0/go.mod h1:BbKIizmSmc5MMPqRYbxO4ZU0S0+P200+tUnFx7PXmsc=
-github.com/mozillazg/go-cos v0.13.0/go.mod h1:Zp6DvvXn0RUOXGJ2chmWt2bLEqRAnJnS3DnAZsJsoaE=
-github.com/mozillazg/go-httpheader v0.2.1/go.mod h1:jJ8xECTlalr6ValeXYdOF8fFUISeBAdw6E61aqQma60=
+github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M=
+github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk=
+github.com/monochromegane/go-gitignore v0.0.0-20200626010858-205db1a8cc00 h1:n6/2gBQ3RWajuToeY6ZtZTIKv2v7ThUy5KKusIT0yc0=
+github.com/monochromegane/go-gitignore v0.0.0-20200626010858-205db1a8cc00/go.mod h1:Pm3mSP3c5uWn86xMLZ5Sa7JB9GsEZySvHYXCTK4E9q4=
+github.com/montanaflynn/stats v0.0.0-20171201202039-1bf9dbcd8cbe/go.mod h1:wL8QJuTMNUDYhXwkmfOly8iTdp5TEcJFWZD2D7SIkUc=
 github.com/munnerz/goautoneg v0.0.0-20120707110453-a547fc61f48d/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ=
 github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ=
 github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U=
 github.com/mwitkow/go-conntrack v0.0.0-20190716064945-2f068394615f/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U=
 github.com/mxk/go-flowrate v0.0.0-20140419014527-cca7078d478f/go.mod h1:ZdcZmHo+o7JKHSa8/e818NopupXU1YMK5fe1lsApnBw=
-github.com/nakagami/firebirdsql v0.0.0-20190310045651-3c02a58cfed8/go.mod h1:86wM1zFnC6/uDBfZGNwB65O+pR2OFi5q/YQaEUid1qA=
-github.com/nats-io/jwt v0.3.0/go.mod h1:fRYCDE99xlTsqUzISS1Bi75UBJ6ljOJQOAAu5VglpSg=
-github.com/nats-io/jwt v0.3.2/go.mod h1:/euKqTS1ZD+zzjYrY7pseZrTtWQSjujC7xjPc8wL6eU=
-github.com/nats-io/nats-server/v2 v2.1.2/go.mod h1:Afk+wRZqkMQs/p45uXdrVLuab3gwv3Z8C4HTBu8GD/k=
-github.com/nats-io/nats.go v1.9.1/go.mod h1:ZjDU1L/7fJ09jvUSRVBR2e7+RnLiiIQyqyzEE/Zbp4w=
-github.com/nats-io/nkeys v0.1.0/go.mod h1:xpnFELMwJABBLVhffcfd1MZx6VsNRFpEugbxziKVo7w=
-github.com/nats-io/nkeys v0.1.3/go.mod h1:xpnFELMwJABBLVhffcfd1MZx6VsNRFpEugbxziKVo7w=
-github.com/nats-io/nuid v1.0.1/go.mod h1:19wcPz3Ph3q0Jbyiqsd0kePYG7A95tJPxeL+1OSON2c=
 github.com/ncw/swift v1.0.47/go.mod h1:23YIA4yWVnGwv2dQlN4bB7egfYX6YLn0Yo/S6zZO/ZM=
-github.com/oklog/oklog v0.3.2/go.mod h1:FCV+B7mhrz4o+ueLpx+KqkyXRGMWOYEvfiXtdGtbWGs=
-github.com/oklog/run v1.0.0/go.mod h1:dlhp/R75TPv97u0XWUtDeV/lRKWPKSdTuV0TZvrmrQA=
-github.com/oklog/ulid v0.0.0-20170117200651-66bb6560562f/go.mod h1:CirwcVhetQ6Lv90oh/F+FBtV6XMibvdAFo93nm5qn4U=
+github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno=
+github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A=
+github.com/nxadm/tail v1.4.8 h1:nPr65rt6Y5JFSKQO7qToXr7pePgD6Gwiw05lkbyAQTE=
+github.com/nxadm/tail v1.4.8/go.mod h1:+ncqLTQzXmGhMZNUePPaPqPvBxHAIsmXswZKocGu+AU=
 github.com/oklog/ulid v1.3.1/go.mod h1:CirwcVhetQ6Lv90oh/F+FBtV6XMibvdAFo93nm5qn4U=
 github.com/olekukonko/tablewriter v0.0.0-20170122224234-a0225b3f23b5/go.mod h1:vsDQFd/mU46D+Z4whnwzcISnGGzXWMclvtLoiIKAKIo=
-github.com/olekukonko/tablewriter v0.0.1/go.mod h1:vsDQFd/mU46D+Z4whnwzcISnGGzXWMclvtLoiIKAKIo=
-github.com/olekukonko/tablewriter v0.0.2/go.mod h1:rSAaSIOAGT9odnlyGlUfAJaoc5w2fSBUmeGDbRWPxyQ=
+github.com/olekukonko/tablewriter v0.0.4/go.mod h1:zq6QwlOf5SlnkVbMSr5EoBv3636FWnp+qbPhuoO21uA=
 github.com/onsi/ginkgo v0.0.0-20170829012221-11459a886d9c/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
 github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
-github.com/onsi/ginkgo v1.7.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
-github.com/onsi/ginkgo v1.8.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
-github.com/onsi/ginkgo v1.10.1/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
-github.com/onsi/ginkgo v1.10.3/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
-github.com/onsi/ginkgo v1.11.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
-github.com/onsi/ginkgo v1.12.0 h1:Iw5WCbBcaAAd0fpRb1c9r5YCylv4XDoCSigm1zLevwU=
-github.com/onsi/ginkgo v1.12.0/go.mod h1:oUhWkIvk5aDxtKvDDuw8gItl8pKl42LzjC9KZE0HfGg=
+github.com/onsi/ginkgo v1.12.1/go.mod h1:zj2OWP4+oCPe1qIXoGWkgMRwljMUYCdkwsT2108oapk=
+github.com/onsi/ginkgo v1.14.0/go.mod h1:iSB4RoI2tjJc9BBv4NKIKWKya62Rps+oPG/Lv9klQyY=
+github.com/onsi/ginkgo v1.16.4/go.mod h1:dX+/inL/fNMqNlz0e9LfyB9TswhZpCVdJM/Z6Vvnwo0=
+github.com/onsi/ginkgo v1.16.5 h1:8xi0RTUf59SOSfEtZMvwTvXYMzG4gV23XVHOZiXNtnE=
+github.com/onsi/ginkgo v1.16.5/go.mod h1:+E8gABHa3K6zRBolWtd+ROzc/U5bkGt0FwiG042wbpU=
 github.com/onsi/gomega v0.0.0-20170829124025-dcabb60a477c/go.mod h1:C1qb7wdrVGGVU+Z6iS04AVkA3Q65CEZX59MT0QO5uiA=
-github.com/onsi/gomega v1.4.3/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY=
-github.com/onsi/gomega v1.5.0/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY=
-github.com/onsi/gomega v1.7.0/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY=
 github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY=
-github.com/onsi/gomega v1.8.1/go.mod h1:Ho0h+IUsWyvy1OpqCwxlQ/21gkhVunqlU8fDGcoTdcA=
-github.com/onsi/gomega v1.9.0 h1:R1uwffexN6Pr340GtYRIdZmAiN4J+iw6WG4wog1DUXg=
-github.com/onsi/gomega v1.9.0/go.mod h1:Ho0h+IUsWyvy1OpqCwxlQ/21gkhVunqlU8fDGcoTdcA=
-github.com/op/go-logging v0.0.0-20160315200505-970db520ece7/go.mod h1:HzydrMdWErDVzsI23lYNej1Htcns9BCg93Dk0bBINWk=
+github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo=
+github.com/onsi/gomega v1.17.0 h1:9Luw4uT5HTjHTN8+aNcSThgH1vdXnmdJ8xIfZ4wyTRE=
+github.com/onsi/gomega v1.17.0/go.mod h1:HnhC7FXeEQY45zxNK3PPoIUhzk/80Xly9PcubAlGdZY=
 github.com/opencontainers/go-digest v0.0.0-20170106003457-a6d0ee40d420/go.mod h1:cMLVZDEM3+U2I4VmLI6N8jQYUd2OVphdqWwCJHrFt2s=
-github.com/opencontainers/go-digest v0.0.0-20180430190053-c9281466c8b2/go.mod h1:cMLVZDEM3+U2I4VmLI6N8jQYUd2OVphdqWwCJHrFt2s=
-github.com/opencontainers/go-digest v1.0.0-rc1/go.mod h1:cMLVZDEM3+U2I4VmLI6N8jQYUd2OVphdqWwCJHrFt2s=
 github.com/opencontainers/go-digest v1.0.0/go.mod h1:0JzlMkj0TRzQZfJkVvzbP0HBR3IKzErnv2BNG4W4MAM=
 github.com/opencontainers/image-spec v1.0.0/go.mod h1:BtxoFyWECRxE4U/7sNtV5W15zMzWCbyJoFRP3s7yZA0=
-github.com/opencontainers/image-spec v1.0.1/go.mod h1:BtxoFyWECRxE4U/7sNtV5W15zMzWCbyJoFRP3s7yZA0=
-github.com/opencontainers/image-spec v1.0.2-0.20190823105129-775207bd45b6/go.mod h1:BtxoFyWECRxE4U/7sNtV5W15zMzWCbyJoFRP3s7yZA0=
-github.com/opencontainers/runc v0.0.0-20190115041553-12f6a991201f/go.mod h1:qT5XzbpPznkRYVz/mWwUaVBUv2rmF59PVA73FjuZG0U=
-github.com/opencontainers/runc v0.1.1/go.mod h1:qT5XzbpPznkRYVz/mWwUaVBUv2rmF59PVA73FjuZG0U=
-github.com/opencontainers/runtime-spec v0.1.2-0.20190507144316-5b71a03e2700/go.mod h1:jwyrGlmzljRJv/Fgzds9SsS/C5hL+LL3ko9hs6T5lQ0=
-github.com/opencontainers/runtime-spec v1.0.2/go.mod h1:jwyrGlmzljRJv/Fgzds9SsS/C5hL+LL3ko9hs6T5lQ0=
-github.com/openshift/origin v0.0.0-20160503220234-8f127d736703/go.mod h1:0Rox5r9C8aQn6j1oAOQ0c1uC86mYbUFObzjBRvUKHII=
-github.com/openshift/prom-label-proxy v0.1.1-0.20191016113035-b8153a7f39f1/go.mod h1:p5MuxzsYP1JPsNGwtjtcgRHHlGziCJJfztff91nNixw=
-github.com/opentracing-contrib/go-observer v0.0.0-20170622124052-a52f23424492/go.mod h1:Ngi6UdF0k5OKD5t5wlmGhe/EDKPoUM3BXZSSfIuJbis=
-github.com/opentracing-contrib/go-stdlib v0.0.0-20190519235532-cf7a6c988dc9/go.mod h1:PLldrQSroqzH70Xl+1DQcGnefIbqsKR7UDaiux3zV+w=
-github.com/opentracing/basictracer-go v1.0.0/go.mod h1:QfBfYuafItcjQuMwinw9GhYKwFXS9KnPs5lxoYwgW74=
-github.com/opentracing/opentracing-go v1.0.2/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o=
 github.com/opentracing/opentracing-go v1.1.0/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o=
-github.com/openzipkin-contrib/zipkin-go-opentracing v0.4.5/go.mod h1:/wsWhb9smxSfWAKL3wpBW7V8scJMt8N8gnaMCS9E/cA=
-github.com/openzipkin/zipkin-go v0.1.6/go.mod h1:QgAqvLzwWbR/WpD4A3cGpPtJrZXNIiJc5AZX7/PBEpw=
-github.com/openzipkin/zipkin-go v0.2.1/go.mod h1:NaW6tEwdmWMaCDZzg8sh+IBNOxHMPnhQw8ySjnjRyN4=
-github.com/openzipkin/zipkin-go v0.2.2/go.mod h1:NaW6tEwdmWMaCDZzg8sh+IBNOxHMPnhQw8ySjnjRyN4=
-github.com/operator-framework/api v0.3.7-0.20200602203552-431198de9fc2/go.mod h1:Xbje9x0SHmh0nihE21kpesB38vk3cyxnE6JdDS8Jo1Q=
-github.com/operator-framework/api v0.3.8/go.mod h1:Xbje9x0SHmh0nihE21kpesB38vk3cyxnE6JdDS8Jo1Q=
-github.com/operator-framework/operator-registry v1.12.6-0.20200611222234-275301b779f8/go.mod h1:loVINznYhgBIkmv83kU4yee88RS0BBk+hqOw9r4bhJk=
-github.com/operator-framework/operator-sdk v0.19.0/go.mod h1:8MR6CguLizat2RGjdSMifGwW6mEMwKqAtZnSUHJ6SxU=
-github.com/otiai10/copy v1.2.0/go.mod h1:rrF5dJ5F0t/EWSYODDu4j9/vEeYHMkc8jt0zJChqQWw=
-github.com/otiai10/curr v0.0.0-20150429015615-9b4961190c95/go.mod h1:9qAhocn7zKJG+0mI8eUu6xqkFDYS2kb2saOteoSB3cE=
-github.com/otiai10/curr v1.0.0/go.mod h1:LskTG5wDwr8Rs+nNQ+1LlxRjAtTZZjtJW4rMXl6j4vs=
-github.com/otiai10/mint v1.3.0/go.mod h1:F5AjcsTsWUqX+Na9fpHb52P8pcRX2CI6A3ctIT91xUo=
-github.com/otiai10/mint v1.3.1/go.mod h1:/yxELlJQ0ufhjUwhshSj+wFjZ78CnZ48/1wtmBH1OTc=
-github.com/pact-foundation/pact-go v1.0.4/go.mod h1:uExwJY4kCzNPcHRj+hCR/HBbOOIwwtUjcrb0b5/5kLM=
 github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc=
-github.com/pascaldekloe/goe v0.1.0/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc=
-github.com/pborman/uuid v1.2.0/go.mod h1:X/NO0urCmaxf9VXbdlT7C2Yzkj2IKimNn4k+gtPdI/k=
 github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic=
-github.com/performancecopilot/speed v3.0.0+incompatible/go.mod h1:/CLtqpZ5gBg1M9iaPbIdPPGyKcA8hKdoy6hAWba7Yac=
+github.com/pelletier/go-toml v1.9.3/go.mod h1:u1nR/EPcESfeI/szUZKdtJ0xRNbUoANCkoOuaOx1Y+c=
 github.com/peterbourgon/diskv v2.0.1+incompatible h1:UBdAOUP5p4RWqPBg048CAvpKN+vxiaj6gdUUzhl4XmI=
 github.com/peterbourgon/diskv v2.0.1+incompatible/go.mod h1:uqqh8zWWbv1HBMNONnaR/tNboyR3/BZd58JJSHlUSCU=
-github.com/phayes/freeport v0.0.0-20180830031419-95f893ade6f2/go.mod h1:iIss55rKnNBTvrwdmkUpLnDpZoAHvWaiq5+iMmen4AE=
-github.com/pierrec/lz4 v1.0.2-0.20190131084431-473cd7ce01a1/go.mod h1:3/3N9NVKO0jef7pBehbT1qWhCMrIgbYNnFAZCqQ5LRc=
-github.com/pierrec/lz4 v2.0.5+incompatible/go.mod h1:pdkljMzZIN41W+lC3N2tnIh5sFi+IEE17M5jbnwPHcY=
 github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
-github.com/pkg/errors v0.8.1-0.20171018195549-f15c970de5b7/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
 github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
 github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
 github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
-github.com/pkg/profile v1.2.1/go.mod h1:hJw3o1OdXxsrSjjVksARp5W95eeEaEfptyVZyv6JUPA=
-github.com/pmezard/go-difflib v0.0.0-20151028094244-d8ed2627bdf0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
+github.com/pkg/sftp v1.10.1/go.mod h1:lYOWFsE0bwd1+KfKJaKeuokY15vzFx25BLbzYYoAxZI=
 github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
 github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
 github.com/posener/complete v1.1.1/go.mod h1:em0nMJCgc9GFtwrmVmEMR/ZL6WyhyjMBndrE9hABlRI=
 github.com/pquerna/cachecontrol v0.0.0-20171018203845-0dec1b30a021/go.mod h1:prYjPmNq4d1NPVmpShWobRqXY3q7Vp+80DqgxxUrUIA=
-github.com/prometheus/alertmanager v0.18.0/go.mod h1:WcxHBl40VSPuOaqWae6l6HpnEOVRIycEJ7i9iYkadEE=
-github.com/prometheus/alertmanager v0.20.0/go.mod h1:9g2i48FAyZW6BtbsnvHtMHQXl2aVtrORKwKVCQ+nbrg=
 github.com/prometheus/client_golang v0.0.0-20180209125602-c332b6f63c06/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw=
 github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw=
-github.com/prometheus/client_golang v0.9.2/go.mod h1:OsXs2jCmiKlQ1lTBmv21f2mNfw4xf/QclQDMrYNZzcM=
-github.com/prometheus/client_golang v0.9.3-0.20190127221311-3c4408c8b829/go.mod h1:p2iRAGwDERtqlqzRXnrOVns+ignqQo//hLXqYxZYVNs=
 github.com/prometheus/client_golang v0.9.3/go.mod h1:/TN21ttK/J9q6uSwhBd54HahCDft0ttaMvbicHlPoso=
 github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo=
-github.com/prometheus/client_golang v1.1.0/go.mod h1:I1FGZT9+L76gKKOs5djB6ezCbFQP1xR9D75/vuwEF3g=
-github.com/prometheus/client_golang v1.2.0/go.mod h1:XMU6Z2MjaRKVu/dC1qupJI9SiNkDYzz3xecMgSW/F+U=
-github.com/prometheus/client_golang v1.2.1/go.mod h1:XMU6Z2MjaRKVu/dC1qupJI9SiNkDYzz3xecMgSW/F+U=
-github.com/prometheus/client_golang v1.3.0/go.mod h1:hJaj2vgQTGQmVCsAACORcieXFeDPbaTKGT+JTgUa3og=
-github.com/prometheus/client_golang v1.5.1/go.mod h1:e9GMxYsXl05ICDXkRhurwBS4Q3OK1iX/F2sw+iXX5zU=
-github.com/prometheus/client_golang v1.7.1 h1:NTGy1Ja9pByO+xAeH/qiWnLrKtr3hJPNjaVUwnjpdpA=
 github.com/prometheus/client_golang v1.7.1/go.mod h1:PY5Wy2awLA44sXw4AOSfFBetzPP4j5+D6mVACh+pe2M=
+github.com/prometheus/client_golang v1.11.0 h1:HNkLOAEQMIDv/K+04rukrLx6ch7msSRwf3/SASFAGtQ=
+github.com/prometheus/client_golang v1.11.0/go.mod h1:Z6t4BnS23TR94PD6BsDNk8yVqroYurpAkEiz0P2BEV0=
 github.com/prometheus/client_model v0.0.0-20171117100541-99fa1f4be8e5/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo=
 github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo=
-github.com/prometheus/client_model v0.0.0-20190115171406-56726106282f/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo=
 github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
 github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
-github.com/prometheus/client_model v0.1.0/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
 github.com/prometheus/client_model v0.2.0 h1:uq5h0d+GuxiXLJLNABMgp2qUWDPiLvgCzz2dUR+/W/M=
 github.com/prometheus/client_model v0.2.0/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
 github.com/prometheus/common v0.0.0-20180110214958-89604d197083/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro=
 github.com/prometheus/common v0.0.0-20181113130724-41aa239b4cce/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro=
-github.com/prometheus/common v0.0.0-20181126121408-4724e9255275/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro=
-github.com/prometheus/common v0.2.0/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4=
 github.com/prometheus/common v0.4.0/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4=
 github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4=
-github.com/prometheus/common v0.6.0/go.mod h1:eBmuwkDJBwy6iBfxCBob6t6dR6ENT/y+J+Zk0j9GMYc=
-github.com/prometheus/common v0.7.0/go.mod h1:DjGbpBbp5NYNiECxcL/VnbXCCaQpKd3tt26CguLLsqA=
-github.com/prometheus/common v0.9.1/go.mod h1:yhUN8i9wzaXS3w1O07YhxHEBxD+W35wd8bs7vj7HSQ4=
-github.com/prometheus/common v0.10.0 h1:RyRA7RzGXQZiW+tGMr7sxa85G1z0yOpM1qq5c8lNawc=
 github.com/prometheus/common v0.10.0/go.mod h1:Tlit/dnDKsSWFlCLTWaA1cyBgKHSMdTB80sz/V91rCo=
+github.com/prometheus/common v0.26.0/go.mod h1:M7rCNAaPfAosfx8veZJCuw84e35h3Cfd9VFqTh1DIvc=
+github.com/prometheus/common v0.28.0 h1:vGVfV9KrDTvWt5boZO0I19g2E3CsWfpPPKZM9dt3mEw=
+github.com/prometheus/common v0.28.0/go.mod h1:vu+V0TpY+O6vW9J44gczi3Ap/oXXR10b+M/gUGO4Hls=
 github.com/prometheus/procfs v0.0.0-20180125133057-cb4147076ac7/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk=
 github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk=
-github.com/prometheus/procfs v0.0.0-20181204211112-1dc9a6cbc91a/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk=
-github.com/prometheus/procfs v0.0.0-20190117184657-bf6a532e95b1/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk=
-github.com/prometheus/procfs v0.0.0-20190425082905-87a4384529e0/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA=
 github.com/prometheus/procfs v0.0.0-20190507164030-5867b95ac084/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA=
-github.com/prometheus/procfs v0.0.0-20190522114515-bc1a522cf7b1/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA=
 github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA=
-github.com/prometheus/procfs v0.0.3/go.mod h1:4A/X28fw3Fc593LaREMrKMqOKvUAntwMDaekg4FpcdQ=
-github.com/prometheus/procfs v0.0.5/go.mod h1:4A/X28fw3Fc593LaREMrKMqOKvUAntwMDaekg4FpcdQ=
-github.com/prometheus/procfs v0.0.6/go.mod h1:7Qr8sr6344vo1JqZ6HhLceV9o3AJ1Ff+GxbHq6oeK9A=
-github.com/prometheus/procfs v0.0.8/go.mod h1:7Qr8sr6344vo1JqZ6HhLceV9o3AJ1Ff+GxbHq6oeK9A=
-github.com/prometheus/procfs v0.0.11/go.mod h1:lV6e/gmhEcM9IjHGsFOCxxuZ+z1YqCvr4OA4YeYWdaU=
-github.com/prometheus/procfs v0.1.3 h1:F0+tqvhOksq22sc6iCHF5WGlWjdwj92p0udFh1VFBS8=
 github.com/prometheus/procfs v0.1.3/go.mod h1:lV6e/gmhEcM9IjHGsFOCxxuZ+z1YqCvr4OA4YeYWdaU=
-github.com/prometheus/prometheus v0.0.0-20180315085919-58e2a31db8de/go.mod h1:oAIUtOny2rjMX0OWN5vPR5/q/twIROJvdqnQKDdil/s=
-github.com/prometheus/prometheus v1.8.2-0.20200110114423-1e64d757f711/go.mod h1:7U90zPoLkWjEIQcy/rweQla82OCTUzxVHE51G3OhJbI=
-github.com/prometheus/prometheus v2.3.2+incompatible/go.mod h1:oAIUtOny2rjMX0OWN5vPR5/q/twIROJvdqnQKDdil/s=
+github.com/prometheus/procfs v0.6.0 h1:mxy4L2jP6qMonqmq+aTtOx1ifVWUgG/TAmntgbh3xv4=
+github.com/prometheus/procfs v0.6.0/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1xBZuNvfVA=
 github.com/prometheus/tsdb v0.7.1/go.mod h1:qhTCs0VvXwvX/y3TZrWD7rabWM+ijKTux40TwIPHuXU=
-github.com/rcrowley/go-metrics v0.0.0-20181016184325-3113b8401b8a/go.mod h1:bCqnVzQkZxMG4s8nGwiZ5l3QUCyqpo9Y+/ZMZ9VjZe4=
-github.com/robfig/cron v0.0.0-20170526150127-736158dc09e1/go.mod h1:JGuDeoQd7Z6yL4zQhZ3OPEVHB7fL6Ka6skscFHfmt2k=
 github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6SoW27p1b0cqNHllgS5HIMJraePCO15w5zCzIWYg=
 github.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ=
-github.com/rogpeppe/go-internal v1.1.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
 github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
-github.com/rogpeppe/go-internal v1.3.2/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTEfhy4qGm1nDQc=
-github.com/rogpeppe/go-internal v1.4.0/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTEfhy4qGm1nDQc=
-github.com/rogpeppe/go-internal v1.5.0/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTEfhy4qGm1nDQc=
-github.com/rs/cors v1.6.0/go.mod h1:gFx+x8UowdsKA9AchylcLynDq+nNFfI8FkUZdN/jGCU=
-github.com/rubenv/sql-migrate v0.0.0-20200616145509-8d140a17f351/go.mod h1:DCgfY80j8GYL7MLEfvcpSFvjD0L5yZq/aZUJmhZklyg=
+github.com/russross/blackfriday v1.5.2 h1:HyvC0ARfnZBqnXwABFeSZHpKvJHJJfPz81GNueLj0oo=
 github.com/russross/blackfriday v1.5.2/go.mod h1:JO/DiYxRf+HjHt06OyowR9PTA263kcR/rfWxYHBV53g=
 github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
 github.com/ryanuber/columnize v0.0.0-20160712163229-9b3edd62028f/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts=
-github.com/ryanuber/columnize v2.1.0+incompatible/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts=
-github.com/samuel/go-zookeeper v0.0.0-20190810000440-0ceca61e4d75/go.mod h1:gi+0XIa01GRL2eRQVjQkKGqKF3SF9vZR/HnPullcV2E=
-github.com/samuel/go-zookeeper v0.0.0-20190923202752-2cc03de413da/go.mod h1:gi+0XIa01GRL2eRQVjQkKGqKF3SF9vZR/HnPullcV2E=
-github.com/santhosh-tekuri/jsonschema v1.2.4/go.mod h1:TEAUOeZSmIxTTuHatJzrvARHiuO9LYd+cIxzgEHCQI4=
-github.com/satori/go.uuid v0.0.0-20160603004225-b111a074d5ef/go.mod h1:dA0hQrYB0VpLJoorglMZABFdXlWrHn1NEOzdhQKdks0=
 github.com/satori/go.uuid v1.2.0/go.mod h1:dA0hQrYB0VpLJoorglMZABFdXlWrHn1NEOzdhQKdks0=
-github.com/sclevine/spec v1.2.0/go.mod h1:W4J29eT/Kzv7/b9IWLB055Z+qvVC9vt0Arko24q7p+U=
 github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529/go.mod h1:DxrIzT+xaE7yg65j358z/aeFdxmN0P9QXhEzd20vsDc=
-github.com/sergi/go-diff v1.0.0/go.mod h1:0CfEIISq7TuYL3j771MWULgwwjU+GofnZX9QAmXWZgo=
-github.com/shopspring/decimal v0.0.0-20180709203117-cd690d0c9e24/go.mod h1:M+9NzErvs504Cn4c5DxATwIqPbtswREoFCre64PpcG4=
-github.com/shopspring/decimal v1.2.0/go.mod h1:DKyhrW/HYNuLGql+MJL6WCR6knT2jwCFRcu2hWCYk4o=
-github.com/shurcooL/httpfs v0.0.0-20171119174359-809beceb2371/go.mod h1:ZY1cvUeJuFPAdZ/B6v7RHavJWZn2YPVFQ1OSXhCGOkg=
-github.com/shurcooL/httpfs v0.0.0-20190707220628-8d4bc4ba7749/go.mod h1:ZY1cvUeJuFPAdZ/B6v7RHavJWZn2YPVFQ1OSXhCGOkg=
+github.com/sergi/go-diff v1.1.0 h1:we8PVUC3FE2uYfodKH/nBHMSetSfHDR6scGdBi+erh0=
+github.com/sergi/go-diff v1.1.0/go.mod h1:STckp+ISIX8hZLjrqAeVduY0gWCT9IjLuqbuNXdaHfM=
 github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc=
-github.com/shurcooL/vfsgen v0.0.0-20180825020608-02ddb050ef6b/go.mod h1:TrYk7fJVaAttu97ZZKrO9UbRa8izdowaMIZcxYMbVaw=
-github.com/shurcooL/vfsgen v0.0.0-20181202132449-6a9ea43bcacd/go.mod h1:TrYk7fJVaAttu97ZZKrO9UbRa8izdowaMIZcxYMbVaw=
-github.com/sirupsen/logrus v1.0.4-0.20170822132746-89742aefa4b2/go.mod h1:pMByvHTf9Beacp5x1UXfOR9xyW/9antXMhjMPG0dEzc=
 github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo=
 github.com/sirupsen/logrus v1.4.1/go.mod h1:ni0Sbl8bgC9z8RoU9G6nDWqqs/fq4eDPysMBDgk/93Q=
 github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE=
-github.com/sirupsen/logrus v1.5.0/go.mod h1:+F7Ogzej0PZc/94MaYx/nvG9jOFMD2osvC3s+Squfpo=
 github.com/sirupsen/logrus v1.6.0/go.mod h1:7uNnSEd1DgxDLC74fIahvMZmmYsHGZGEOFrfsX/uA88=
-github.com/sirupsen/logrus v1.7.0 h1:ShrD1U9pZB12TX0cVy0DtePoCH97K8EtX+mg7ZARUtM=
 github.com/sirupsen/logrus v1.7.0/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0=
+github.com/sirupsen/logrus v1.8.1 h1:dJKuHgqk1NNQlqoA6BTlM1Wf9DOH3NBjQyu0h9+AZZE=
+github.com/sirupsen/logrus v1.8.1/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0=
 github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc=
-github.com/smartystreets/assertions v1.0.1/go.mod h1:kHHU4qYBaI3q23Pp3VPrmWhuIUrLW/7eUrw0BU5VaoM=
 github.com/smartystreets/goconvey v0.0.0-20190330032615-68dc04aab96a/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA=
 github.com/smartystreets/goconvey v1.6.4/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA=
-github.com/soheilhy/cmux v0.1.4 h1:0HKaf1o97UwFjHH9o5XsHUOF+tqmdA7KEzXLpiyaw0E=
 github.com/soheilhy/cmux v0.1.4/go.mod h1:IM3LyeVVIOuxMH7sFAkER9+bJ4dT7Ms6E4xg4kGIyLM=
-github.com/sony/gobreaker v0.4.1/go.mod h1:ZKptC7FHNvhBz7dN2LGjPVBz2sZJmc0/PkyDJOjmxWY=
+github.com/soheilhy/cmux v0.1.5 h1:jjzc5WVemNEDTLwv9tlmemhC73tI08BNOIGwBOo10Js=
+github.com/soheilhy/cmux v0.1.5/go.mod h1:T7TcVDs9LWfQgPlPsdngu6I6QIoyIFZDDC6sNE1GqG0=
 github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA=
-github.com/spaolacci/murmur3 v1.1.0/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA=
 github.com/spf13/afero v1.1.2/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B0CQ=
 github.com/spf13/afero v1.2.2/go.mod h1:9ZxEEn6pIJ8Rxe320qSDBk6AsU0r9pR7Q4OcevTdifk=
+github.com/spf13/afero v1.6.0/go.mod h1:Ai8FlHk4v/PARR026UzYexafAt9roJ7LcLMAmO6Z93I=
 github.com/spf13/cast v1.3.0/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE=
 github.com/spf13/cast v1.3.1/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE=
-github.com/spf13/cobra v0.0.2-0.20171109065643-2da4a54c5cee/go.mod h1:1l0Ry5zgKvJasoi3XT1TypsSe7PqH0Sj9dhYf7v3XqQ=
 github.com/spf13/cobra v0.0.3/go.mod h1:1l0Ry5zgKvJasoi3XT1TypsSe7PqH0Sj9dhYf7v3XqQ=
-github.com/spf13/cobra v0.0.5/go.mod h1:3K3wKZymM7VvHMDS9+Akkh4K60UwM26emMESw8tLCHU=
-github.com/spf13/cobra v0.0.6/go.mod h1:/6GTrnGXV9HjY+aR4k0oJ5tcvakLuG6EuKReYlHNrgE=
-github.com/spf13/cobra v0.0.7/go.mod h1:/6GTrnGXV9HjY+aR4k0oJ5tcvakLuG6EuKReYlHNrgE=
 github.com/spf13/cobra v1.0.0/go.mod h1:/6GTrnGXV9HjY+aR4k0oJ5tcvakLuG6EuKReYlHNrgE=
-github.com/spf13/cobra v1.1.1 h1:KfztREH0tPxJJ+geloSLaAkaPkr4ki2Er5quFV1TDo4=
-github.com/spf13/cobra v1.1.1/go.mod h1:WnodtKOvamDL/PwE2M4iKs8aMDBZ5Q5klgD3qfVJQMI=
+github.com/spf13/cobra v1.1.3/go.mod h1:pGADOWyqRD/YMrPZigI/zbliZ2wVD/23d+is3pSWzOo=
+github.com/spf13/cobra v1.2.1 h1:+KmjbUw1hriSNMF55oPrkZcb27aECyrj8V2ytv7kWDw=
+github.com/spf13/cobra v1.2.1/go.mod h1:ExllRjgxM/piMAM+3tAZvg8fsklGAf3tPfi+i8t68Nk=
 github.com/spf13/jwalterweatherman v1.0.0/go.mod h1:cQK4TGJAtQXfYWX+Ddv3mKDzgVb68N+wFjFa4jdeBTo=
+github.com/spf13/jwalterweatherman v1.1.0/go.mod h1:aNWZUN0dPAAO/Ljvb5BEdw96iTZ0EXowPYD95IqWIGo=
 github.com/spf13/pflag v0.0.0-20170130214245-9ff6c6923cff/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4=
-github.com/spf13/pflag v1.0.1-0.20171106142849-4c012f6dcd95/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4=
 github.com/spf13/pflag v1.0.1/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4=
 github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4=
 github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA=
 github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
-github.com/spf13/viper v1.3.2/go.mod h1:ZiWeW+zYFKm7srdB9IoDzzZXaJaI5eL9QjNiN/DMA2s=
 github.com/spf13/viper v1.4.0/go.mod h1:PTJ7Z/lr49W6bUbkmS1V3by4uWynFiR9p7+dSq/yZzE=
 github.com/spf13/viper v1.7.0/go.mod h1:8WkrPz2fc9jxqZNCJI/76HCieCp4Q8HaLFoCha5qpdg=
-github.com/streadway/amqp v0.0.0-20190404075320-75d898a42a94/go.mod h1:AZpEONHx3DKn8O/DFsRAY58/XVQiIPMTMB1SddzLXVw=
-github.com/streadway/amqp v0.0.0-20190827072141-edfb9018d271/go.mod h1:AZpEONHx3DKn8O/DFsRAY58/XVQiIPMTMB1SddzLXVw=
-github.com/streadway/handy v0.0.0-20190108123426-d5acb3125c2a/go.mod h1:qNTQ5P5JnDBl6z3cMAg/SywNDC5ABu5ApDIw6lUbRmI=
+github.com/spf13/viper v1.8.1/go.mod h1:o0Pch8wJ9BVSWGQMbra6iw0oQ5oktSIBaujf1rJH9Ns=
+github.com/stoewer/go-strcase v1.2.0/go.mod h1:IBiWB2sKIp3wVVQ3Y035++gc+knqhUQag1KpM8ahLw8=
 github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
 github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
+github.com/stretchr/objx v0.2.0 h1:Hbg2NidpLE8veEBkEZTL3CvlkUIVzuU9jDplZO54c48=
 github.com/stretchr/objx v0.2.0/go.mod h1:qt09Ya8vawLte6SNmTgCsAVtYtaKzEcn8ATUoHMkEqE=
-github.com/stretchr/testify v0.0.0-20151208002404-e3a8ff8ce365/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
 github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
 github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
 github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
 github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA=
+github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
 github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY=
 github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
 github.com/subosito/gotenv v1.2.0/go.mod h1:N0PQaV/YGNqwC0u51sEeR/aUtSLEXKX9iv69rRypqCw=
-github.com/thanos-io/thanos v0.11.0/go.mod h1:N/Yes7J68KqvmY+xM6J5CJqEvWIvKSR5sqGtmuD6wDc=
-github.com/tidwall/pretty v0.0.0-20180105212114-65a9db5fad51/go.mod h1:XNkn88O1ChpSDQmQeStsy+sBenx6DDtFZJxhVysOjyk=
-github.com/tidwall/pretty v1.0.0 h1:HsD+QiTn7sK6flMKIvNmpqz1qrpP3Ps6jOKIKMooyg4=
+github.com/tidwall/gjson v1.14.0 h1:6aeJ0bzojgWLa82gDQHcx3S0Lr/O51I9bJ5nv6JFx5w=
+github.com/tidwall/gjson v1.14.0/go.mod h1:/wbyibRr2FHMks5tjHJ5F8dMZh3AcwJEMf5vlfC0lxk=
+github.com/tidwall/match v1.1.1 h1:+Ho715JplO36QYgwN9PGYNhgZvoUSc9X2c80KVTi+GA=
+github.com/tidwall/match v1.1.1/go.mod h1:eRSPERbgtNPcGhD8UCthc6PmLEQXEWd3PRB5JTxsfmM=
 github.com/tidwall/pretty v1.0.0/go.mod h1:XNkn88O1ChpSDQmQeStsy+sBenx6DDtFZJxhVysOjyk=
+github.com/tidwall/pretty v1.2.0 h1:RWIZEg2iJ8/g6fDDYzMpobmaoGh5OLl4AXtGUGPcqCs=
+github.com/tidwall/pretty v1.2.0/go.mod h1:ITEVvHYasfjBbM0u2Pg8T2nJnzm8xPwvNhhsoaGGjNU=
 github.com/tmc/grpc-websocket-proxy v0.0.0-20170815181823-89b8d40f7ca8/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U=
-github.com/tmc/grpc-websocket-proxy v0.0.0-20190109142713-0ad062ec5ee5 h1:LnC5Kc/wtumK+WB441p7ynQJzVuNRJiqddSIE3IlSEQ=
 github.com/tmc/grpc-websocket-proxy v0.0.0-20190109142713-0ad062ec5ee5/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U=
-github.com/tv42/httpunix v0.0.0-20150427012821-b75d8614f926/go.mod h1:9ESjWnEqriFuLhtthL60Sar/7RFoluCcXsuvEwTV5KM=
-github.com/uber/jaeger-client-go v2.20.1+incompatible/go.mod h1:WVhlPFC8FDjOFMMWRy2pZqQJSXxYSwNYOkTr/Z6d3Kk=
-github.com/uber/jaeger-lib v2.2.0+incompatible/go.mod h1:ComeNDZlWwrWnDv8aPp0Ba6+uUTzImX/AauajbLI56U=
+github.com/tmc/grpc-websocket-proxy v0.0.0-20201229170055-e5319fda7802 h1:uruHq4dN7GR16kFc5fp3d1RIYzJW5onx8Ybykw2YQFA=
+github.com/tmc/grpc-websocket-proxy v0.0.0-20201229170055-e5319fda7802/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U=
 github.com/ugorji/go v1.1.4/go.mod h1:uQMGLiO92mf5W77hV/PUCpI3pbzQx3CRekS0kk+RGrc=
-github.com/ugorji/go/codec v0.0.0-20181204163529-d75b2dcb6bc8/go.mod h1:VFNgLljTbGfSG7qAOspJ7OScBnGdDN/yBr0sguwnwf0=
-github.com/urfave/cli v0.0.0-20171014202726-7bc6a0acffa5/go.mod h1:70zkFmudgCuE/ngEzBv17Jvp/497gISqfk5gWijbERA=
 github.com/urfave/cli v1.20.0/go.mod h1:70zkFmudgCuE/ngEzBv17Jvp/497gISqfk5gWijbERA=
-github.com/urfave/cli v1.22.1/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0=
-github.com/urfave/cli v1.22.2/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0=
-github.com/vektah/gqlparser v1.1.2/go.mod h1:1ycwN7Ij5njmMkPPAOaRFY4rET2Enx7IkVv3vaXspKw=
-github.com/xanzy/go-gitlab v0.15.0/go.mod h1:8zdQa/ri1dfn8eS3Ir1SyfvOKlw7WBJ8DVThkpGiXrs=
-github.com/xdg/scram v0.0.0-20180814205039-7eeb5667e42c h1:u40Z8hqBAAQyv+vATcGgV0YCnDjqSL7/q/JyPhhJSPk=
-github.com/xdg/scram v0.0.0-20180814205039-7eeb5667e42c/go.mod h1:lB8K/P019DLNhemzwFU4jHLhdvlE6uDZjXFejJXr49I=
-github.com/xdg/stringprep v1.0.0 h1:d9X0esnoa3dFsV0FG35rAT0RIhYFlPq7MiP+DW89La0=
-github.com/xdg/stringprep v1.0.0/go.mod h1:Jhud4/sHMO4oL310DaZAKk9ZaJ08SJfe+sJh0HrGL1Y=
+github.com/xanzy/go-gitlab v0.54.3/go.mod h1:F0QEXwmqiBUxCgJm8fE9S+1veX4XC9Z4cfaAbqwk4YM=
+github.com/xanzy/ssh-agent v0.3.0/go.mod h1:3s9xbODqPuuhK9JV1R321M/FlMZSBvE5aY6eAcqrDh0=
+github.com/xdg-go/pbkdf2 v1.0.0 h1:Su7DPu48wXMwC3bs7MCNG+z4FhcyEuz5dlvchbq0B0c=
+github.com/xdg-go/pbkdf2 v1.0.0/go.mod h1:jrpuAogTd400dnrH08LKmI/xc1MbPOebTwRqcT5RDeI=
+github.com/xdg-go/scram v1.0.2 h1:akYIkZ28e6A96dkWNJQu3nmCzH3YfwMPQExUYDaRv7w=
+github.com/xdg-go/scram v1.0.2/go.mod h1:1WAq6h33pAW+iRreB34OORO2Nf7qel3VV3fjBj+hCSs=
+github.com/xdg-go/stringprep v1.0.2 h1:6iq84/ryjjeRmMJwxutI51F2GIPlP5BfTvXHeYjyhBc=
+github.com/xdg-go/stringprep v1.0.2/go.mod h1:8F9zXuvzgwmyT5DUm4GUfZGDdT3W+LCvS6+da4O5kxM=
+github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f h1:J9EGpcZtP0E/raorCMxlFGSTBrsSlaDGf3jU/qvAE2c=
 github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f/go.mod h1:N2zxlSyiKSe5eX1tZViRH5QA0qijqEDrYZiPEAiq3wU=
+github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415 h1:EzJWgHovont7NscjpAxXsDA8S8BMYve8Y5+7cuRE7R0=
 github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415/go.mod h1:GwrjFmJcFw6At/Gs6z4yjiIwzuJ1/+UwLxMQDVQXShQ=
+github.com/xeipuuv/gojsonschema v1.2.0 h1:LhYJRs+L4fBtjZUfuSZIKGeVu0QRy8e5Xi7D17UxZ74=
 github.com/xeipuuv/gojsonschema v1.2.0/go.mod h1:anYRn/JVcOK2ZgGU+IjEV4nwlhoK5sQluxsYJ78Id3Y=
 github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2 h1:eY9dn8+vbi4tKz5Qo6v2eYzo7kUS51QINcR5jNpbZS8=
 github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU=
-github.com/xlab/handysort v0.0.0-20150421192137-fb3537ed64a1/go.mod h1:QcJo0QPSfTONNIgpN5RA8prR7fF8nkF6cTWTcNerRO8=
-github.com/xlab/treeprint v0.0.0-20180616005107-d6fb6747feb6/go.mod h1:ce1O1j6UtZfjr22oyGxGLbauSBp2YVXpARAosm7dHBg=
+github.com/xlab/treeprint v0.0.0-20181112141820-a009c3971eca h1:1CFlNzQhALwjS9mBAUkycX616GzgsuYUOCHA5+HSlXI=
+github.com/xlab/treeprint v0.0.0-20181112141820-a009c3971eca/go.mod h1:ce1O1j6UtZfjr22oyGxGLbauSBp2YVXpARAosm7dHBg=
 github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77/go.mod h1:aYKd//L2LvnjZzWKhF00oedf4jCCReLcmhLdhm1A27Q=
+github.com/youmark/pkcs8 v0.0.0-20181117223130-1be2e3e5546d h1:splanxYIlg+5LfHAM6xpdFEAYOk8iySO56hMFq6uLyA=
+github.com/youmark/pkcs8 v0.0.0-20181117223130-1be2e3e5546d/go.mod h1:rHwXgn7JulP+udvsHwJoVG1YGAP6VLg4y9I5dyZdqmA=
+github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
 github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
+github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
+github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
+github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k=
+github.com/yuin/goldmark v1.4.0/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k=
 github.com/yvasiyarov/go-metrics v0.0.0-20140926110328-57bccd1ccd43/go.mod h1:aX5oPXxHm3bOH+xeAttToC8pqch2ScQN/JoXYupl6xs=
 github.com/yvasiyarov/gorelic v0.0.0-20141212073537-a9bba5b9ab50/go.mod h1:NUSPSUX/bi6SeDMUh6brw0nXpxHnc96TguQh0+r/ssA=
 github.com/yvasiyarov/newrelic_platform_go v0.0.0-20140908184405-b21fdbd4370f/go.mod h1:GlGEuHIJweS1mbCqG+7vt2nvWLzLLnRHbXz5JKd/Qbg=
-github.com/ziutek/mymysql v1.5.4/go.mod h1:LMSpPZ6DbqWFxNCHW77HeMg9I646SAhApZ/wKdgO/C0=
-gitlab.com/nyarla/go-crypt v0.0.0-20160106005555-d9a5dc2b789b/go.mod h1:T3BPAOm2cqquPa0MKWeNkmOM5RQsRhkrwMWonFMN7fE=
-go.elastic.co/apm v1.5.0/go.mod h1:OdB9sPtM6Vt7oz3VXt7+KR96i9li74qrxBGHTQygFvk=
-go.elastic.co/apm/module/apmhttp v1.5.0/go.mod h1:1FbmNuyD3ddauwzgVwFB0fqY6KbZt3JkV187tGCYYhY=
-go.elastic.co/apm/module/apmot v1.5.0/go.mod h1:d2KYwhJParTpyw2WnTNy8geNlHKKFX+4oK3YLlsesWE=
-go.elastic.co/fastjson v1.0.0/go.mod h1:PmeUOMMtLHQr9ZS9J9owrAVg0FkaZDRZJEFTTGHtchs=
 go.etcd.io/bbolt v1.3.2/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU=
 go.etcd.io/bbolt v1.3.3/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU=
-go.etcd.io/bbolt v1.3.4/go.mod h1:G5EMThwa9y8QZGBClrRx5EY+Yw9kAhnjy3bSjsnlVTQ=
-go.etcd.io/bbolt v1.3.5 h1:XAzx9gjCb0Rxj7EoqcClPD1d5ZBxZJk0jbuoPHenBt0=
-go.etcd.io/bbolt v1.3.5/go.mod h1:G5EMThwa9y8QZGBClrRx5EY+Yw9kAhnjy3bSjsnlVTQ=
+go.etcd.io/bbolt v1.3.6 h1:/ecaJf0sk1l4l6V4awd65v2C3ILy7MSj+s/x1ADCIMU=
+go.etcd.io/bbolt v1.3.6/go.mod h1:qXsaaIqmgQH0T+OPdb99Bf+PKfBBQVAdyD6TY9G8XM4=
 go.etcd.io/etcd v0.5.0-alpha.5.0.20200819165624-17cef6e3e9d5 h1:Gqga3zA9tdAcfqobUGjSoCob5L3f8Dt5EuOp3ihNZko=
 go.etcd.io/etcd v0.5.0-alpha.5.0.20200819165624-17cef6e3e9d5/go.mod h1:skWido08r9w6Lq/w70DO5XYIKMu4QFu1+4VsqLQuJy8=
-go.mongodb.org/mongo-driver v1.0.3/go.mod h1:u7ryQJ+DOzQmeO7zB6MHyr8jkEQvC8vH7qLUO4lqsUM=
-go.mongodb.org/mongo-driver v1.1.0/go.mod h1:u7ryQJ+DOzQmeO7zB6MHyr8jkEQvC8vH7qLUO4lqsUM=
-go.mongodb.org/mongo-driver v1.1.1/go.mod h1:u7ryQJ+DOzQmeO7zB6MHyr8jkEQvC8vH7qLUO4lqsUM=
-go.mongodb.org/mongo-driver v1.1.2 h1:jxcFYjlkl8xaERsgLo+RNquI0epW6zuy/ZRQs6jnrFA=
-go.mongodb.org/mongo-driver v1.1.2/go.mod h1:u7ryQJ+DOzQmeO7zB6MHyr8jkEQvC8vH7qLUO4lqsUM=
-go.opencensus.io v0.20.1/go.mod h1:6WKK9ahsWS3RSO+PY9ZHZUfv2irvY6gN279GOPZjmmk=
-go.opencensus.io v0.20.2/go.mod h1:6WKK9ahsWS3RSO+PY9ZHZUfv2irvY6gN279GOPZjmmk=
+go.etcd.io/etcd/api/v3 v3.5.0/go.mod h1:cbVKeC6lCfl7j/8jBhAK6aIYO9XOjdptoxU/nLQcPvs=
+go.etcd.io/etcd/client/pkg/v3 v3.5.0/go.mod h1:IJHfcCEKxYu1Os13ZdwCwIUTUVGYTSAM3YSwc9/Ac1g=
+go.etcd.io/etcd/client/v2 v2.305.0/go.mod h1:h9puh54ZTgAKtEbut2oe9P4L/oqKCVB6xsXlzd7alYQ=
+go.etcd.io/etcd/client/v3 v3.5.0/go.mod h1:AIKXXVX/DQXtfTEqBryiLTUXwON+GuvO6Z7lLS/oTh0=
+go.etcd.io/etcd/pkg/v3 v3.5.0/go.mod h1:UzJGatBQ1lXChBkQF0AuAtkRQMYnHubxAEYIrC3MSsE=
+go.etcd.io/etcd/raft/v3 v3.5.0/go.mod h1:UFOHSIvO/nKwd4lhkwabrTD3cqW5yVyYYf/KlD00Szc=
+go.etcd.io/etcd/server/v3 v3.5.0/go.mod h1:3Ah5ruV+M+7RZr0+Y/5mNLwC+eQlni+mQmOVdCRJoS4=
+go.mongodb.org/mongo-driver v1.8.4 h1:NruvZPPL0PBcRJKmbswoWSrmHeUvzdxA3GCPfD/NEOA=
+go.mongodb.org/mongo-driver v1.8.4/go.mod h1:0sQWfOeY63QTntERDJJ/0SuKK0T1uVSgKCuAROlKEPY=
 go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU=
 go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8=
 go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
+go.opencensus.io v0.22.3/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
+go.opencensus.io v0.22.4/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
+go.opencensus.io v0.22.5/go.mod h1:5pWMHQbX5EPX2/62yrJeAkowc+lfs/XD7Uxpq3pI6kk=
+go.opencensus.io v0.23.0/go.mod h1:XItmlyltB5F7CS4xOC1DcqMoFqwtC6OG2xF7mCv7P7E=
+go.opentelemetry.io/contrib v0.20.0/go.mod h1:G/EtFaa6qaN7+LxqfIAT3GiZa7Wv5DTBUzl5H4LY0Kc=
+go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.20.0/go.mod h1:oVGt1LRbBOBq1A5BQLlUg9UaU/54aiHw8cgjV3aWZ/E=
+go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.20.0/go.mod h1:2AboqHi0CiIZU0qwhtUfCYD1GeUzvvIXWNkhDt7ZMG4=
+go.opentelemetry.io/otel v0.20.0/go.mod h1:Y3ugLH2oa81t5QO+Lty+zXf8zC9L26ax4Nzoxm/dooo=
+go.opentelemetry.io/otel/exporters/otlp v0.20.0/go.mod h1:YIieizyaN77rtLJra0buKiNBOm9XQfkPEKBeuhoMwAM=
+go.opentelemetry.io/otel/metric v0.20.0/go.mod h1:598I5tYlH1vzBjn+BTuhzTCSb/9debfNp6R3s7Pr1eU=
+go.opentelemetry.io/otel/oteltest v0.20.0/go.mod h1:L7bgKf9ZB7qCwT9Up7i9/pn0PWIa9FqQ2IQ8LoxiGnw=
+go.opentelemetry.io/otel/sdk v0.20.0/go.mod h1:g/IcepuwNsoiX5Byy2nNV0ySUF1em498m7hBWC279Yc=
+go.opentelemetry.io/otel/sdk/export/metric v0.20.0/go.mod h1:h7RBNMsDJ5pmI1zExLi+bJK+Dr8NQCh0qGhm1KDnNlE=
+go.opentelemetry.io/otel/sdk/metric v0.20.0/go.mod h1:knxiS8Xd4E/N+ZqKmUPf3gTTZ4/0TjTXukfxjzSTpHE=
+go.opentelemetry.io/otel/trace v0.20.0/go.mod h1:6GjCW8zgDjwGHGa6GkyeB8+/5vjT16gUEi0Nf1iBdgw=
+go.opentelemetry.io/proto/otlp v0.7.0/go.mod h1:PqfVotwruBrMGOCsRd/89rSnXhoiJIqeYNgFYFoEGnI=
+go.starlark.net v0.0.0-20200306205701-8dd3e2ee1dd5 h1:+FNtrFTmVw0YZGpBGX56XDee331t6JAXeK2bcyhLOOc=
+go.starlark.net v0.0.0-20200306205701-8dd3e2ee1dd5/go.mod h1:nmDLcffg48OtT/PSW0Hg7FvpRQsQh5OSqIylirxKC7o=
 go.uber.org/atomic v1.3.2/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE=
 go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE=
-go.uber.org/atomic v1.5.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ=
-go.uber.org/atomic v1.6.0 h1:Ezj3JGmsOnG1MoRWQkPBsKLe9DwWD9QeXzTRzzldNVk=
-go.uber.org/atomic v1.6.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ=
-go.uber.org/automaxprocs v1.2.0/go.mod h1:YfO3fm683kQpzETxlTGZhGIVmXAhaw3gxeBADbpZtnU=
+go.uber.org/atomic v1.7.0 h1:ADUqmZGgLDDfbSL9ZmPxKTybcoEYHgpYfELNoN+7hsw=
+go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc=
+go.uber.org/goleak v1.1.10/go.mod h1:8a7PlsEVH3e/a/GLqe5IIrQx6GzcnRmZEufDUTk4A7A=
+go.uber.org/goleak v1.1.11-0.20210813005559-691160354723/go.mod h1:cwTWslyiVhfpKIDGSZEM2HlOvcqm+tG4zioyIeLoqMQ=
+go.uber.org/goleak v1.1.12 h1:gZAh5/EyT/HQwlpkCy6wTpqfH9H8Lz8zbm3dZh+OyzA=
+go.uber.org/goleak v1.1.12/go.mod h1:cwTWslyiVhfpKIDGSZEM2HlOvcqm+tG4zioyIeLoqMQ=
 go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0=
-go.uber.org/multierr v1.3.0/go.mod h1:VgVr7evmIr6uPjLBxg28wmKNXyqE9akIJ5XnfpiKl+4=
-go.uber.org/multierr v1.5.0 h1:KCa4XfM8CWFCpxXRGok+Q0SS/0XBhMDbHHGABQLvD2A=
-go.uber.org/multierr v1.5.0/go.mod h1:FeouvMocqHpRaaGuG9EjoKcStLC43Zu/fmqdUMPcKYU=
-go.uber.org/tools v0.0.0-20190618225709-2cfd321de3ee h1:0mgffUl7nfd+FpvXMVz4IDEaUSmT1ysygQC7qYo7sG4=
-go.uber.org/tools v0.0.0-20190618225709-2cfd321de3ee/go.mod h1:vJERXedbb3MVM5f9Ejo0C68/HhF8uaILCdgjnY+goOA=
-go.uber.org/zap v1.8.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q=
+go.uber.org/multierr v1.6.0 h1:y6IPFStTAIT5Ytl7/XYmHvzXQ7S3g/IeZW9hyZ5thw4=
+go.uber.org/multierr v1.6.0/go.mod h1:cdWPpRnG4AhwMwsgIHip0KRBQjJy5kYEpYjJxpXp9iU=
 go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q=
-go.uber.org/zap v1.13.0/go.mod h1:zwrFLgMcdUuIBviXEYEH1YKNaOBnKXsx2IPda5bBwHM=
-go.uber.org/zap v1.14.1 h1:nYDKopTbvAPq/NrUVZwT15y2lpROBiLLyoRTbXOYWOo=
-go.uber.org/zap v1.14.1/go.mod h1:Mb2vm2krFEG5DV0W9qcHBYFtp/Wku1cvYaqPsS/WYfc=
-golang.org/x/crypto v0.0.0-20171113213409-9f005a07e0d3/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
+go.uber.org/zap v1.17.0/go.mod h1:MXVU+bhUf/A7Xi2HNOnopQOrmycQ5Ih87HtOu4q5SSo=
+go.uber.org/zap v1.19.0/go.mod h1:xg/QME4nWcxGxrpdeYfq7UvYrLh66cuVKdrbD1XF/NI=
+go.uber.org/zap v1.19.1 h1:ue41HOKd1vGURxrmeKIgELGb3jPW9DMUDGtsinblHwI=
+go.uber.org/zap v1.19.1/go.mod h1:j3DNczoxDZroyBnOT1L/Q79cfUMGZxlv/9dzN7SM1rI=
 golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
 golang.org/x/crypto v0.0.0-20181029021203-45a5f77698d3/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
-golang.org/x/crypto v0.0.0-20181203042331-505ab145d0a9/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
-golang.org/x/crypto v0.0.0-20190211182817-74369b46fc67/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
+golang.org/x/crypto v0.0.0-20190219172222-a4c6cb3142f2/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
 golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
-golang.org/x/crypto v0.0.0-20190320223903-b7391e95e576/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
-golang.org/x/crypto v0.0.0-20190325154230-a5d413f7728c/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
-golang.org/x/crypto v0.0.0-20190426145343-a29dc8fdc734/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
 golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
-golang.org/x/crypto v0.0.0-20190513172903-22d7a77e9e5f/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
 golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
-golang.org/x/crypto v0.0.0-20190611184440-5c40567a22f8/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
-golang.org/x/crypto v0.0.0-20190617133340-57b3e21c3d56/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
-golang.org/x/crypto v0.0.0-20190621222207-cc06ce4a13d4/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
-golang.org/x/crypto v0.0.0-20190701094942-4def268fd1a4/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
-golang.org/x/crypto v0.0.0-20190923035154-9ee001bba392/go.mod h1:/lpIB1dKB+9EgE3H3cr1v9wB50oz8l4C4h62xy7jSTY=
+golang.org/x/crypto v0.0.0-20190820162420-60c769a6c586/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
 golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
-golang.org/x/crypto v0.0.0-20191112222119-e1110fd1c708/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
-golang.org/x/crypto v0.0.0-20191206172530-e9b2fee46413/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
-golang.org/x/crypto v0.0.0-20200414173820-0848c9571904/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
 golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
-golang.org/x/crypto v0.0.0-20201221181555-eec23a3978ad h1:DN0cp81fZ3njFcrLCytUHRSUkqBjfTo4Tx9RJTWs0EY=
-golang.org/x/crypto v0.0.0-20201221181555-eec23a3978ad/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I=
+golang.org/x/crypto v0.0.0-20201002170205-7f63de1d35b0/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
+golang.org/x/crypto v0.0.0-20201216223049-8b5274cf687f/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I=
+golang.org/x/crypto v0.0.0-20210322153248-0c34fe9e7dc2/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4=
+golang.org/x/crypto v0.0.0-20210421170649-83a5a9bb288b/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4=
+golang.org/x/crypto v0.0.0-20210817164053-32db794688a5/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
+golang.org/x/crypto v0.0.0-20211215153901-e495a2d5b3d3 h1:0es+/5331RGQPcXlMfP+WrnIIS6dNnNRe0WB02W0F4M=
+golang.org/x/crypto v0.0.0-20211215153901-e495a2d5b3d3/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
 golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
 golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
 golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8=
 golang.org/x/exp v0.0.0-20190829153037-c13cbed26979/go.mod h1:86+5VVa7VpoJ4kLfm080zCjGlMRFzhUhsZKEZO7MGek=
 golang.org/x/exp v0.0.0-20191030013958-a1ab85dbe136/go.mod h1:JXzH8nQsPlswgeRAPE3MuO9GYsAcnJvJ4vnMwN/5qkY=
+golang.org/x/exp v0.0.0-20191129062945-2f5052295587/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4=
 golang.org/x/exp v0.0.0-20191227195350-da58074b4299/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4=
+golang.org/x/exp v0.0.0-20200119233911-0405dc783f0a/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4=
+golang.org/x/exp v0.0.0-20200207192155-f17229e696bd/go.mod h1:J/WKrq2StrnmMY6+EHIKF9dgMWnmCNThgcyBT1FY9mM=
+golang.org/x/exp v0.0.0-20200224162631-6cc2880d07d6/go.mod h1:3jZMyOhIsHpP37uCMkUooju7aAi5cS1Q23tOzKc+0MU=
 golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js=
 golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0=
-golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
 golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU=
 golang.org/x/lint v0.0.0-20190301231843-5614ed5bae6f/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
 golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
 golang.org/x/lint v0.0.0-20190409202823-959b441ac422/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
 golang.org/x/lint v0.0.0-20190909230951-414d861bb4ac/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
 golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
-golang.org/x/lint v0.0.0-20191125180803-fdd1cda4f05f h1:J5lckAjkw6qYlOZNj90mLYNTEKDvWeuc1yieZ8qUzUE=
 golang.org/x/lint v0.0.0-20191125180803-fdd1cda4f05f/go.mod h1:5qLYkcX4OjUUV8bRuDixDT3tpyyb+LUpUlRWLxfhWrs=
+golang.org/x/lint v0.0.0-20200130185559-910be7a94367/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY=
+golang.org/x/lint v0.0.0-20200302205851-738671d3881b/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY=
+golang.org/x/lint v0.0.0-20201208152925-83fdc39ff7b5/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY=
+golang.org/x/lint v0.0.0-20210508222113-6edffad5e616/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY=
 golang.org/x/mobile v0.0.0-20190312151609-d3739f865fa6/go.mod h1:z+o9i4GpDbdi3rU15maQ/Ox0txvL9dWGYEHz965HBQE=
 golang.org/x/mobile v0.0.0-20190719004257-d2bd2a29d028/go.mod h1:E/iHnbuqvinMTCcRqshq8CkpyQDoeVncDDYHnLhea+o=
 golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc=
 golang.org/x/mod v0.1.0/go.mod h1:0QHyrYULN0/3qlju5TqG8bIK38QM8yzMo5ekMj3DlcY=
 golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg=
+golang.org/x/mod v0.1.1-0.20191107180719-034126e5016b/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg=
 golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
-golang.org/x/mod v0.3.0 h1:RM4zey1++hCTbCVQfnWeKs9/IEsaBLA8vTkd0WVtmH4=
 golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
-golang.org/x/net v0.0.0-20170114055629-f2499483f923/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
+golang.org/x/mod v0.4.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
+golang.org/x/mod v0.4.1/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
+golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
+golang.org/x/net v0.0.0-20180218175443-cbe0f9307d01/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
 golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
-golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
 golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
-golang.org/x/net v0.0.0-20181005035420-146acd28ed58/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
 golang.org/x/net v0.0.0-20181023162649-9b4f9f5ad519/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
-golang.org/x/net v0.0.0-20181108082009-03003ca0c849/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
 golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
 golang.org/x/net v0.0.0-20181201002055-351d144fa1fc/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
 golang.org/x/net v0.0.0-20181220203305-927f97764cc3/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
 golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
-golang.org/x/net v0.0.0-20190125091013-d26f9f9a57f3/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
 golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
 golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
-golang.org/x/net v0.0.0-20190320064053-1272bf9dcd53/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
 golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
-golang.org/x/net v0.0.0-20190424112056-4829fb13d2c6/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
 golang.org/x/net v0.0.0-20190501004415-9ce7a6920f09/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
 golang.org/x/net v0.0.0-20190503192946-f4e77d36d62c/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
 golang.org/x/net v0.0.0-20190522155817-f3200d17e092/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks=
@@ -1021,163 +779,232 @@ golang.org/x/net v0.0.0-20190628185345-da137c7871d7/go.mod h1:z5CRVTTTmAJ677TzLL
 golang.org/x/net v0.0.0-20190724013045-ca1201d0de80/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
 golang.org/x/net v0.0.0-20190813141303-74dc4d7220e7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
 golang.org/x/net v0.0.0-20190827160401-ba9fcec4b297/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
-golang.org/x/net v0.0.0-20190923162816-aa69164e4478/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
-golang.org/x/net v0.0.0-20191002035440-2ec189313ef0/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
-golang.org/x/net v0.0.0-20191004110552-13f9640d40b9/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
-golang.org/x/net v0.0.0-20191028085509-fe3aa8a45271/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
-golang.org/x/net v0.0.0-20191112182307-2180aed22343/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
 golang.org/x/net v0.0.0-20191209160850-c0dbc17a3553/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
+golang.org/x/net v0.0.0-20200114155413-6afb5195e5aa/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
+golang.org/x/net v0.0.0-20200202094626-16171245cfb2/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
+golang.org/x/net v0.0.0-20200222125558-5a598a2470a0/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
 golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
 golang.org/x/net v0.0.0-20200301022130-244492dfa37a/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
 golang.org/x/net v0.0.0-20200324143707-d3edc9973b7e/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
-golang.org/x/net v0.0.0-20200707034311-ab3426394381 h1:VXak5I6aEWmAXeQjA+QSZzlgNrpq9mjcfDemuexIKsU=
+golang.org/x/net v0.0.0-20200501053045-e0ff5e5a1de5/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
+golang.org/x/net v0.0.0-20200506145744-7e3656a0809f/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
+golang.org/x/net v0.0.0-20200513185701-a91f0712d120/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
+golang.org/x/net v0.0.0-20200520004742-59133d7f0dd7/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
+golang.org/x/net v0.0.0-20200520182314-0ba52f642ac2/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
+golang.org/x/net v0.0.0-20200625001655-4c5254603344/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
 golang.org/x/net v0.0.0-20200707034311-ab3426394381/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
+golang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
+golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
+golang.org/x/net v0.0.0-20201031054903-ff519b6c9102/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
+golang.org/x/net v0.0.0-20201110031124-69a78807bb2b/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
+golang.org/x/net v0.0.0-20201202161906-c7110b5ffcbb/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
+golang.org/x/net v0.0.0-20201209123823-ac852fbbde11/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
+golang.org/x/net v0.0.0-20210119194325-5f4716e94777/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
+golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
+golang.org/x/net v0.0.0-20210316092652-d523dce5a7f4/go.mod h1:RBQZq4jEuRlivfhVLdyRGr576XBO4/greRjx4P4O3yc=
+golang.org/x/net v0.0.0-20210326060303-6b1517762897/go.mod h1:uSPa2vr4CLtc/ILN5odXGNXS6mhrKVzTaCXzk9m6W3k=
+golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM=
+golang.org/x/net v0.0.0-20210428140749-89ef3d95e781/go.mod h1:OJAsFXCWl8Ukc7SiCT/9KSuxbyM7479/AVlXFRxuMCk=
+golang.org/x/net v0.0.0-20210525063256-abc453219eb5/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
+golang.org/x/net v0.0.0-20210805182204-aaa1db679c0d/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
+golang.org/x/net v0.0.0-20210825183410-e898025ed96a/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
+golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
+golang.org/x/net v0.0.0-20211209124913-491a49abca63/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
+golang.org/x/net v0.0.0-20211215060638-4ddde0e984e9/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
+golang.org/x/net v0.0.0-20211216030914-fe4d6282115f/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
+golang.org/x/net v0.0.0-20220127200216-cd36cc0744dd h1:O7DYs+zxREGLKzKoMQrtrEacpb0ZVXA5rIwylE2Xchk=
+golang.org/x/net v0.0.0-20220127200216-cd36cc0744dd/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk=
+golang.org/x/oauth2 v0.0.0-20180227000427-d7d64896b5ff/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
 golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
 golang.org/x/oauth2 v0.0.0-20181106182150-f42d05182288/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
 golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
-golang.org/x/oauth2 v0.0.0-20190402181905-9f3314589c9a/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
 golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
-golang.org/x/oauth2 v0.0.0-20191202225959-858c2ad4c8b6 h1:pE8b58s1HRDMi8RDc79m0HISf9D4TzseP40cEA6IGfs=
 golang.org/x/oauth2 v0.0.0-20191202225959-858c2ad4c8b6/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
+golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
+golang.org/x/oauth2 v0.0.0-20200902213428-5d25da1a8d43/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
+golang.org/x/oauth2 v0.0.0-20201109201403-9fd604954f58/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
+golang.org/x/oauth2 v0.0.0-20201208152858-08078c50e5b5/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
+golang.org/x/oauth2 v0.0.0-20210218202405-ba52d332ba99/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
+golang.org/x/oauth2 v0.0.0-20210220000619-9bb904979d93/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
+golang.org/x/oauth2 v0.0.0-20210313182246-cd4f82c27b84/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
+golang.org/x/oauth2 v0.0.0-20210402161424-2e8d93401602/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
+golang.org/x/oauth2 v0.0.0-20210514164344-f6687ab2804c/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
+golang.org/x/oauth2 v0.0.0-20210819190943-2bc19b11175f h1:Qmd2pbz05z7z6lm0DrgQVVPuBm92jqujBKMHMOlOQEw=
+golang.org/x/oauth2 v0.0.0-20210819190943-2bc19b11175f/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
 golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
 golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
 golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
 golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
 golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
 golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
-golang.org/x/sync v0.0.0-20201207232520-09787c993a3a h1:DcqTD9SDLc+1P/r1EmRBwnVsrOwW+kk2vWf9n+1sGhs=
+golang.org/x/sync v0.0.0-20200317015054-43a5402ce75a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
+golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
+golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
 golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
-golang.org/x/sys v0.0.0-20170830134202-bb24a47a89ea/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
+golang.org/x/sync v0.0.0-20210220032951-036812b2e83c h1:5KslGYwFpkhGh+Q16bwMP3cOontH8FOep7tGV86Y7SQ=
+golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
+golang.org/x/sys v0.0.0-20180224232135-f6cff0780e54/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
 golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
-golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
 golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
 golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
 golang.org/x/sys v0.0.0-20181026203630-95b1ffbd15a5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
 golang.org/x/sys v0.0.0-20181107165924-66b7b1311ac8/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
 golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
-golang.org/x/sys v0.0.0-20181122145206-62eef0e2fa9b/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
-golang.org/x/sys v0.0.0-20181205085412-a5c9d58dba9a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
-golang.org/x/sys v0.0.0-20190102155601-82a175fd1598/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
-golang.org/x/sys v0.0.0-20190209173611-3b5209105503/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
 golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
-golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
-golang.org/x/sys v0.0.0-20190310054646-10058d7d4faa/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/sys v0.0.0-20190321052220-f7bb7a8bee54/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/sys v0.0.0-20190425145619-16072639606e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/sys v0.0.0-20190426135247-a129542de9ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 golang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/sys v0.0.0-20190514135907-3a4b5fb9f71f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/sys v0.0.0-20190515120540-06a5c4944438/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 golang.org/x/sys v0.0.0-20190602015325-4c4f7f33c9ed/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/sys v0.0.0-20190616124812-15dcb6c0061f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/sys v0.0.0-20190626221950-04f50cda93cb/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/sys v0.0.0-20190712062909-fae7ac547cb7/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 golang.org/x/sys v0.0.0-20190726091711-fc99dfbffb4e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/sys v0.0.0-20190801041406-cbf593c0f2f3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/sys v0.0.0-20190813064441-fde4db37ae7a/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 golang.org/x/sys v0.0.0-20190826190057-c7b8b68b1456/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20190904154756-749cb33beabd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 golang.org/x/sys v0.0.0-20190916202348-b4ddaad3f8a3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/sys v0.0.0-20190922100055-0a153f010e69/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/sys v0.0.0-20190924154521-2837fb4f24fe/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20191001151750-bb3f8db39f24/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20191002063906-3421d5a6bb1c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/sys v0.0.0-20191010194322-b09406accb47/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/sys v0.0.0-20191022100944-742c48ecaeb7/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/sys v0.0.0-20191025021431-6c3a3bfe00ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/sys v0.0.0-20191112214154-59a1497f0cea/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/sys v0.0.0-20191113165036-4c7a9d0fe056/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 golang.org/x/sys v0.0.0-20191120155948-bd437916bb0e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/sys v0.0.0-20191220142924-d4481acd189f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 golang.org/x/sys v0.0.0-20191228213918-04cbcbbfeed8/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 golang.org/x/sys v0.0.0-20200106162015-b016eb3dc98e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/sys v0.0.0-20200120151820-655fe14d7479/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20200113162924-86b910548bc1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 golang.org/x/sys v0.0.0-20200122134326-e047566fdf82/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 golang.org/x/sys v0.0.0-20200202164722-d101bd2416d5/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20200212091648-12a6c2dcc1e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 golang.org/x/sys v0.0.0-20200302150141-5c8b2ff67527/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20200331124033-c3d80250170d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20200501052902-10377860bb8e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20200511232937-7e40ca221e25/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20200515095857-1151b9dac4a9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20200519105757-fe76b779f299/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20200523222454-059865788121/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 golang.org/x/sys v0.0.0-20200615200032-f1bc736245b1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/sys v0.0.0-20200622214017-ed371f2e16b4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20200625212154-ddb9806d33ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20200803210538-64077c9b5642/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20200831180312-196b9ba8737a/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20200905004654-be1d3432aa8f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20200923182605-d9f96fdee20d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 golang.org/x/sys v0.0.0-20201201145000-ef89a241ccb3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c h1:VwygUrnw9jn88c4u8GD3rZQbqrP/tgas88tPUbBxQrk=
+golang.org/x/sys v0.0.0-20210104204734-6f8348627aad/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20210112080510-489259a85091/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20210119212857-b64e53b001e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/term v0.0.0-20201117132131-f5c789dd3221 h1:/ZHdbVpdR/jk3g30/d4yUL0JU9kksj8+F/bnQUVLGDM=
+golang.org/x/sys v0.0.0-20210220050731-9a76102bfb43/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20210305230114-8fe3ee5dd75b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20210315160823-c6e025ad8005/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20210320140829-1e4c9ba3b0c4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20210324051608-47abb6519492/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20210403161142-5e06dd20ab57/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20210502180810-71e4cd670f79/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.0.0-20210603081109-ebe580a85c40/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.0.0-20210616094352-59db8d763f22/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.0.0-20210809222454-d867a43fc93e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.0.0-20210831042530-f4d43177bf5e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.0.0-20211029165221-6e7872819dc8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e h1:fLOSk5Q00efkSvAm+4xcoXD+RRmLmmulPn5I3Y9F2EM=
+golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
 golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw=
-golang.org/x/text v0.0.0-20160726164857-2910a502d2bf/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
+golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
+golang.org/x/term v0.0.0-20210615171337-6886f2dfbf5b/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
+golang.org/x/term v0.0.0-20210927222741-03fcf44c2211 h1:JGgROgKl9N8DuW20oFS5gxc+lE67/N3FcwmBPMe7ArY=
+golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
+golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
 golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
-golang.org/x/text v0.3.1-0.20180805044716-cb6730876b98/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
 golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
 golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
-golang.org/x/text v0.3.3 h1:cokOdA+Jmi5PJGXLlLllQSgYigAEfHXJAERHVMaCc2k=
 golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
+golang.org/x/text v0.3.4/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
+golang.org/x/text v0.3.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
+golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
+golang.org/x/text v0.3.7 h1:olpwvP2KacW1ZWvsR7uQhoyTYvKAupfQrRGBFM352Gk=
+golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
 golang.org/x/time v0.0.0-20180412165947-fbb02b2291d2/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
 golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
 golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
-golang.org/x/time v0.0.0-20191024005414-555d28b269f0 h1:/5xXl8Y5W96D+TtHSlonuFqGHIWVuyCkGJLwGh9JJFs=
 golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
+golang.org/x/time v0.0.0-20210220033141-f8bda1e9f3ba/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
+golang.org/x/time v0.0.0-20210723032227-1f47c861a9ac h1:7zkz7BUtwNFFqcowJ+RIgu2MaV/MapERkDIy+mwPyjs=
+golang.org/x/time v0.0.0-20210723032227-1f47c861a9ac/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
 golang.org/x/tools v0.0.0-20180221164845-07fd8470d635/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
-golang.org/x/tools v0.0.0-20180828015842-6cd1fcedba52/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
 golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
-golang.org/x/tools v0.0.0-20181011042414-1f849cf54d09/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
 golang.org/x/tools v0.0.0-20181030221726-6c7e314b6563/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
-golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
-golang.org/x/tools v0.0.0-20190118193359-16909d206f00/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
-golang.org/x/tools v0.0.0-20190125232054-d66bd3c5d5a6/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
 golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY=
 golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
 golang.org/x/tools v0.0.0-20190312151545-0bb0c0a6e846/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
 golang.org/x/tools v0.0.0-20190312170243-e65039ee4138/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
 golang.org/x/tools v0.0.0-20190328211700-ab21143f2384/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
 golang.org/x/tools v0.0.0-20190425150028-36563e24a262/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
-golang.org/x/tools v0.0.0-20190425222832-ad9eeb80039a/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
 golang.org/x/tools v0.0.0-20190506145303-2d16b83fe98c/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
 golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
+golang.org/x/tools v0.0.0-20190531172133-b3315ee88b7d/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
 golang.org/x/tools v0.0.0-20190606124116-d0a3d012864b/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
-golang.org/x/tools v0.0.0-20190614205625-5aca471b1d59/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
-golang.org/x/tools v0.0.0-20190617190820-da514acc4774/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
 golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
 golang.org/x/tools v0.0.0-20190624222133-a101b041ded4/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
 golang.org/x/tools v0.0.0-20190628153133-6cdbf07be9d0/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
-golang.org/x/tools v0.0.0-20190706070813-72ffa07ba3db/go.mod h1:jcCCGcm9btYwXyDqrUWc6MKQKKGJCWEQ3AfLSRIbEuI=
-golang.org/x/tools v0.0.0-20190813034749-528a2984e271/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
 golang.org/x/tools v0.0.0-20190816200558-6889da9d5479/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
-golang.org/x/tools v0.0.0-20190907020128-2ca718005c18/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
 golang.org/x/tools v0.0.0-20190911174233-4f2ddba30aff/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
-golang.org/x/tools v0.0.0-20190918214516-5a1a30219888/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
-golang.org/x/tools v0.0.0-20190920225731-5eefd052ad72/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
-golang.org/x/tools v0.0.0-20191004055002-72853e10c5a3/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
 golang.org/x/tools v0.0.0-20191012152004-8de300cfc20a/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
-golang.org/x/tools v0.0.0-20191029041327-9cc4af7d6b2c/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
-golang.org/x/tools v0.0.0-20191029190741-b9c20aec41a5/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
-golang.org/x/tools v0.0.0-20191030203535-5e247c9ad0a0/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
-golang.org/x/tools v0.0.0-20191111182352-50fa39b762bc/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
+golang.org/x/tools v0.0.0-20191108193012-7d206e10da11/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
 golang.org/x/tools v0.0.0-20191112195655-aa38f8e97acc/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
 golang.org/x/tools v0.0.0-20191113191852-77e3bb0ad9e7/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
 golang.org/x/tools v0.0.0-20191115202509-3a792d9c32b2/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
 golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
 golang.org/x/tools v0.0.0-20191125144606-a911d9008d1f/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
+golang.org/x/tools v0.0.0-20191130070609-6e064ea0cf2d/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
+golang.org/x/tools v0.0.0-20191216173652-a0e659d51361/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
 golang.org/x/tools v0.0.0-20191227053925-7b8e75db28f4/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
-golang.org/x/tools v0.0.0-20200103221440-774c71fcf114/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
-golang.org/x/tools v0.0.0-20200403190813-44a64ad78b9b/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
-golang.org/x/tools v0.0.0-20200616133436-c1934b75d054 h1:HHeAlu5H9b71C+Fx0K+1dGgVFN1DM1/wz4aoGOA5qS8=
-golang.org/x/tools v0.0.0-20200616133436-c1934b75d054/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
+golang.org/x/tools v0.0.0-20200117161641-43d50277825c/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
+golang.org/x/tools v0.0.0-20200122220014-bf1340f18c4a/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
+golang.org/x/tools v0.0.0-20200130002326-2f3ba24bd6e7/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
+golang.org/x/tools v0.0.0-20200204074204-1cc6d1ef6c74/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
+golang.org/x/tools v0.0.0-20200207183749-b753a1ba74fa/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
+golang.org/x/tools v0.0.0-20200212150539-ea181f53ac56/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
+golang.org/x/tools v0.0.0-20200224181240-023911ca70b2/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
+golang.org/x/tools v0.0.0-20200227222343-706bc42d1f0d/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
+golang.org/x/tools v0.0.0-20200304193943-95d2e580d8eb/go.mod h1:o4KQGtdN14AW+yjsvvwRTJJuXz8XRtIHtEnmAXLyFUw=
+golang.org/x/tools v0.0.0-20200312045724-11d5b4c81c7d/go.mod h1:o4KQGtdN14AW+yjsvvwRTJJuXz8XRtIHtEnmAXLyFUw=
+golang.org/x/tools v0.0.0-20200331025713-a30bf2db82d4/go.mod h1:Sl4aGygMT6LrqrWclx+PTx3U+LnKx/seiNR+3G19Ar8=
+golang.org/x/tools v0.0.0-20200501065659-ab2804fb9c9d/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
+golang.org/x/tools v0.0.0-20200505023115-26f46d2f7ef8/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
+golang.org/x/tools v0.0.0-20200512131952-2bc93b1c0c88/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
+golang.org/x/tools v0.0.0-20200515010526-7d3b6ebf133d/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
+golang.org/x/tools v0.0.0-20200618134242-20370b0cb4b2/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
+golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
+golang.org/x/tools v0.0.0-20200729194436-6467de6f59a7/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA=
+golang.org/x/tools v0.0.0-20200804011535-6c149bb5ef0d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA=
+golang.org/x/tools v0.0.0-20200825202427-b303f430e36d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA=
+golang.org/x/tools v0.0.0-20200904185747-39188db58858/go.mod h1:Cj7w3i3Rnn0Xh82ur9kSqwfTHTeVxaDqrfMjpcNT6bE=
+golang.org/x/tools v0.0.0-20201110124207-079ba7bd75cd/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
+golang.org/x/tools v0.0.0-20201201161351-ac6f37ff4c2a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
+golang.org/x/tools v0.0.0-20201208233053-a543418bbed2/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
+golang.org/x/tools v0.0.0-20201224043029-2b0845dc783e/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
+golang.org/x/tools v0.0.0-20210105154028-b0ab187a4818/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
+golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
+golang.org/x/tools v0.1.0/go.mod h1:xkSsbof2nBLbhDlRMhhhyNLN/zl3eTqcnHD5viDpcZ0=
+golang.org/x/tools v0.1.1/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
+golang.org/x/tools v0.1.2/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
+golang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
+golang.org/x/tools v0.1.6-0.20210820212750-d4cc65f0b2ff/go.mod h1:YD9qOF0M9xpSpdWTBbzEl5e/RnCefISl8E5Noe10jFM=
 golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
 golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
-golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543 h1:E7g+9GITq07hpfrRu66IVDexMakfv52eLZ2CXBWiKr4=
 golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
-gomodules.xyz/jsonpatch/v2 v2.0.1/go.mod h1:IhYNNY4jnS53ZnfE4PAmpKtDpTCj1JFXc+3mwe7XcUU=
-gomodules.xyz/jsonpatch/v3 v3.0.1/go.mod h1:CBhndykehEwTOlEfnsfJwvkFQbSN8YZFr9M+cIHAJto=
-gomodules.xyz/orderedmap v0.1.0/go.mod h1:g9/TPUCm1t2gwD3j3zfV8uylyYhVdCNSi+xCEIu7yTU=
+golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE=
+golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
+gomodules.xyz/jsonpatch/v2 v2.2.0/go.mod h1:WXp+iVDkoLQqPudfQ9GBlwB2eZ5DKOnjQZCYdOS8GPY=
 google.golang.org/api v0.0.0-20160322025152-9bf6e6e569ff/go.mod h1:4mhQ8q/RsB7i+udVvVy5NUi08OU8ZlA0gRVgrF7VFY0=
-google.golang.org/api v0.3.1/go.mod h1:6wY9I6uQWHQ8EM57III9mq/AjF+i8G65rmVagqKMtkk=
-google.golang.org/api v0.3.2/go.mod h1:6wY9I6uQWHQ8EM57III9mq/AjF+i8G65rmVagqKMtkk=
 google.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE=
 google.golang.org/api v0.7.0/go.mod h1:WtwebWUNSVBH/HAw79HIFXZNqEvBhG+Ra+ax0hx3E3M=
 google.golang.org/api v0.8.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg=
@@ -1185,50 +1012,79 @@ google.golang.org/api v0.9.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEn
 google.golang.org/api v0.13.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI=
 google.golang.org/api v0.14.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI=
 google.golang.org/api v0.15.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI=
-google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM=
-google.golang.org/appengine v1.2.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
+google.golang.org/api v0.17.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE=
+google.golang.org/api v0.18.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE=
+google.golang.org/api v0.19.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE=
+google.golang.org/api v0.20.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE=
+google.golang.org/api v0.22.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE=
+google.golang.org/api v0.24.0/go.mod h1:lIXQywCXRcnZPGlsd8NbLnOjtAoL6em04bJ9+z0MncE=
+google.golang.org/api v0.28.0/go.mod h1:lIXQywCXRcnZPGlsd8NbLnOjtAoL6em04bJ9+z0MncE=
+google.golang.org/api v0.29.0/go.mod h1:Lcubydp8VUV7KeIHD9z2Bys/sm/vGKnG1UHuDBSrHWM=
+google.golang.org/api v0.30.0/go.mod h1:QGmEvQ87FHZNiUVJkT14jQNYJ4ZJjdRF23ZXz5138Fc=
+google.golang.org/api v0.35.0/go.mod h1:/XrVsuzM0rZmrsbjJutiuftIzeuTQcEeaYcSk/mQ1dg=
+google.golang.org/api v0.36.0/go.mod h1:+z5ficQTmoYpPn8LCUNVpK5I7hwkpjbcgqA7I34qYtE=
+google.golang.org/api v0.40.0/go.mod h1:fYKFpnQN0DsDSKRVRcQSDQNtqWPfM9i+zNPxepjRCQ8=
+google.golang.org/api v0.41.0/go.mod h1:RkxM5lITDfTzmyKFPt+wGrCJbVfniCr2ool8kTBzRTU=
+google.golang.org/api v0.43.0/go.mod h1:nQsDGjRXMo4lvh5hP0TKqF244gqhGcr/YSIykhUk/94=
+google.golang.org/api v0.44.0/go.mod h1:EBOGZqzyhtvMDoxwS97ctnh0zUmYY6CxqXsc1AvkYD8=
+google.golang.org/appengine v1.0.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM=
 google.golang.org/appengine v1.3.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
 google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
 google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
 google.golang.org/appengine v1.6.1/go.mod h1:i06prIuMbXzDqacNJfV5OdTW448YApPu5ww/cMBSeb0=
-google.golang.org/appengine v1.6.5 h1:tycE03LOZYQNhDpS27tcQdAzLCVMaj7QT2SXxebnpCM=
 google.golang.org/appengine v1.6.5/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc=
+google.golang.org/appengine v1.6.6/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc=
+google.golang.org/appengine v1.6.7 h1:FZR1q0exgwxzPzp/aF+VccGrSfxfPpkBqjIIEq3ru6c=
+google.golang.org/appengine v1.6.7/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc=
 google.golang.org/cloud v0.0.0-20151119220103-975617b05ea8/go.mod h1:0H1ncTHf11KCFhTc/+EFRbzSCOZx+VUbRMk55Yv5MYk=
 google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
 google.golang.org/genproto v0.0.0-20190307195333-5fe7a883aa19/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
-google.golang.org/genproto v0.0.0-20190404172233-64821d5d2107/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
 google.golang.org/genproto v0.0.0-20190418145605-e7d98fc518a7/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
 google.golang.org/genproto v0.0.0-20190425155659-357c62f0e4bb/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
 google.golang.org/genproto v0.0.0-20190502173448-54afdca5d873/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
-google.golang.org/genproto v0.0.0-20190530194941-fb225487d101/go.mod h1:z3L6/3dTEVtUr6QSP8miRzeRqwQOioJ9I66odjN4I7s=
-google.golang.org/genproto v0.0.0-20190716160619-c506a9f90610/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc=
 google.golang.org/genproto v0.0.0-20190801165951-fa694d86fc64/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc=
 google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc=
 google.golang.org/genproto v0.0.0-20190911173649-1774047e7e51/go.mod h1:IbNlFCBrqXvoKpeg0TB2l7cyZUmoaFKYIwrEpbDKLA8=
-google.golang.org/genproto v0.0.0-20190927181202-20e1ac93f88c/go.mod h1:IbNlFCBrqXvoKpeg0TB2l7cyZUmoaFKYIwrEpbDKLA8=
 google.golang.org/genproto v0.0.0-20191108220845-16a3f7862a1a/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
 google.golang.org/genproto v0.0.0-20191115194625-c23dd37a84c9/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
+google.golang.org/genproto v0.0.0-20191216164720-4f79533eabd1/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
 google.golang.org/genproto v0.0.0-20191230161307-f3c370f40bfb/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
-google.golang.org/genproto v0.0.0-20200117163144-32f20d992d24/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
-google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013 h1:+kGHl1aib/qcwaRi1CbqBZ1rk19r85MNUf8HaBghugY=
+google.golang.org/genproto v0.0.0-20200115191322-ca5a22157cba/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
+google.golang.org/genproto v0.0.0-20200122232147-0452cf42e150/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
+google.golang.org/genproto v0.0.0-20200204135345-fa8e72b47b90/go.mod h1:GmwEX6Z4W5gMy59cAlVYjN9JhxgbQH6Gn+gFDQe2lzA=
+google.golang.org/genproto v0.0.0-20200212174721-66ed5ce911ce/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
+google.golang.org/genproto v0.0.0-20200224152610-e50cd9704f63/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
+google.golang.org/genproto v0.0.0-20200228133532-8c2c7df3a383/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
+google.golang.org/genproto v0.0.0-20200305110556-506484158171/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
+google.golang.org/genproto v0.0.0-20200312145019-da6875a35672/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
+google.golang.org/genproto v0.0.0-20200331122359-1ee6d9798940/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
+google.golang.org/genproto v0.0.0-20200423170343-7949de9c1215/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
+google.golang.org/genproto v0.0.0-20200430143042-b979b6f78d84/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
+google.golang.org/genproto v0.0.0-20200511104702-f5ebc3bea380/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
+google.golang.org/genproto v0.0.0-20200513103714-09dca8ec2884/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
+google.golang.org/genproto v0.0.0-20200515170657-fc4c6c6a6587/go.mod h1:YsZOwe1myG/8QRHRsmBRE1LrgQY60beZKjly0O1fX9U=
 google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo=
-google.golang.org/grpc v0.0.0-20160317175043-d3ddb4469d5a/go.mod h1:yo6s7OP7yaDglbqo1J04qKzAhqBH6lvTonzMVmEdcZw=
-google.golang.org/grpc v1.17.0/go.mod h1:6QZJwpn2B+Zp71q/5VxRsJ6NXXVCE5NRUHRo+f3cWCs=
-google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
-google.golang.org/grpc v1.20.0/go.mod h1:chYK+tFQF0nDUGJgXMSgLCQk3phJEuONr2DCgLDdAQM=
-google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38=
-google.golang.org/grpc v1.21.0/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM=
-google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM=
-google.golang.org/grpc v1.22.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg=
-google.golang.org/grpc v1.22.1/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg=
-google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg=
-google.golang.org/grpc v1.23.1/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg=
-google.golang.org/grpc v1.24.0/go.mod h1:XDChyiUovWa60DnaeDeZmSW86xtLtjtZbwvSiRnRtcA=
-google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY=
-google.golang.org/grpc v1.26.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk=
-google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk=
-google.golang.org/grpc v1.28.0 h1:bO/TA4OxCOummhSf10siHuG7vJOiwh7SpRpFZDkOgl4=
-google.golang.org/grpc v1.28.0/go.mod h1:rpkK4SK4GF4Ach/+MFLZUBavHOvF2JJB5uozKKal+60=
+google.golang.org/genproto v0.0.0-20200618031413-b414f8b61790/go.mod h1:jDfRM7FcilCzHH/e9qn6dsT145K34l5v+OpcnNgKAAA=
+google.golang.org/genproto v0.0.0-20200729003335-053ba62fc06f/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
+google.golang.org/genproto v0.0.0-20200804131852-c06518451d9c/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
+google.golang.org/genproto v0.0.0-20200825200019-8632dd797987/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
+google.golang.org/genproto v0.0.0-20200904004341-0bd0a958aa1d/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
+google.golang.org/genproto v0.0.0-20201019141844-1ed22bb0c154/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
+google.golang.org/genproto v0.0.0-20201102152239-715cce707fb0/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
+google.golang.org/genproto v0.0.0-20201109203340-2640f1f9cdfb/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
+google.golang.org/genproto v0.0.0-20201201144952-b05cb90ed32e/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
+google.golang.org/genproto v0.0.0-20201210142538-e3217bee35cc/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
+google.golang.org/genproto v0.0.0-20201214200347-8c77b98c765d/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
+google.golang.org/genproto v0.0.0-20210222152913-aa3ee6e6a81c/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
+google.golang.org/genproto v0.0.0-20210303154014-9728d6b83eeb/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
+google.golang.org/genproto v0.0.0-20210310155132-4ce2db91004e/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
+google.golang.org/genproto v0.0.0-20210319143718-93e7006c17a6/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
+google.golang.org/genproto v0.0.0-20210402141018-6c239bbf2bb1/go.mod h1:9lPAdzaEmUacj36I+k7YKbEc5CXzPIeORRgDAUOu28A=
+google.golang.org/genproto v0.0.0-20210602131652-f16073e35f0c/go.mod h1:UODoCrxHCcBojKKwX1terBiRUaqAsFqJiF615XL43r0=
+google.golang.org/genproto v0.0.0-20210831024726-fe130286e0e2 h1:NHN4wOCScVzKhPenJ2dt+BTs3X/XkBVI/Rh4iDt55T8=
+google.golang.org/genproto v0.0.0-20210831024726-fe130286e0e2/go.mod h1:eFjDcFEctNawg4eG61bRv87N7iHBWyVhJu7u1kqDUXY=
+google.golang.org/grpc v1.29.0 h1:2pJjwYOdkZ9HlN4sWRYBg9ttH5bCOlsueaM+b/oYjwo=
+google.golang.org/grpc v1.29.0/go.mod h1:itym6AZVZYACWQqET3MqgPpjcuV5QH3BxFS3IjizoKk=
 google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8=
 google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0=
 google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM=
@@ -1237,120 +1093,130 @@ google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzi
 google.golang.org/protobuf v1.22.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
 google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
 google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
-google.golang.org/protobuf v1.24.0 h1:UhZDfRO8JRQru4/+LlLE0BRKGF8L+PICnvYZmx/fEGA=
 google.golang.org/protobuf v1.24.0/go.mod h1:r/3tXBNzIEhYS9I1OUVjXDlt8tc493IdKGjtUeSXeh4=
-gopkg.in/airbrake/gobrake.v2 v2.0.9/go.mod h1:/h5ZAUhDkGaJfjzjKLSjv6zCL6O0LLBxU4K+aSYdM/U=
+google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c=
+google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw=
+google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
+google.golang.org/protobuf v1.27.1 h1:SnqbnDw1V7RiZcXPx5MEeqPv2s79L9i7BJUlG/+RurQ=
+google.golang.org/protobuf v1.27.1/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
 gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw=
 gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
 gopkg.in/check.v1 v1.0.0-20141024133853-64131543e789/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
 gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
-gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15 h1:YR8cESwS4TdDjEe65xsg0ogRM/Nc3DYOhEAlW+xobZo=
 gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
+gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
+gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
+gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=
 gopkg.in/cheggaaa/pb.v1 v1.0.25/go.mod h1:V/YB90LKu/1FcN3WVnfiiE5oMCibMjukxqG/qStrOgw=
 gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI=
-gopkg.in/fsnotify.v1 v1.4.7 h1:xOHLXZwVvI9hhs+cLKq5+I5onOuwQLhQwiu63xxlHs4=
 gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys=
-gopkg.in/fsnotify/fsnotify.v1 v1.4.7/go.mod h1:Fyux9zXlo4rWoMSIzpn9fDAYjalPqJ/K1qJ27s+7ltE=
-gopkg.in/gcfg.v1 v1.2.3/go.mod h1:yesOnuUOFQAhST5vPY4nbZsb/huCgGGXlipJsBn0b3o=
-gopkg.in/gemnasium/logrus-airbrake-hook.v2 v2.1.2/go.mod h1:Xk6kEKp8OKb+X14hQBKWaSkCsqBpgog8nAV2xsGOxlo=
-gopkg.in/gorp.v1 v1.7.2/go.mod h1:Wo3h+DBQZIxATwftsglhdD/62zRFPhGhTiu5jUJmCaw=
-gopkg.in/imdario/mergo.v0 v0.3.7/go.mod h1:9qPP6AGrlC1G2PTNXko614FwGZvorN7MiBU0Eppok+U=
 gopkg.in/inf.v0 v0.9.1 h1:73M5CoZyi3ZLMOyDlQh031Cx6N9NDJ2Vvfl76EDAgDc=
 gopkg.in/inf.v0 v0.9.1/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw=
-gopkg.in/ini.v1 v1.42.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
 gopkg.in/ini.v1 v1.51.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
+gopkg.in/ini.v1 v1.62.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
 gopkg.in/natefinch/lumberjack.v2 v2.0.0/go.mod h1:l0ndWWf7gzL7RNwBG7wST/UCcT4T24xpD6X8LsfU/+k=
-gopkg.in/op/go-logging.v1 v1.0.0-20160211212156-b2cb9fa56473/go.mod h1:N1eN2tsCx0Ydtgjl4cqmbRCsY4/+z4cYDeqwZTk6zog=
 gopkg.in/resty.v1 v1.12.0/go.mod h1:mDo4pnntr5jdWRML875a/NmxYqAlA73dVijT2AXvQQo=
 gopkg.in/square/go-jose.v2 v2.2.2/go.mod h1:M9dMgbHiYLoDGQrXy7OpJDJWiKiU//h+vD76mk0e1AI=
 gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ=
 gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw=
 gopkg.in/warnings.v0 v0.1.2/go.mod h1:jksf8JmL6Qr/oQM2OXTHunEvvTAsrWBLb6OOjuVWRNI=
 gopkg.in/yaml.v2 v2.0.0-20170812160011-eb3733d160e7/go.mod h1:JAlM8MvJe8wmxCU4Bli9HhUf9+ttbYbLASfIpnQbh74=
-gopkg.in/yaml.v2 v2.1.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
 gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
 gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
 gopkg.in/yaml.v2 v2.2.3/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
 gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
 gopkg.in/yaml.v2 v2.2.5/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
 gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
-gopkg.in/yaml.v2 v2.3.0 h1:clyUAQHOM3G0M3f5vQj7LuJrETvjVot3Z5el9nffUtU=
 gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
-gopkg.in/yaml.v3 v3.0.0-20190905181640-827449938966/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
-gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c h1:dUUwHk2QECo/6vqA44rthZ8ie2QXMNeKRTHCNY2nXvo=
+gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY=
+gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
 gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
-gotest.tools v2.2.0+incompatible/go.mod h1:DsYFclhRJ6vuDpmuTbkuFWG+y2sxOXAzmJt81HFBacw=
+gopkg.in/yaml.v3 v3.0.0-20200615113413-eeeca48fe776/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
+gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b h1:h8qDotaEPuJATrMmW04NCwg7v22aHH28wwpauUhK9Oo=
+gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
 gotest.tools/v3 v3.0.2/go.mod h1:3SzNCllyD9/Y+b5r9JIKQ474KzkZyqLqEfYqMsX94Bk=
+gotest.tools/v3 v3.0.3 h1:4AuOwCGf4lLR9u3YOe2awrHygurzhO/HeQ6laiA6Sx0=
 gotest.tools/v3 v3.0.3/go.mod h1:Z7Lb0S5l+klDB31fvDQX8ss/FlKDxtlFlw3Oa8Ymbl8=
-helm.sh/helm/v3 v3.5.3/go.mod h1:Tv6yZjudrwek+Jhm0DSjZgM1zzPhkhd7avb7tc3lIwU=
-honnef.co/go/tools v0.0.0-20180728063816-88497007e858/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
 honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
 honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
 honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
 honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
-honnef.co/go/tools v0.0.1-2019.2.3 h1:3JgtbtFHMiCmsznwGVTUWbgGov+pVqnlf1dEJTNAXeM=
 honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg=
-howett.net/plist v0.0.0-20181124034731-591f970eefbb/go.mod h1:vMygbs4qMhSZSc4lCUl2OEE+rDiIIJAIdR4m7MiMcm0=
-k8s.io/api v0.19.4 h1:I+1I4cgJYuCDgiLNjKx7SLmIbwgj9w7N7Zr5vSIdwpo=
-k8s.io/api v0.19.4/go.mod h1:SbtJ2aHCItirzdJ36YslycFNzWADYH3tgOhvBEFtZAk=
-k8s.io/apiextensions-apiserver v0.19.4 h1:D9ak9T012tb3vcGFWYmbQuj9SCC8YM4zhA4XZqsAQC4=
-k8s.io/apiextensions-apiserver v0.19.4/go.mod h1:B9rpH/nu4JBCtuUp3zTTk8DEjZUupZTBEec7/2zNRYw=
-k8s.io/apimachinery v0.19.4 h1:+ZoddM7nbzrDCp0T3SWnyxqf8cbWPT2fkZImoyvHUG0=
-k8s.io/apimachinery v0.19.4/go.mod h1:DnPGDnARWFvYa3pMHgSxtbZb7gpzzAZ1pTfaUNDVlmA=
-k8s.io/apiserver v0.19.4/go.mod h1:X8WRHCR1UGZDd7HpV0QDc1h/6VbbpAeAGyxSh8yzZXw=
-k8s.io/autoscaler v0.0.0-20190607113959-1b4f1855cb8e/go.mod h1:QEXezc9uKPT91dwqhSJq3GNI3B1HxFRQHiku9kmrsSA=
-k8s.io/cli-runtime v0.19.4 h1:FPpoqFbWsFzRbZNRI+o/+iiLFmWMYTmBueIj3OaNVTI=
-k8s.io/cli-runtime v0.19.4/go.mod h1:m8G32dVbKOeaX1foGhleLEvNd6REvU7YnZyWn5//9rw=
-k8s.io/client-go v0.19.4 h1:85D3mDNoLF+xqpyE9Dh/OtrJDyJrSRKkHmDXIbEzer8=
-k8s.io/client-go v0.19.4/go.mod h1:ZrEy7+wj9PjH5VMBCuu/BDlvtUAku0oVFk4MmnW9mWA=
-k8s.io/code-generator v0.19.4/go.mod h1:moqLn7w0t9cMs4+5CQyxnfA/HV8MF6aAVENF+WZZhgk=
-k8s.io/component-base v0.19.4/go.mod h1:ZzuSLlsWhajIDEkKF73j64Gz/5o0AgON08FgRbEPI70=
-k8s.io/gengo v0.0.0-20190128074634-0689ccc1d7d6/go.mod h1:ezvh/TsK7cY6rbqRK0oQQ8IAqLxYwwyPxAX1Pzy0ii0=
-k8s.io/gengo v0.0.0-20200114144118-36b2048a9120/go.mod h1:ezvh/TsK7cY6rbqRK0oQQ8IAqLxYwwyPxAX1Pzy0ii0=
+honnef.co/go/tools v0.0.1-2020.1.3/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k=
+honnef.co/go/tools v0.0.1-2020.1.4/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k=
+k8s.io/api v0.23.0/go.mod h1:8wmDdLBHBNxtOIytwLstXt5E9PddnZb0GaMcqsvDBpg=
+k8s.io/api v0.23.1/go.mod h1:WfXnOnwSqNtG62Y1CdjoMxh7r7u9QXGCkA1u0na2jgo=
+k8s.io/api v0.23.2/go.mod h1:sYuDb3flCtRPI8ghn6qFrcK5ZBu2mhbElxRE95qpwlI=
+k8s.io/api v0.23.3 h1:KNrME8KHGr12Ozjf8ytOewKzZh6hl/hHUZeHddT3a38=
+k8s.io/api v0.23.3/go.mod h1:w258XdGyvCmnBj/vGzQMj6kzdufJZVUwEM1U2fRJwSQ=
+k8s.io/apiextensions-apiserver v0.23.0/go.mod h1:xIFAEEDlAZgpVBl/1VSjGDmLoXAWRG40+GsWhKhAxY4=
+k8s.io/apiextensions-apiserver v0.23.2/go.mod h1:9cs7avT6+GfzbB0pambTvH11wcaR85QQg4ovl9s15UU=
+k8s.io/apiextensions-apiserver v0.23.3 h1:JvPJA7hSEAqMRteveq4aj9semilAZYcJv+9HHFWfUdM=
+k8s.io/apiextensions-apiserver v0.23.3/go.mod h1:/ZpRXdgKZA6DvIVPEmXDCZJN53YIQEUDF+hrpIQJL38=
+k8s.io/apimachinery v0.23.0/go.mod h1:fFCTTBKvKcwTPFzjlcxp91uPFZr+JA0FubU4fLzzFYc=
+k8s.io/apimachinery v0.23.1/go.mod h1:SADt2Kl8/sttJ62RRsi9MIV4o8f5S3coArm0Iu3fBno=
+k8s.io/apimachinery v0.23.2/go.mod h1:zDqeV0AK62LbCI0CI7KbWCAYdLg+E+8UXJ0rIz5gmS8=
+k8s.io/apimachinery v0.23.3 h1:7IW6jxNzrXTsP0c8yXz2E5Yx/WTzVPTsHIx/2Vm0cIk=
+k8s.io/apimachinery v0.23.3/go.mod h1:BEuFMMBaIbcOqVIJqNZJXGFTP4W6AycEpb5+m/97hrM=
+k8s.io/apiserver v0.23.0/go.mod h1:Cec35u/9zAepDPPFyT+UMrgqOCjgJ5qtfVJDxjZYmt4=
+k8s.io/apiserver v0.23.2/go.mod h1:Kdt8gafkPev9Gfh+H6lCPbmRu42f7BfhOfHKKa3dtyU=
+k8s.io/apiserver v0.23.3/go.mod h1:3HhsTmC+Pn+Jctw+Ow0LHA4dQ4oXrQ4XJDzrVDG64T4=
+k8s.io/cli-runtime v0.23.3 h1:aJiediw+uUbxkfO6BNulcAMTUoU9Om43g3R7rIkYqcw=
+k8s.io/cli-runtime v0.23.3/go.mod h1:yA00O5pDqnjkBh8fkuugBbfIfjB1nOpz+aYLotbnOfc=
+k8s.io/client-go v0.23.0/go.mod h1:hrDnpnK1mSr65lHHcUuIZIXDgEbzc7/683c6hyG4jTA=
+k8s.io/client-go v0.23.1/go.mod h1:6QSI8fEuqD4zgFK0xbdwfB/PthBsIxCJMa3s17WlcO0=
+k8s.io/client-go v0.23.2/go.mod h1:k3YbsWg6GWdHF1THHTQP88X9RhB1DWPo3Dq7KfU/D1c=
+k8s.io/client-go v0.23.3 h1:23QYUmCQ/W6hW78xIwm3XqZrrKZM+LWDqW2zfo+szJs=
+k8s.io/client-go v0.23.3/go.mod h1:47oMd+YvAOqZM7pcQ6neJtBiFH7alOyfunYN48VsmwE=
+k8s.io/code-generator v0.23.0/go.mod h1:vQvOhDXhuzqiVfM/YHp+dmg10WDZCchJVObc9MvowsE=
+k8s.io/code-generator v0.23.2/go.mod h1:S0Q1JVA+kSzTI1oUvbKAxZY/DYbA/ZUb4Uknog12ETk=
+k8s.io/code-generator v0.23.3/go.mod h1:S0Q1JVA+kSzTI1oUvbKAxZY/DYbA/ZUb4Uknog12ETk=
+k8s.io/component-base v0.23.0/go.mod h1:DHH5uiFvLC1edCpvcTDV++NKULdYYU6pR9Tt3HIKMKI=
+k8s.io/component-base v0.23.2/go.mod h1:wS9Z03MO3oJ0RU8bB/dbXTiluGju+SC/F5i660gxB8c=
+k8s.io/component-base v0.23.3 h1:q+epprVdylgecijVGVdf4MbizEL2feW4ssd7cdo6LVY=
+k8s.io/component-base v0.23.3/go.mod h1:1Smc4C60rWG7d3HjSYpIwEbySQ3YWg0uzH5a2AtaTLg=
+k8s.io/component-helpers v0.23.3/go.mod h1:SH+W/WPTaTenbWyDEeY7iytAQiMh45aqKxkvlqQ57cg=
 k8s.io/gengo v0.0.0-20200413195148-3a45101e95ac/go.mod h1:ezvh/TsK7cY6rbqRK0oQQ8IAqLxYwwyPxAX1Pzy0ii0=
-k8s.io/gengo v0.0.0-20200428234225-8167cfdcfc14/go.mod h1:ezvh/TsK7cY6rbqRK0oQQ8IAqLxYwwyPxAX1Pzy0ii0=
-k8s.io/klog v0.0.0-20181102134211-b9b56d5dfc92/go.mod h1:Gq+BEi5rUBO/HRz0bTSXDUcqjScdoY3a9IHpCEIOOfk=
-k8s.io/klog v0.3.0/go.mod h1:Gq+BEi5rUBO/HRz0bTSXDUcqjScdoY3a9IHpCEIOOfk=
-k8s.io/klog v0.3.3/go.mod h1:Gq+BEi5rUBO/HRz0bTSXDUcqjScdoY3a9IHpCEIOOfk=
-k8s.io/klog v0.4.0/go.mod h1:4Bi6QPql/J/LkTDqv7R/cd3hPo4k2DG6Ptcz060Ez5I=
-k8s.io/klog v1.0.0 h1:Pt+yjF5aB1xDSVbau4VsWe+dQNzA0qv1LlXdC2dF6Q8=
-k8s.io/klog v1.0.0/go.mod h1:4Bi6QPql/J/LkTDqv7R/cd3hPo4k2DG6Ptcz060Ez5I=
+k8s.io/gengo v0.0.0-20210813121822-485abfe95c7c/go.mod h1:FiNAH4ZV3gBg2Kwh89tzAEV2be7d5xI0vBa/VySYy3E=
 k8s.io/klog/v2 v2.0.0/go.mod h1:PBfzABfn139FHAV07az/IF9Wp1bkk3vpT2XSJ76fSDE=
 k8s.io/klog/v2 v2.2.0/go.mod h1:Od+F08eJP+W3HUb4pSrPpgp9DGU4GzlpG/TmITuYh/Y=
-k8s.io/klog/v2 v2.4.0 h1:7+X0fUguPyrKEC4WjH8iGDg3laWgMo5tMnRTIGTTxGQ=
-k8s.io/klog/v2 v2.4.0/go.mod h1:Od+F08eJP+W3HUb4pSrPpgp9DGU4GzlpG/TmITuYh/Y=
-k8s.io/kube-openapi v0.0.0-20190320154901-5e45bb682580/go.mod h1:BXM9ceUBTj2QnfH2MK1odQs778ajze1RxcmP6S8RVVc=
-k8s.io/kube-openapi v0.0.0-20191107075043-30be4d16710a/go.mod h1:1TqjTSzOxsLGIKfj0lK8EeCP7K1iUG65v09OM0/WG5E=
-k8s.io/kube-openapi v0.0.0-20200805222855-6aeccd4b50c6/go.mod h1:UuqjUnNftUyPE5H64/qeyjQoUZhGpeFDVdxjTeEVN2o=
-k8s.io/kube-openapi v0.0.0-20201113171705-d219536bb9fd h1:sOHNzJIkytDF6qadMNKhhDRpc6ODik8lVC6nOur7B2c=
-k8s.io/kube-openapi v0.0.0-20201113171705-d219536bb9fd/go.mod h1:WOJ3KddDSol4tAGcJo0Tvi+dK12EcqSLqcWsryKMpfM=
-k8s.io/kube-state-metrics v1.7.2/go.mod h1:U2Y6DRi07sS85rmVPmBFlmv+2peBcL8IWGjM+IjYA/E=
-k8s.io/kubectl v0.19.4 h1:XFrHibf5fS4Ot8h3EnzdVsKrYj+pndlzKbwPkfra5hI=
-k8s.io/kubectl v0.19.4/go.mod h1:XPmlu4DJEYgD83pvZFeKF8+MSvGnYGqunbFSrJsqHv0=
-k8s.io/metrics v0.19.4/go.mod h1:a0gvAzrxQPw2ouBqnXI7X9qlggpPkKAFgWU/Py+KZiU=
-k8s.io/utils v0.0.0-20190308190857-21c4ce38f2a7/go.mod h1:8k8uAuAQ0rXslZKaEWd0c3oVhZz7sSzSiPnVZayjIX0=
-k8s.io/utils v0.0.0-20190801114015-581e00157fb1/go.mod h1:sZAwmy6armz5eXlNoLmJcl4F1QuKu7sr+mFQ0byX7Ew=
-k8s.io/utils v0.0.0-20191114200735-6ca3b61696b6/go.mod h1:sZAwmy6armz5eXlNoLmJcl4F1QuKu7sr+mFQ0byX7Ew=
-k8s.io/utils v0.0.0-20200324210504-a9aa75ae1b89/go.mod h1:sZAwmy6armz5eXlNoLmJcl4F1QuKu7sr+mFQ0byX7Ew=
-k8s.io/utils v0.0.0-20200729134348-d5654de09c73 h1:uJmqzgNWG7XyClnU/mLPBWwfKKF1K8Hf8whTseBgJcg=
-k8s.io/utils v0.0.0-20200729134348-d5654de09c73/go.mod h1:jPW/WVKK9YHAvNhRxK0md/EJ228hCsBRufyofKtW8HA=
+k8s.io/klog/v2 v2.30.0 h1:bUO6drIvCIsvZ/XFgfxoGFQU/a4Qkh0iAlvUR7vlHJw=
+k8s.io/klog/v2 v2.30.0/go.mod h1:y1WjHnz7Dj687irZUWR/WLkLc5N1YHtjLdmgWjndZn0=
+k8s.io/kube-openapi v0.0.0-20210421082810-95288971da7e/go.mod h1:vHXdDvt9+2spS2Rx9ql3I8tycm3H9FDfdUoIuKCefvw=
+k8s.io/kube-openapi v0.0.0-20211115234752-e816edb12b65/go.mod h1:sX9MT8g7NVZM5lVL/j8QyCCJe8YSMW30QvGZWaCIDIk=
+k8s.io/kube-openapi v0.0.0-20220124234850-424119656bbf h1:M9XBsiMslw2lb2ZzglC0TOkBPK5NQi0/noUrdnoFwUg=
+k8s.io/kube-openapi v0.0.0-20220124234850-424119656bbf/go.mod h1:sX9MT8g7NVZM5lVL/j8QyCCJe8YSMW30QvGZWaCIDIk=
+k8s.io/kubectl v0.23.3 h1:gJsF7cahkWDPYlNvYKK+OrBZLAJUBzCym+Zsi+dfi1E=
+k8s.io/kubectl v0.23.3/go.mod h1:VBeeXNgLhSabu4/k0O7Q0YujgnA3+CLTUE0RcmF73yY=
+k8s.io/metrics v0.23.3/go.mod h1:Ut8TvkbsO4oMVeUzaTArvPrcw9QRFLs2XNzUlORjdYE=
+k8s.io/utils v0.0.0-20210802155522-efc7438f0176/go.mod h1:jPW/WVKK9YHAvNhRxK0md/EJ228hCsBRufyofKtW8HA=
+k8s.io/utils v0.0.0-20210930125809-cb0fa318a74b/go.mod h1:jPW/WVKK9YHAvNhRxK0md/EJ228hCsBRufyofKtW8HA=
+k8s.io/utils v0.0.0-20211116205334-6203023598ed/go.mod h1:jPW/WVKK9YHAvNhRxK0md/EJ228hCsBRufyofKtW8HA=
+k8s.io/utils v0.0.0-20211208161948-7d6a63dca704 h1:ZKMMxTvduyf5WUtREOqg5LiXaN1KO/+0oOQPRFrClpo=
+k8s.io/utils v0.0.0-20211208161948-7d6a63dca704/go.mod h1:jPW/WVKK9YHAvNhRxK0md/EJ228hCsBRufyofKtW8HA=
 rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8=
-rsc.io/letsencrypt v0.0.3/go.mod h1:buyQKZ6IXrRnB7TdkHP0RyEybLx18HHyOSoTyoOLqNY=
-sigs.k8s.io/apiserver-network-proxy/konnectivity-client v0.0.9/go.mod h1:dzAXnQbTRyDlZPJX2SUPEqvnB+j7AJjtlox7PEwigU0=
-sigs.k8s.io/controller-runtime v0.6.0 h1:Fzna3DY7c4BIP6KwfSlrfnj20DJ+SeMBK8HSFvOk9NM=
-sigs.k8s.io/controller-runtime v0.6.0/go.mod h1:CpYf5pdNY/B352A1TFLAS2JVSlnGQ5O2cftPHndTroo=
-sigs.k8s.io/controller-tools v0.2.4/go.mod h1:m/ztfQNocGYBgTTCmFdnK94uVvgxeZeE3LtJvd/jIzA=
-sigs.k8s.io/controller-tools v0.3.0/go.mod h1:enhtKGfxZD1GFEoMgP8Fdbu+uKQ/cq1/WGJhdVChfvI=
-sigs.k8s.io/kubebuilder v1.0.9-0.20200618125005-36aa113dbe99/go.mod h1:FGPx0hvP73+bapzWoy5ePuhAJYgJjrFbPxgvWyortM0=
-sigs.k8s.io/kustomize v2.0.3+incompatible h1:JUufWFNlI44MdtnjUqVnvh29rR37PQFzPbLXqhyOyX0=
-sigs.k8s.io/kustomize v2.0.3+incompatible/go.mod h1:MkjgH3RdOWrievjo6c9T245dYlB5QeXV4WCbnt/PEpU=
-sigs.k8s.io/structured-merge-diff v0.0.0-20190525122527-15d366b2352e h1:4Z09Hglb792X0kfOBBJUPFEyvVfQWrYT/l8h5EKA6JQ=
-sigs.k8s.io/structured-merge-diff v0.0.0-20190525122527-15d366b2352e/go.mod h1:wWxsB5ozmmv/SG7nM11ayaAW51xMvak/t1r0CSlcokI=
-sigs.k8s.io/structured-merge-diff/v4 v4.0.1/go.mod h1:bJZC9H9iH24zzfZ/41RGcq60oK1F7G282QMXDPYydCw=
-sigs.k8s.io/structured-merge-diff/v4 v4.0.2 h1:YHQV7Dajm86OuqnIR6zAelnDWBRjo+YhYV9PmGrh1s8=
+rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0=
+rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA=
+sigs.k8s.io/apiserver-network-proxy/konnectivity-client v0.0.25/go.mod h1:Mlj9PNLmG9bZ6BHFwFKDo5afkpWyUISkb9Me0GnK66I=
+sigs.k8s.io/apiserver-network-proxy/konnectivity-client v0.0.27/go.mod h1:tq2nT0Kx7W+/f2JVE+zxYtUhdjuELJkVpNz+x/QN5R4=
+sigs.k8s.io/controller-runtime v0.11.0/go.mod h1:KKwLiTooNGu+JmLZGn9Sl3Gjmfj66eMbCQznLP5zcqA=
+sigs.k8s.io/controller-runtime v0.11.1 h1:7YIHT2QnHJArj/dk9aUkYhfqfK5cIxPOX5gPECfdZLU=
+sigs.k8s.io/controller-runtime v0.11.1/go.mod h1:KKwLiTooNGu+JmLZGn9Sl3Gjmfj66eMbCQznLP5zcqA=
+sigs.k8s.io/json v0.0.0-20211020170558-c049b76a60c6/go.mod h1:p4QtZmO4uMYipTQNzagwnNoseA6OxSUutVw05NhYDRs=
+sigs.k8s.io/json v0.0.0-20211208200746-9f7c6b3444d2 h1:kDi4JBNAsJWfz1aEXhO8Jg87JJaPNLh5tIzYHgStQ9Y=
+sigs.k8s.io/json v0.0.0-20211208200746-9f7c6b3444d2/go.mod h1:B+TnT182UBxE84DiCz4CVE26eOSDAeYCpfDnC2kdKMY=
+sigs.k8s.io/kustomize/api v0.10.1 h1:KgU7hfYoscuqag84kxtzKdEC3mKMb99DPI3a0eaV1d0=
+sigs.k8s.io/kustomize/api v0.10.1/go.mod h1:2FigT1QN6xKdcnGS2Ppp1uIWrtWN28Ms8A3OZUZhwr8=
+sigs.k8s.io/kustomize/cmd/config v0.10.2/go.mod h1:K2aW7nXJ0AaT+VA/eO0/dzFLxmpFcTzudmAgDwPY1HQ=
+sigs.k8s.io/kustomize/kustomize/v4 v4.4.1/go.mod h1:qOKJMMz2mBP+vcS7vK+mNz4HBLjaQSWRY22EF6Tb7Io=
+sigs.k8s.io/kustomize/kyaml v0.13.0 h1:9c+ETyNfSrVhxvphs+K2dzT3dh5oVPPEqPOE/cUpScY=
+sigs.k8s.io/kustomize/kyaml v0.13.0/go.mod h1:FTJxEZ86ScK184NpGSAQcfEqee0nul8oLCK30D47m4E=
 sigs.k8s.io/structured-merge-diff/v4 v4.0.2/go.mod h1:bJZC9H9iH24zzfZ/41RGcq60oK1F7G282QMXDPYydCw=
+sigs.k8s.io/structured-merge-diff/v4 v4.1.2/go.mod h1:j/nl6xW8vLS49O8YvXW1ocPhZawJtm+Yrr7PPRQ0Vg4=
+sigs.k8s.io/structured-merge-diff/v4 v4.2.0/go.mod h1:j/nl6xW8vLS49O8YvXW1ocPhZawJtm+Yrr7PPRQ0Vg4=
+sigs.k8s.io/structured-merge-diff/v4 v4.2.1 h1:bKCqE9GvQ5tiVHn5rfn1r+yao3aLQEaLzkkmAkf+A6Y=
+sigs.k8s.io/structured-merge-diff/v4 v4.2.1/go.mod h1:j/nl6xW8vLS49O8YvXW1ocPhZawJtm+Yrr7PPRQ0Vg4=
 sigs.k8s.io/yaml v1.1.0/go.mod h1:UJmg0vDUVViEyp3mgSv9WPwZCDxu4rQW1olrI1uml+o=
-sigs.k8s.io/yaml v1.2.0 h1:kr/MCeFWJWTwyaHoR9c8EjH9OumOmoF9YGiZd7lFm/Q=
 sigs.k8s.io/yaml v1.2.0/go.mod h1:yfXDCHCao9+ENCvLSE62v9VSji2MKu5jeNfTrofGhJc=
-sourcegraph.com/sourcegraph/appdash v0.0.0-20190731080439-ebfcffb1b5c0/go.mod h1:hI742Nqp5OhwiqlzhgfbWU4mW4yO10fP+LoT9WOswdU=
-vbom.ml/util v0.0.0-20160121211510-db5cfe13f5cc/go.mod h1:so/NYdZXCz+E3ZpW0uAoCj6uzU2+8OWDFv/HxUSs7kI=
+sigs.k8s.io/yaml v1.3.0 h1:a2VclLzOGrwOHDiV8EfBGhvjHvP46CtW5j6POvhYGGo=
+sigs.k8s.io/yaml v1.3.0/go.mod h1:GeOyir5tyXNByN85N/dRIT9es5UQNerPYEKK56eTBm8=
index 304eadd..a59d3eb 100644 (file)
@@ -7,23 +7,25 @@ import (
        "context"
        "encoding/json"
 
-       "github.com/open-ness/EMCO/src/orchestrator/pkg/appcontext/subresources"
-       "github.com/open-ness/EMCO/src/orchestrator/pkg/infra/logutils"
        pkgerrors "github.com/pkg/errors"
-       certificatesv1beta1 "k8s.io/api/certificates/v1beta1"
+       "gitlab.com/project-emco/core/emco-base/src/orchestrator/pkg/appcontext/subresources"
+       "gitlab.com/project-emco/core/emco-base/src/orchestrator/pkg/infra/logutils"
+       k8scertsv1 "k8s.io/api/certificates/v1"
        metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
 )
 
 func (c *Client) Approve(name string, sa []byte) error {
 
        var a subresources.ApprovalSubresource
+
        err := json.Unmarshal(sa, &a)
        if err != nil {
                return pkgerrors.Wrap(err, "An error occurred while parsing the approval Subresource.")
        }
-       csr, err := c.Clientset.CertificatesV1beta1().CertificateSigningRequests().Get(context.TODO(), name, metav1.GetOptions{})
+
+       csr, err := c.Clientset.CertificatesV1().CertificateSigningRequests().Get(context.TODO(), name, metav1.GetOptions{})
        if err != nil {
-               return err
+               return pkgerrors.Wrap(err, "could not get the certificate")
        }
        var timePtr metav1.Time
        str := []string{a.LastUpdateTime}
@@ -31,14 +33,15 @@ func (c *Client) Approve(name string, sa []byte) error {
                return pkgerrors.Wrap(err, "An error occurred while converting time from string.")
        }
        // Update CSR with Conditions
-       csr.Status.Conditions = append(csr.Status.Conditions, certificatesv1beta1.CertificateSigningRequestCondition{
-               Type:           certificatesv1beta1.RequestConditionType(a.Type),
+       csr.Status.Conditions = append(csr.Status.Conditions, k8scertsv1.CertificateSigningRequestCondition{
+               Type:           k8scertsv1.RequestConditionType(a.Type),
                Reason:         a.Reason,
                Message:        a.Message,
                LastUpdateTime: timePtr,
+               Status:         a.Status,
        })
        // CSR Approval
-       _, err = c.Clientset.CertificatesV1beta1().CertificateSigningRequests().UpdateApproval(context.TODO(), csr, metav1.UpdateOptions{})
+       _, err = c.Clientset.CertificatesV1().CertificateSigningRequests().UpdateApproval(context.TODO(), csr.Name, csr, metav1.UpdateOptions{})
        if err != nil {
                logutils.Error("Failed to UpdateApproval", logutils.Fields{
                        "error":    err,
index bd713df..659884b 100644 (file)
@@ -33,12 +33,12 @@ func (c *Client) DeleteResource(r *resource.Result) error {
        if err := r.Err(); err != nil {
                return err
        }
-       return r.Visit(delete)
+       return r.Visit(deleteResource)
 }
 
-func delete(info *resource.Info, err error) error {
+func deleteResource(info *resource.Info, err error) error {
        if err != nil {
-               return failedTo("delete", info, err)
+               return failedTo("deleteResource", info, err)
        }
 
        // TODO: Background or Foreground?
index 2791ade..bd102f7 100644 (file)
@@ -37,7 +37,9 @@ type factory struct {
        KubeConfig            string
        Context               string
        initOpenAPIGetterOnce sync.Once
-       openAPIGetter         openapi.Getter
+       openAPIGetter         *openapi.CachedOpenAPIGetter
+       openAPIParser         *openapi.CachedOpenAPIParser
+       parser                sync.Once
 }
 
 // If multiple clients are created, this sync.once make sure the CRDs are added
@@ -265,6 +267,12 @@ func (f *factory) OpenAPISchema() (openapi.Resources, error) {
                f.openAPIGetter = openapi.NewOpenAPIGetter(discovery)
        })
 
-       // Delegate to the OpenAPIGetter
-       return f.openAPIGetter.Get()
+       // Lazily initialize the OpenAPIParser once
+       f.parser.Do(func() {
+               // Create the caching OpenAPIParser
+               f.openAPIParser = openapi.NewOpenAPIParser(f.openAPIGetter)
+       })
+
+       // Delegate to the OpenAPIPArser
+       return f.openAPIParser.Parse()
 }
index e0a92fe..94b5e4a 100644 (file)
@@ -6,7 +6,7 @@ package client
 import (
        "context"
 
-       log "github.com/open-ness/EMCO/src/orchestrator/pkg/infra/logutils"
+       log "gitlab.com/project-emco/core/emco-base/src/orchestrator/pkg/infra/logutils"
 
        corev1 "k8s.io/api/core/v1"
        metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
index f0e2e63..8608711 100644 (file)
@@ -8,7 +8,7 @@ import (
        "errors"
        "fmt"
 
-       log "github.com/open-ness/EMCO/src/orchestrator/pkg/infra/logutils"
+       log "gitlab.com/project-emco/core/emco-base/src/orchestrator/pkg/infra/logutils"
        corev1 "k8s.io/api/core/v1"
        "k8s.io/apimachinery/pkg/api/resource"
        metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
@@ -22,13 +22,11 @@ var (
 
 // GetNodeLabels .. Fetch labels published by the K8s node
 func (c *Client) GetNodeLabels(ctx context.Context) (map[string](map[string]string), error) {
-       log.Info("Get Node Labels list", nil)
-
        var nodeLabelMap = make(map[string](map[string]string))
+
        // iterate through Node Labels
        nodes, _ := c.Clientset.CoreV1().Nodes().List(ctx, metav1.ListOptions{})
        for _, node := range nodes.Items {
-               log.Info("GetNodeLabels .. Node Labels", log.Fields{"kube_cluster_name": node.GetClusterName(), "kube_node_name": node.Name, "node_labels": node.Labels})
                nodeLabelMap[node.Name] = node.Labels
        }
 
@@ -123,22 +121,26 @@ func (c *Client) GetAvailableNodeResources(ctx context.Context, resName string)
                reqs, limits, _ := c.GetPodsTotalRequestsAndLimits(ctx, podList)
                resReqs, resLimits := reqs[corev1.ResourceName(resName)], limits[corev1.ResourceName(resName)]
 
-               // availableAfterResourceReqs is Resource available after deducting active pod and system daemon Resource requests
-               // availableAfterResourceLimits is Resource available after deducting active pod and system daemon Resource limits
-               // Limit can be negative for over committed Resources
-
+               // availableAfterResourceReqs is Resource count available(after deducting active pod and system daemon Resource requests)
+               // availableAfterResourceLimits is Resource count available(after deducting active pod and system daemon Resource limits)
+               // nodeResourceMap is the map of node to Resource count available(after deducting active pod and system daemon Resource requests)
                if val, ok := node.Status.Allocatable[corev1.ResourceName(resName)]; ok {
-                       availableAfterResourceReqs += (val.Value() - resReqs.MilliValue()/1000)
-                       nodeResourceMap[node.Name] = (val.Value() - resReqs.MilliValue()/1000)
-                       availableAfterResourceLimits += (val.Value() - resLimits.MilliValue()/1000)
+                       valOrig := val
+                       val.Sub(resReqs)
+                       availableAfterResourceReqs += val.MilliValue() / 1000
+                       nodeResourceMap[node.Name] = val.MilliValue() / 1000
+                       availableAfterResourceLimits += val.MilliValue() / 1000
 
                        log.Info("GetAvailableNodeResources info => ", log.Fields{
-                               "res_name":                         resName,
-                               "node_name":                        node.Name,
-                               "cluster_name":                     node.GetClusterName(),
-                               "resAllocatedToPodsRequest(milli)": resReqs.MilliValue(),
-                               "resAllocatedToPodsLimit(milli)":   resLimits.MilliValue(),
-                               "allocatableRes(milli)":            (val.Value() * 1000)})
+                               "res_name":                  resName,
+                               "node_name":                 node.Name,
+                               "cluster_name":              node.GetClusterName(),
+                               "resAllocatedRequests":      valOrig,
+                               "resAllocatedToPodsRequest": resReqs,
+                               "resAllocatedToPodsLimit":   resLimits,
+                               "resAllocatedFinalRequests": val,
+                               "nodeResourceMap":           nodeResourceMap,
+                       })
                }
        }
 
index 5d1afc8..2746b17 100644 (file)
@@ -4,68 +4,39 @@
 package connector
 
 import (
-       "encoding/base64"
        "errors"
        "fmt"
        "os"
-       "strings"
        "sync"
+       //types "gitlab.com/project-emco/core/emco-base/src/rsync/pkg/types"
 
-       log "github.com/open-ness/EMCO/src/orchestrator/pkg/infra/logutils"
-       kubeclient "github.com/open-ness/EMCO/src/rsync/pkg/client"
-       "github.com/open-ness/EMCO/src/rsync/pkg/db"
-       pkgerrors "github.com/pkg/errors"
+       log "gitlab.com/project-emco/core/emco-base/src/orchestrator/pkg/infra/logutils"
+       kubeclient "gitlab.com/project-emco/core/emco-base/src/rsync/pkg/client"
+       "gitlab.com/project-emco/core/emco-base/src/rsync/pkg/internal/utils"
 )
 
 // IsTestKubeClient .. global variable used during unit-tests to check whether a fake kube client object has to be instantiated
 var IsTestKubeClient bool = false
 
-type Connector struct {
-       cid     string
+// Connection is for a cluster
+type Connection struct {
+       Cid     string
        Clients map[string]*kubeclient.Client
        sync.Mutex
 }
 
 const basePath string = "/tmp/rsync/"
 
-// Init connector for an app context
-func Init(id interface{}) *Connector {
-       c := make(map[string]*kubeclient.Client)
-       str := fmt.Sprintf("%v", id)
-       return &Connector{
-               Clients: c,
-               cid:     str,
-       }
-}
-
-// GetKubeConfig uses the connectivity client to get the kubeconfig based on the name
-// of the clustername.
-func GetKubeConfig(clustername string, level string, namespace string) ([]byte, error) {
-       if !strings.Contains(clustername, "+") {
-               return nil, pkgerrors.New("Not a valid cluster name")
-       }
-       strs := strings.Split(clustername, "+")
-       if len(strs) != 2 {
-               return nil, pkgerrors.New("Not a valid cluster name")
-       }
-
-       ccc := db.NewCloudConfigClient()
-
-       cconfig, err := ccc.GetCloudConfig(strs[0], strs[1], level, namespace)
-       if err != nil {
-               return nil, pkgerrors.New("Get kubeconfig failed")
-       }
-       log.Info("Successfully looked up CloudConfig", log.Fields{".Provider": cconfig.Provider, ".Cluster": cconfig.Cluster, ".Level": cconfig.Level, ".Namespace": cconfig.Namespace})
-
-       dec, err := base64.StdEncoding.DecodeString(cconfig.Config)
-       if err != nil {
-               return nil, err
-       }
-       return dec, nil
+// Init Connection for an app context
+func (c *Connection) Init(id interface{}) error {
+       log.Info("Init with interface", log.Fields{})
+       c.Clients = make(map[string]*kubeclient.Client)
+       c.Cid = fmt.Sprintf("%v", id)
+       return nil
 }
 
 // GetClient returns client for the cluster
-func (c *Connector) GetClient(cluster string, level string, namespace string) (*kubeclient.Client, error) {
+func (c *Connection) GetClient(cluster string, level string, namespace string) (*kubeclient.Client, error) {
        c.Lock()
        defer c.Unlock()
 
@@ -78,11 +49,11 @@ func (c *Connector) GetClient(cluster string, level string, namespace string) (*
        client, ok := c.Clients[cluster]
        if !ok {
                // Get file from DB
-               dec, err := GetKubeConfig(cluster, level, namespace)
+               dec, err := utils.GetKubeConfig(cluster, level, namespace)
                if err != nil {
                        return nil, err
                }
-               var kubeConfigPath string = basePath + c.cid + "/" + cluster + "/"
+               var kubeConfigPath string = basePath + c.Cid + "/" + cluster + "/"
                if _, err := os.Stat(kubeConfigPath); os.IsNotExist(err) {
                        err = os.MkdirAll(kubeConfigPath, 0700)
                        if err != nil {
@@ -108,21 +79,10 @@ func (c *Connector) GetClient(cluster string, level string, namespace string) (*
        return client, nil
 }
 
-func (c *Connector) GetClientWithRetry(cluster string, level string, namespace string) (*kubeclient.Client, error) {
-       client, err := c.GetClient(cluster, level, namespace)
-       if err != nil {
-               return nil, err
-       }
-       if err = client.IsReachable(); err != nil {
-               return nil, err // TODO: Add retry
-       }
-       return client, nil
-}
-
-func (c *Connector) RemoveClient() {
+func (c *Connection) RemoveClient() {
        c.Lock()
        defer c.Unlock()
-       err := os.RemoveAll(basePath + "/" + c.cid)
+       err := os.RemoveAll(basePath + "/" + c.Cid)
        if err != nil {
                log.Error("Warning: Deleting kubepath", log.Fields{"err": err})
        }
diff --git a/central-controller/src/rsync/pkg/connector/connector_new.go b/central-controller/src/rsync/pkg/connector/connector_new.go
new file mode 100644 (file)
index 0000000..6db6f8c
--- /dev/null
@@ -0,0 +1,99 @@
+// SPDX-License-Identifier: Apache-2.0
+// Copyright (c) 2020 Intel Corporation
+
+package connector
+
+import (
+       "fmt"
+
+       "strings"
+
+       pkgerrors "github.com/pkg/errors"
+       log "gitlab.com/project-emco/core/emco-base/src/orchestrator/pkg/infra/logutils"
+       "gitlab.com/project-emco/core/emco-base/src/rsync/pkg/internal/utils"
+       "gitlab.com/project-emco/core/emco-base/src/rsync/pkg/plugins/azurearc"
+       "gitlab.com/project-emco/core/emco-base/src/rsync/pkg/plugins/fluxv2"
+       "gitlab.com/project-emco/core/emco-base/src/rsync/pkg/plugins/k8s"
+       "gitlab.com/project-emco/core/emco-base/src/rsync/pkg/plugins/k8sexp"
+       . "gitlab.com/project-emco/core/emco-base/src/rsync/pkg/types"
+)
+
+// Connection is for a cluster
+type Provider struct {
+       cid string
+}
+
+func NewProvider(id interface{}) Provider {
+       return Provider{
+               cid: fmt.Sprintf("%v", id),
+       }
+}
+
+func (p *Provider) GetClientProviders(app, cluster, level, namespace string) (ClientProvider, error) {
+       // Default Provider type
+       var providerType string = "k8s"
+
+       result := strings.SplitN(cluster, "+", 2)
+       if len(result) != 2 {
+               log.Error("Invalid cluster name format::", log.Fields{"cluster": cluster})
+               return nil, pkgerrors.New("Invalid cluster name format")
+       }
+
+       kc, err := utils.GetKubeConfig(cluster, level, namespace)
+       if err != nil {
+               return nil, err
+       }
+
+       if len(kc) > 0 {
+               providerType = "k8s"
+       } else {
+               c, err := utils.GetGitOpsConfig(cluster, level, namespace)
+               if err != nil {
+                       return nil, err
+               }
+               providerType = c.Props.GitOpsType
+               if providerType == "" {
+                       return nil, pkgerrors.New("No provider type specified")
+               }
+       }
+
+       switch providerType {
+       case "k8s":
+               cl, err := k8s.NewK8sProvider(p.cid, app, cluster, level, namespace)
+               if err != nil {
+                       return nil, err
+               }
+               return cl, nil
+               // This case is unused at this time.
+               // In the above case K8s plugin each resource is written
+               // to the cluster individually. The disadvantage is
+               // that if any resource fails then the application is
+               // left in bad state on the cluster with some resources
+               // already applied on the cluster. In this plugin all
+               // application resources are collected in a temporary
+               // file, and then applied together to the cluster.
+               // All or no resources will be applied to the cluster.
+               // More Disk space is required in this approach.
+       case "k8sExp":
+               cl, err := k8sexp.NewK8sProvider(p.cid, app, cluster, level, namespace)
+               if err != nil {
+                       return nil, err
+               }
+               return cl, nil
+
+       case "fluxcd":
+               cl, err := fluxv2.NewFluxv2Provider(p.cid, app, cluster, level, namespace)
+               if err != nil {
+                       return nil, err
+               }
+               return cl, nil
+               //Add other types like Azure Arc, Anthos etc here
+       case "azureArc":
+               cl, err := azurearc.NewAzureArcProvider(p.cid, app, cluster, level, namespace)
+               if err != nil {
+                       return nil, err
+               }
+               return cl, nil
+       }
+       return nil, pkgerrors.New("Provider type not supported")
+}
diff --git a/central-controller/src/rsync/pkg/context/cluster.go b/central-controller/src/rsync/pkg/context/cluster.go
new file mode 100644 (file)
index 0000000..5b56c8b
--- /dev/null
@@ -0,0 +1,303 @@
+// SPDX-License-Identifier: Apache-2.0
+// Copyright (c) 2020 Intel Corporation
+
+package context
+
+import (
+       "context"
+       pkgerrors "github.com/pkg/errors"
+       "gitlab.com/project-emco/core/emco-base/src/orchestrator/pkg/appcontext"
+       log "gitlab.com/project-emco/core/emco-base/src/orchestrator/pkg/infra/logutils"
+       "gitlab.com/project-emco/core/emco-base/src/orchestrator/pkg/resourcestatus"
+       "gitlab.com/project-emco/core/emco-base/src/rsync/pkg/status"
+       . "gitlab.com/project-emco/core/emco-base/src/rsync/pkg/types"
+       "strings"
+       "time"
+)
+
+type resProvd struct {
+       app     string
+       cluster string
+       cl      ClientProvider
+       context Context
+}
+
+// Hook Kinds that require wait
+var HelmHookRelevantKindSet map[string]bool = map[string]bool{"Job": true, "Pod": true, "Deployment": true, "DaemonSet": true, "StatefulSet": true}
+
+// handleResources - performs the operation on the cluster
+// If wait is true wait for resources to be ready/success before next resource
+func (r *resProvd) handleResources(ctx context.Context, op RsyncOperation, resources []string) (int, error) {
+
+       var handledRes int
+       var ref interface{}
+       var breakonError bool
+
+       if len(resources) <= 0 {
+               return handledRes, nil
+       }
+       // Keep retrying for reachability
+       for {
+               // Wait for cluster to be reachable
+               err := r.waitForClusterReady(ctx)
+               if err != nil {
+                       return handledRes, err
+               }
+               reachable := true
+               handledRes = 0
+               // Handle all resources in order
+               for _, res := range resources {
+                       ref, breakonError, err = r.handleResource(ctx, op, res, ref)
+                       if err != nil {
+                               log.Error("Error in resource", log.Fields{"error": err, "cluster": r.cluster, "resource": res})
+                               // If failure is due to reachability issues start retrying
+                               if err1 := r.cl.IsReachable(); err1 != nil {
+                                       reachable = false
+                                       break
+                               }
+                               if breakonError {
+                                       return handledRes, err
+                               }
+                       }
+                       handledRes++
+               }
+               // Check if the break from loop due to reachabilty issues
+               if reachable {
+                       // Not reachability issue, commit resources to the cluster
+                       r.cl.Commit(ctx, ref)
+                       return handledRes, nil
+               }
+       }
+}
+
+func (r *resProvd) handleResourcesWithWait(ctx context.Context, op RsyncOperation, resources []string) (int, error) {
+       var handledRes int
+       for _, res := range resources {
+               // Apply one resource and then wait for it to be succeded before going to next resource
+               if _, err := r.handleResources(ctx, op, []string{res}); err == nil {
+                       // Resouce successfully applied
+                       handledRes++
+                       // Check if this resource needs waiting based on Helm comment:
+                       // https://github.com/helm/helm/blob/67f92d63faef0f9acdd0a95680dbc03dc7f86ed6/pkg/kube/client.go#L552
+                       // For things like a secret or a config map, this is the best indicator
+                       // we get. We care mostly about jobs, where what we want to see is
+                       // the status go into a good state.
+                       result := strings.SplitN(res, "+", 2)
+                       if len(result) != 2 {
+                               log.Error("Invalid resource name format::", log.Fields{"res": res})
+                               return handledRes, err
+                       }
+                       if ok := HelmHookRelevantKindSet[result[1]]; !ok {
+                               continue
+                       }
+                       if err := r.context.dm.WaitResourceDependency(ctx, r.app, r.cluster, res); err != nil {
+                               log.Error("Dependency error", log.Fields{"error": err, "cluster": r.cluster, "resource": res})
+                               return handledRes, err
+                       }
+               } else {
+                       return handledRes, err
+               }
+       }
+       return handledRes, nil
+}
+
+func (r *resProvd) waitForClusterReady(ctx context.Context) error {
+
+       // Check if reachable
+       if err := r.cl.IsReachable(); err == nil {
+               r.context.acRef.SetClusterAvailableStatus(r.app, r.cluster, appcontext.ClusterReadyStatusEnum.Available)
+               return nil
+       }
+       r.context.acRef.SetClusterAvailableStatus(r.app, r.cluster, appcontext.ClusterReadyStatusEnum.Retrying)
+       timedOut := false
+       retryCnt := 0
+       forceDone := false
+Loop:
+       for {
+               select {
+               // Wait for wait time before checking cluster ready
+               case <-time.After(time.Duration(r.context.waitTime) * time.Second):
+                       // Context is canceled
+                       if ctx.Err() != nil {
+                               return ctx.Err()
+                       }
+                       // If cluster is reachable then done
+                       if err := r.cl.IsReachable(); err == nil {
+                               r.context.acRef.SetClusterAvailableStatus(r.app, r.cluster, appcontext.ClusterReadyStatusEnum.Available)
+                               return nil
+                       }
+                       log.Info("Cluster is not reachable - keep trying::", log.Fields{"cluster": r.cluster, "retry count": retryCnt})
+                       retryCnt++
+                       if r.context.maxRetry >= 0 && retryCnt > r.context.maxRetry {
+                               timedOut = true
+                               break Loop
+                       }
+               // Check if the context is canceled
+               case <-ctx.Done():
+                       return ctx.Err()
+               }
+       }
+       if timedOut {
+               return pkgerrors.Errorf("Retries exceeded max: " + r.cluster)
+       }
+       if forceDone {
+               return pkgerrors.Errorf("Termination of rsync cluster retry: " + r.cluster)
+       }
+       return nil
+}
+
+func (r *resProvd) handleResource(ctx context.Context, op RsyncOperation, res string, ref interface{}) (interface{}, bool, error) {
+
+       var q interface{}
+       var err error
+       switch op {
+       case OpApply:
+               // Get resource dependency here
+               q, err = r.instantiateResource(res, ref)
+               if err != nil {
+                       // return true for breakon error
+                       return q, true, err
+               }
+       case OpCreate:
+               // Get resource dependency here
+               q, err = r.createResource(res, ref)
+               if err != nil {
+                       // return true for breakon error
+                       return q, true, err
+               }
+       case OpDelete:
+               q, err = r.terminateResource(res, ref)
+               if err != nil {
+                       // return false for breakon error
+                       return q, false, err
+               }
+       case OpRead:
+               err = r.readResource(res)
+               if err != nil {
+                       // return false for breakon error
+                       return nil, false, err
+               }
+       }
+       // return false for breakon error
+       return q, false, nil
+}
+
+func (r *resProvd) instantiateResource(name string, ref interface{}) (interface{}, error) {
+       var q interface{}
+       res, _, err := r.context.acRef.GetRes(name, r.app, r.cluster)
+       if err != nil {
+               r.updateResourceStatus(name, resourcestatus.ResourceStatus{Status: resourcestatus.RsyncStatusEnum.Failed})
+               return nil, err
+       }
+       label := r.context.statusAcID + "-" + r.app
+       b, err := r.cl.TagResource(res, label)
+       if err != nil {
+               log.Error("Error Tag Resoruce with label:", log.Fields{"err": err, "label": label, "resource": name})
+               return nil, err
+       }
+       if q, err = r.cl.Apply(name, ref, b); err != nil {
+               r.updateResourceStatus(name, resourcestatus.ResourceStatus{Status: resourcestatus.RsyncStatusEnum.Failed})
+               log.Error("Failed to apply res", log.Fields{"error": err, "resource": name})
+               return nil, err
+       }
+       r.updateResourceStatus(name, resourcestatus.ResourceStatus{Status: resourcestatus.RsyncStatusEnum.Applied})
+       return q, nil
+}
+
+func (r *resProvd) createResource(name string, ref interface{}) (interface{}, error) {
+       var q interface{}
+
+       res, _, err := r.context.acRef.GetRes(name, r.app, r.cluster)
+       if err != nil {
+               r.updateResourceStatus(name, resourcestatus.ResourceStatus{Status: resourcestatus.RsyncStatusEnum.Failed})
+               return nil, err
+       }
+       label := r.context.statusAcID + "-" + r.app
+       b, err := r.cl.TagResource(res, label)
+       if err != nil {
+               log.Error("Error Tag Resoruce with label:", log.Fields{"err": err, "label": label, "resource": name})
+               return nil, err
+       }
+       if q, err = r.cl.Create(name, ref, b); err != nil {
+               r.updateResourceStatus(name, resourcestatus.ResourceStatus{Status: resourcestatus.RsyncStatusEnum.Failed})
+               log.Error("Failed to create res", log.Fields{"error": err, "resource": name})
+               return nil, err
+       }
+       r.updateResourceStatus(name, resourcestatus.ResourceStatus{Status: resourcestatus.RsyncStatusEnum.Applied})
+       return q, nil
+}
+
+func (r *resProvd) terminateResource(name string, ref interface{}) (interface{}, error) {
+       var q interface{}
+
+       res, sh, err := r.context.acRef.GetRes(name, r.app, r.cluster)
+       if err != nil {
+               if sh != nil {
+                       r.updateResourceStatus(name, resourcestatus.ResourceStatus{Status: resourcestatus.RsyncStatusEnum.Failed})
+               }
+               return nil, err
+       }
+       if q, err = r.cl.Delete(name, ref, res); err != nil {
+               r.updateResourceStatus(name, resourcestatus.ResourceStatus{Status: resourcestatus.RsyncStatusEnum.Failed})
+               log.Error("Failed to delete res", log.Fields{"error": err, "resource": name})
+               return nil, err
+       }
+       r.updateResourceStatus(name, resourcestatus.ResourceStatus{Status: resourcestatus.RsyncStatusEnum.Deleted})
+       return q, nil
+}
+
+func (r *resProvd) readResource(name string) error {
+
+       res, _, err := r.context.acRef.GetRes(name, r.app, r.cluster)
+       if err != nil {
+               r.updateResourceStatus(name, resourcestatus.ResourceStatus{Status: resourcestatus.RsyncStatusEnum.Failed})
+               return err
+       }
+       // Get the resource from the cluster
+       b, err := r.cl.Get(name, res)
+       if err != nil {
+               r.updateResourceStatus(name, resourcestatus.ResourceStatus{Status: resourcestatus.RsyncStatusEnum.Failed})
+               log.Error("Failed to read res", log.Fields{"error": err, "resource": name})
+               return err
+       }
+       // Store result back in AppContext
+       r.context.acRef.PutRes(name, r.app, r.cluster, b)
+       r.updateResourceStatus(name, resourcestatus.ResourceStatus{Status: resourcestatus.RsyncStatusEnum.Applied})
+       return nil
+}
+
+func (r *resProvd) addStatusTracker(extraLabel string) error {
+       // Get label and create CR
+       label := r.context.statusAcID + "-" + r.app
+       b, err := status.GetStatusCR(label, extraLabel)
+       if err != nil {
+               log.Error("Failed to get status CR for installing", log.Fields{"error": err, "label": label})
+               return err
+       }
+       if err = r.cl.ApplyStatusCR(label, b); err != nil {
+               log.Error("Failed to apply status tracker", log.Fields{"error": err, "cluster": r.cluster, "app": r.app, "label": label})
+               return err
+       }
+       return nil
+}
+
+func (r *resProvd) deleteStatusTracker(extraLabel string) error {
+       // Get label and create CR
+       label := r.context.statusAcID + "-" + r.app
+       b, err := status.GetStatusCR(label, extraLabel)
+       if err != nil {
+               log.Error("Failed to get status CR for deleting", log.Fields{"error": err, "label": label})
+               return err
+       }
+       if err = r.cl.DeleteStatusCR(label, b); err != nil {
+               log.Error("Failed to delete res", log.Fields{"error": err, "app": r.app, "label": label})
+               return err
+       }
+       return nil
+}
+
+func (r *resProvd) updateResourceStatus(name string, status interface{}) {
+       // Use utils with status appContext
+       _ = r.context.scRef.AddResourceStatus(name, r.app, r.cluster, status, r.context.acID)
+       // Treating status errors as non fatal
+}
index 37e8a4f..afe46ad 100644 (file)
@@ -5,977 +5,229 @@ package context
 
 import (
        "context"
-       "encoding/json"
        "fmt"
        "strconv"
-       "strings"
        "sync"
        "time"
 
-       "github.com/open-ness/EMCO/src/orchestrator/pkg/appcontext"
-       "github.com/open-ness/EMCO/src/orchestrator/pkg/infra/config"
-       "github.com/open-ness/EMCO/src/orchestrator/pkg/infra/logutils"
-       "github.com/open-ness/EMCO/src/orchestrator/pkg/resourcestatus"
-       kubeclient "github.com/open-ness/EMCO/src/rsync/pkg/client"
-       connector "github.com/open-ness/EMCO/src/rsync/pkg/connector"
-       utils "github.com/open-ness/EMCO/src/rsync/pkg/internal"
-       status "github.com/open-ness/EMCO/src/rsync/pkg/status"
-       pkgerrors "github.com/pkg/errors"
-       "golang.org/x/sync/errgroup"
-       "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
+       "gitlab.com/project-emco/core/emco-base/src/orchestrator/pkg/infra/config"
+       "gitlab.com/project-emco/core/emco-base/src/orchestrator/pkg/infra/logutils"
+       "gitlab.com/project-emco/core/emco-base/src/rsync/pkg/connector"
+       "gitlab.com/project-emco/core/emco-base/src/rsync/pkg/depend"
+       "gitlab.com/project-emco/core/emco-base/src/rsync/pkg/internal/utils"
+       . "gitlab.com/project-emco/core/emco-base/src/rsync/pkg/types"
 )
 
-type CompositeAppContext struct {
-       cid   interface{}
-       chans []chan bool
-       mutex sync.Mutex
-}
-
-func getMaxRetries() int {
-       s := config.GetConfiguration().MaxRetries
-       if s == "" {
-               return -1
-       }
-       maxRetries, err := strconv.Atoi(s)
-       if err != nil {
-               return -1
-       } else {
-               if maxRetries < 0 {
-                       return -1
-               }
-       }
-       return maxRetries
-}
-
-func getRes(ac appcontext.AppContext, name string, app string, cluster string) ([]byte, interface{}, error) {
-       var byteRes []byte
-       rh, err := ac.GetResourceHandle(app, cluster, name)
-       if err != nil {
-               return nil, nil, err
-       }
-       sh, err := ac.GetLevelHandle(rh, "status")
-       if err != nil {
-               return nil, nil, err
-       }
-       resval, err := ac.GetValue(rh)
-       if err != nil {
-               return nil, sh, err
-       }
-       if resval != "" {
-               result := strings.Split(name, "+")
-               if result[0] == "" {
-                       return nil, sh, pkgerrors.Errorf("Resource name is nil %s:", name)
-               }
-               byteRes = []byte(fmt.Sprintf("%v", resval.(interface{})))
-       } else {
-               return nil, sh, pkgerrors.Errorf("Resource value is nil %s", name)
-       }
-       return byteRes, sh, nil
-}
-
-func getSubResApprove(ac appcontext.AppContext, name string, app string, cluster string) ([]byte, interface{}, error) {
-       var byteRes []byte
-       rh, err := ac.GetResourceHandle(app, cluster, name)
-       if err != nil {
-               return nil, nil, err
-       }
-       sh, err := ac.GetLevelHandle(rh, "subresource/approval")
-       if err != nil {
-               return nil, nil, err
-       }
-       resval, err := ac.GetValue(sh)
-       if err != nil {
-               return nil, sh, err
-       }
-       if resval != "" {
-               byteRes = []byte(fmt.Sprintf("%v", resval.(interface{})))
-       } else {
-               return nil, sh, pkgerrors.Errorf("SubResource value is nil %s", name)
-       }
-       return byteRes, sh, nil
-}
-
-func terminateResource(ac appcontext.AppContext, c *kubeclient.Client, name string, app string, cluster string, label string) error {
-       res, sh, err := getRes(ac, name, app, cluster)
-       if err != nil {
-               if sh != nil {
-                       ac.UpdateStatusValue(sh, resourcestatus.ResourceStatus{Status: resourcestatus.RsyncStatusEnum.Failed})
+// Context is Per AppContext struct
+type Context struct {
+       Lock    *sync.Mutex
+       Running bool
+       Channel chan RsyncEvent
+       // AppContext ID
+       acID string
+       // AppContext handle
+       acRef utils.AppContextReference
+       // Status AppContext ID
+       statusAcID string
+       // Status AppContext handle
+       scRef utils.AppContextReference
+       // Connector interface
+       con Connector
+       // Function to cancel running threads on terminate
+       cancel context.CancelFunc
+       // Max Retries for cluster reachability
+       maxRetry int
+       // wait time (seconds) between trying again for cluster reachability
+       waitTime int
+       // Structure to hold CompositeApp Information
+       ca CompositeApp
+       // To manage dependency
+       dm *depend.DependManager
+       // Keep track for scheduled monitor CR delete functions
+       // Key for the map is app+cluster
+       timerList map[string]*time.Timer
+}
+
+// AppContextData struct
+type AppContextData struct {
+       Data map[string]*Context
+       sync.Mutex
+}
+
+var appContextData = AppContextData{
+       Data: map[string]*Context{},
+}
+
+// HandleAppContext adds event to queue and starts main thread
+func HandleAppContext(a interface{}, ucid interface{}, e RsyncEvent, con Connector) error {
+
+       acID := fmt.Sprintf("%v", a)
+       // Create AppContext data if not already created
+       _, c := CreateAppContextData(acID)
+       // Add event to queue
+       err := c.EnqueueToAppContext(a, ucid, e)
+       if err != nil {
+               return err
+       }
+       // If main thread is not running start it
+       // Acquire Mutex
+       c.Lock.Lock()
+       defer c.Lock.Unlock()
+       if c.Running {
+               if e == TerminateEvent {
+                       c.terminateContextRoutine()
                }
-               return err
-       }
-       if err := c.Delete(res); err != nil {
-               ac.UpdateStatusValue(sh, resourcestatus.ResourceStatus{Status: resourcestatus.RsyncStatusEnum.Failed})
-               logutils.Error("Failed to delete res", logutils.Fields{
-                       "error":    err,
-                       "resource": name,
-               })
-               return err
-       }
-       ac.UpdateStatusValue(sh, resourcestatus.ResourceStatus{Status: resourcestatus.RsyncStatusEnum.Deleted})
-       logutils.Info("Deleted::", logutils.Fields{
-               "cluster":  cluster,
-               "resource": name,
-       })
-       return nil
-}
-
-func instantiateResource(ac appcontext.AppContext, c *kubeclient.Client, name string, app string, cluster string, label string) error {
-       res, sh, err := getRes(ac, name, app, cluster)
-       if err != nil {
-               if sh != nil {
-                       ac.UpdateStatusValue(sh, resourcestatus.ResourceStatus{Status: resourcestatus.RsyncStatusEnum.Failed})
-               }
-               return err
-       }
-       //Decode the yaml to create a runtime.Object
-       unstruct := &unstructured.Unstructured{}
-       //Ignore the returned obj as we expect the data in unstruct
-       _, err = utils.DecodeYAMLData(string(res), unstruct)
-       if err != nil {
-               return pkgerrors.Wrap(err, "Decode deployment object error")
-       }
-
-       //Add the tracking label to all resources created here
-       labels := unstruct.GetLabels()
-       //Check if labels exist for this object
-       if labels == nil {
-               labels = map[string]string{}
-       }
-       //labels[config.GetConfiguration().KubernetesLabelName] = client.GetInstanceID()
-       labels["emco/deployment-id"] = label
-       unstruct.SetLabels(labels)
-
-       // This checks if the resource we are creating has a podSpec in it
-       // Eg: Deployment, StatefulSet, Job etc..
-       // If a PodSpec is found, the label will be added to it too.
-       //connector.TagPodsIfPresent(unstruct, client.GetInstanceID())
-       utils.TagPodsIfPresent(unstruct, label)
-       b, err := unstruct.MarshalJSON()
-       if err != nil {
-               logutils.Error("Failed to MarshalJSON", logutils.Fields{
-                       "error":    err,
-                       "resource": name,
-               })
-               return err
-       }
-       if err := c.Apply(b); err != nil {
-               ac.UpdateStatusValue(sh, resourcestatus.ResourceStatus{Status: resourcestatus.RsyncStatusEnum.Failed})
-               logutils.Error("Failed to apply res", logutils.Fields{
-                       "error":    err,
-                       "resource": name,
-               })
-               return err
-       }
-       ac.UpdateStatusValue(sh, resourcestatus.ResourceStatus{Status: resourcestatus.RsyncStatusEnum.Applied})
-       logutils.Info("Installed::", logutils.Fields{
-               "cluster":  cluster,
-               "resource": name,
-       })
-
-       // Currently only subresource supported is approval
-       subres, _, err := getSubResApprove(ac, name, app, cluster)
-       if err == nil {
-               result := strings.Split(name, "+")
-               if result[0] == "" {
-                       return pkgerrors.Errorf("Resource name is nil %s:", name)
-               }
-               logutils.Info("Approval Subresource::", logutils.Fields{
-                       "cluster":  cluster,
-                       "resource": result[0],
-                       "approval": string(subres),
-               })
-               err = c.Approve(result[0], subres)
-               return err
-       }
-       return nil
-}
-
-func readResource(ac appcontext.AppContext, c *kubeclient.Client, name string, app string, cluster string, label string) error {
-       res, sh, err := getRes(ac, name, app, cluster)
-       if err != nil {
-               if sh != nil {
-                       ac.UpdateStatusValue(sh, resourcestatus.ResourceStatus{Status: resourcestatus.RsyncStatusEnum.Failed})
-               }
-               return err
-       }
-       namespace := "default"
-       appmeta, err := ac.GetCompositeAppMeta()
-       if err == nil {
-               namespace = appmeta.Namespace
-       }
-       // Get the resource from the cluster
-       b, err := c.Get(res, namespace)
-       if err != nil {
-               return pkgerrors.Wrap(err, "Client Get failed")
-       }
-       // Get the handle for the context/app/cluster/res status object
-       rh, err := ac.GetResourceHandle(app, cluster, name)
-       if err != nil {
-               return err
-       }
-       handle, _ := ac.GetLevelHandle(rh, "definition")
-       // If definition handle was not found, then create it
-       if handle == nil {
-               ac.AddLevelValue(rh, "definition", string(b))
        } else {
-               ac.UpdateStatusValue(rh, string(b))
-       }
-       return nil
-}
-
-func updateResourceStatus(ac appcontext.AppContext, resState resourcestatus.ResourceStatus, app string, cluster string, aov map[string][]string) error {
-
-       for _, res := range aov["resorder"] {
-
-               rh, err := ac.GetResourceHandle(app, cluster, res)
+               // One main thread for AppContext
+               c.Running = true
+               err = c.startMainThread(a, con)
                if err != nil {
+                       c.Running = false
                        return err
                }
-               sh, err := ac.GetLevelHandle(rh, "status")
-               if err != nil {
-                       return err
-               }
-
-               s, err := ac.GetValue(sh)
-               if err != nil {
-                       return err
-               }
-               rStatus := resourcestatus.ResourceStatus{}
-               js, err := json.Marshal(s)
-               if err != nil {
-                       return err
-               }
-               err = json.Unmarshal(js, &rStatus)
-               if err != nil {
-                       return err
-               }
-               // no need to update a status that has reached a 'done' status
-               if rStatus.Status == resourcestatus.RsyncStatusEnum.Deleted ||
-                       rStatus.Status == resourcestatus.RsyncStatusEnum.Applied ||
-                       rStatus.Status == resourcestatus.RsyncStatusEnum.Failed {
-                       continue
-               }
-
-               err = ac.UpdateStatusValue(sh, resState)
-               if err != nil {
-                       return err
-               }
-       }
-
-       return nil
-
-}
-
-// return true if all resources have reached a 'done' status - e.g. Applied, Deleted or Failed
-func allResourcesDone(ac appcontext.AppContext, app string, cluster string, aov map[string][]string) bool {
-
-       for _, res := range aov["resorder"] {
-
-               rh, err := ac.GetResourceHandle(app, cluster, res)
-               if err != nil {
-                       return false
-               }
-               sh, err := ac.GetLevelHandle(rh, "status")
-               if err != nil {
-                       return false
-               }
-
-               s, err := ac.GetValue(sh)
-               if err != nil {
-                       return false
-               }
-               rStatus := resourcestatus.ResourceStatus{}
-               js, err := json.Marshal(s)
-               if err != nil {
-                       return false
-               }
-               err = json.Unmarshal(js, &rStatus)
-               if err != nil {
-                       return false
-               }
-               if rStatus.Status != resourcestatus.RsyncStatusEnum.Deleted &&
-                       rStatus.Status != resourcestatus.RsyncStatusEnum.Applied &&
-                       rStatus.Status != resourcestatus.RsyncStatusEnum.Failed {
-                       return false
-               }
        }
-
-       return true
-
+       return err
 }
 
-// Wait for 2 secs
-const waitTime = 2
-
-func waitForClusterReady(instca *CompositeAppContext, ac appcontext.AppContext, acStatus appcontext.AppContextStatus, c *kubeclient.Client, appname string, cluster string, aov map[string][]string) error {
-
-       forceDone := false
-       timedOut := false
-       resStateUpdated := false
-       ch := addChan(instca)
-
-       rch := make(chan error, 1)
-       checkReachable := func() {
-               err := c.IsReachable()
-               rch <- err
-       }
-
-       go checkReachable()
-
-       maxRetries := getMaxRetries()
-       retryCnt := 0
-Loop:
-       for {
-               select {
-               case rerr := <-rch:
-                       if rerr == nil {
-                               break Loop
-                       } else {
-                               logutils.Info("Cluster is not reachable - keep trying::", logutils.Fields{"cluster": cluster})
-                       }
-               case <-ch:
-                       statusFailed := resourcestatus.ResourceStatus{
-                               Status: resourcestatus.RsyncStatusEnum.Failed,
-                       }
-                       err := updateResourceStatus(ac, statusFailed, appname, cluster, aov)
-                       if err != nil {
-                               deleteChan(instca, ch)
-                               return err
-                       }
-                       forceDone = true
-                       break Loop
-               case <-time.After(waitTime * time.Second):
-                       // on first timeout - cluster is apparently not reachable, update resources in
-                       // this group to 'Retrying'
-                       if !resStateUpdated {
-                               statusRetrying := resourcestatus.ResourceStatus{
-                                       Status: resourcestatus.RsyncStatusEnum.Retrying,
-                               }
-                               err := updateResourceStatus(ac, statusRetrying, appname, cluster, aov)
-                               if err != nil {
-                                       deleteChan(instca, ch)
-                                       return err
-                               }
-                               resStateUpdated = true
-                       }
-
-                       retryCnt++
-                       if maxRetries >= 0 && retryCnt > maxRetries {
-                               statusFailed := resourcestatus.ResourceStatus{
-                                       Status: resourcestatus.RsyncStatusEnum.Failed,
-                               }
-                               err := updateResourceStatus(ac, statusFailed, appname, cluster, aov)
-                               if err != nil {
-                                       deleteChan(instca, ch)
-                                       return err
-                               }
-                               timedOut = true
-                               break Loop
-                       } else {
-                               go checkReachable()
-                       }
-                       break
-               }
-       }
-
-       deleteChan(instca, ch)
-       if timedOut {
-               if acStatus.Status == appcontext.AppContextStatusEnum.Terminating {
-                       logutils.Error("Terminate retries exceeded max.  Application resources may be left in cluster", logutils.Fields{
-                               "cluster": cluster,
-                               "app":     appname,
-                               "retries": retryCnt,
-                       })
-               } else {
-                       logutils.Error("Instantiate retries exceeded max.", logutils.Fields{
-                               "cluster": cluster,
-                               "app":     appname,
-                               "retries": retryCnt,
-                       })
-               }
-               return pkgerrors.Errorf("Retries exceeded max: " + cluster)
-       }
-       if forceDone {
-               return pkgerrors.Errorf("Termination of rsync cluster retry: " + cluster)
-       }
-       return nil
-}
-
-// initializeAppContextStatus sets the initial status of every resource appropriately based on the state of the AppContext
-func initializeAppContextStatus(ac appcontext.AppContext, acStatus appcontext.AppContextStatus) error {
-       h, err := ac.GetCompositeAppHandle()
+// EnqueueToAppContext adds the event to the appContext Queue
+func (c *Context) EnqueueToAppContext(a interface{}, ucid interface{}, e RsyncEvent) error {
+       acID := fmt.Sprintf("%v", a)
+       acUtils, err := utils.NewAppContextReference(acID)
        if err != nil {
                return err
        }
-       sh, err := ac.GetLevelHandle(h, "status")
-       if sh == nil {
-               _, err = ac.AddLevelValue(h, "status", acStatus)
+       qUtils := AppContextQueueUtils{ac: acUtils.GetAppContextHandle()}
+       var elem AppContextQueueElement
+       // Store UpdateID
+       if ucid != nil {
+               ucID := fmt.Sprintf("%v", ucid)
+               elem = AppContextQueueElement{Event: e, Status: "Pending", UCID: ucID}
        } else {
-               err = ac.UpdateValue(sh, acStatus)
+               elem = AppContextQueueElement{Event: e, Status: "Pending"}
        }
-       if err != nil {
-               return err
+       // Acquire Mutex before adding to queue
+       c.Lock.Lock()
+       // Push the appContext to ActiveContext space of etcD
+       ok, err := RecordActiveContext(acID)
+       if !ok {
+               logutils.Info("Already in active context", logutils.Fields{"AppContextID": acID, "err": err})
        }
+       // Enqueue event
+       qUtils.Enqueue(elem)
+       c.Lock.Unlock()
        return nil
 }
 
-// initializeResourceStatus sets the initial status of every resource appropriately based on the state of the AppContext
-func initializeResourceStatus(ac appcontext.AppContext, acStatus appcontext.AppContextStatus) error {
-       statusPending := resourcestatus.ResourceStatus{
-               Status: resourcestatus.RsyncStatusEnum.Pending,
-       }
-       statusDeleted := resourcestatus.ResourceStatus{
-               Status: resourcestatus.RsyncStatusEnum.Deleted,
-       }
-
-       appsOrder, err := ac.GetAppInstruction("order")
-       if err != nil {
-               return err
+//
+func (c *Context) StopDeleteStatusCRTimer(key string) {
+       // Acquire Mutex
+       c.Lock.Lock()
+       defer c.Lock.Unlock()
+       if c.timerList[key] != nil {
+               c.timerList[key].Stop()
+               c.timerList[key] = nil
        }
-       var appList map[string][]string
-       json.Unmarshal([]byte(appsOrder.(string)), &appList)
-
-       for _, app := range appList["apporder"] {
-               clusterNames, err := ac.GetClusterNames(app)
-               if err != nil {
-                       return err
-               }
-               for k := 0; k < len(clusterNames); k++ {
-                       cluster := clusterNames[k]
-                       resorder, err := ac.GetResourceInstruction(app, cluster, "order")
-                       if err != nil {
-                               return err
-                       }
-                       var aov map[string][]string
-                       json.Unmarshal([]byte(resorder.(string)), &aov)
-                       for _, res := range aov["resorder"] {
-                               rh, err := ac.GetResourceHandle(app, cluster, res)
-                               if err != nil {
-                                       return err
-                               }
-                               sh, err := ac.GetLevelHandle(rh, "status")
-                               if acStatus.Status == appcontext.AppContextStatusEnum.Instantiating {
-                                       if sh == nil {
-                                               _, err = ac.AddLevelValue(rh, "status", statusPending)
-                                       } else {
-                                               err = ac.UpdateStatusValue(sh, statusPending)
-                                       }
-                                       if err != nil {
-                                               return err
-                                       }
-                               } else if acStatus.Status == appcontext.AppContextStatusEnum.Terminating {
-                                       if sh == nil {
-                                               _, err = ac.AddLevelValue(rh, "status", statusDeleted)
-                                       } else {
-                                               s, err := ac.GetValue(sh)
-                                               if err != nil {
-                                                       return err
-                                               }
-                                               rStatus := resourcestatus.ResourceStatus{}
-                                               js, _ := json.Marshal(s)
-                                               json.Unmarshal(js, &rStatus)
-                                               if rStatus.Status == resourcestatus.RsyncStatusEnum.Applied {
-                                                       err = ac.UpdateStatusValue(sh, statusPending)
-                                               } else {
-                                                       err = ac.UpdateStatusValue(sh, statusDeleted)
-                                               }
-                                               if err != nil {
-                                                       return err
-                                               }
-                                       }
-                               } else {
-                                       return pkgerrors.Errorf("Error intializing AppContext Resource Statuses")
-                               }
-                       }
-               }
-       }
-       return nil
 }
+func (c *Context) UpdateDeleteStatusCRTimer(key string, timer *time.Timer) {
+       // Acquire Mutex
+       c.Lock.Lock()
+       defer c.Lock.Unlock()
+       c.timerList[key] = timer
 
-func addStatusTracker(c *kubeclient.Client, app string, cluster string, label string) error {
-
-       b, err := status.GetStatusCR(label)
-       if err != nil {
-               logutils.Error("Failed to get status CR for installing", logutils.Fields{
-                       "error": err,
-                       "label": label,
-               })
-               return err
-       }
-       // TODO: Check reachability?
-       if err = c.Apply(b); err != nil {
-               logutils.Error("Failed to apply status tracker", logutils.Fields{
-                       "error":   err,
-                       "cluster": cluster,
-                       "app":     app,
-                       "label":   label,
-               })
-               return err
-       }
-       logutils.Info("Status tracker installed::", logutils.Fields{
-               "cluster": cluster,
-               "app":     app,
-               "label":   label,
-       })
-       return nil
 }
 
-func deleteStatusTracker(c *kubeclient.Client, app string, cluster string, label string) error {
-       b, err := status.GetStatusCR(label)
-       if err != nil {
-               logutils.Error("Failed to get status CR for deleting", logutils.Fields{
-                       "error": err,
-                       "label": label,
-               })
-               return err
-       }
-       if err = c.Delete(b); err != nil {
-               logutils.Error("Failed to delete res", logutils.Fields{
-                       "error": err,
-                       "app":   app,
-                       "label": label,
-               })
-               return err
-       }
-       logutils.Info("Status tracker deleted::", logutils.Fields{
-               "cluster": cluster,
-               "app":     app,
-               "label":   label,
-       })
-       return nil
-}
-
-func updateEndingAppContextStatus(ac appcontext.AppContext, handle interface{}, failure bool) error {
-       sh, err := ac.GetLevelHandle(handle, "status")
-       if err != nil {
-               return err
-       }
-       s, err := ac.GetValue(sh)
-       if err != nil {
-               return err
-       }
-       acStatus := appcontext.AppContextStatus{}
-       js, _ := json.Marshal(s)
-       json.Unmarshal(js, &acStatus)
+// RestartAppContext called in Restart scenario to handle an AppContext
+func RestartAppContext(a interface{}, con Connector) error {
+       var err error
+       acID := fmt.Sprintf("%v", a)
+       // Create AppContext data if not already created
+       _, c := CreateAppContextData(acID)
 
-       if acStatus.Status == appcontext.AppContextStatusEnum.Instantiating {
-               if failure {
-                       acStatus.Status = appcontext.AppContextStatusEnum.InstantiateFailed
-               } else {
-                       acStatus.Status = appcontext.AppContextStatusEnum.Instantiated
-               }
-       } else if acStatus.Status == appcontext.AppContextStatusEnum.Terminating {
-               if failure {
-                       acStatus.Status = appcontext.AppContextStatusEnum.TerminateFailed
-               } else {
-                       acStatus.Status = appcontext.AppContextStatusEnum.Terminated
-               }
-       } else {
-               return pkgerrors.Errorf("Invalid AppContextStatus %v", acStatus)
+       // Acquire Mutex
+       c.Lock.Lock()
+       defer c.Lock.Unlock()
+       if c.Running == false {
+               err = c.startMainThread(a, con)
        }
-
-       err = ac.UpdateValue(sh, acStatus)
-       if err != nil {
-               return err
-       }
-       return nil
+       return err
 }
 
-func getAppContextStatus(ac appcontext.AppContext) (*appcontext.AppContextStatus, error) {
-
-       h, err := ac.GetCompositeAppHandle()
-       if err != nil {
-               return nil, err
-       }
-       sh, err := ac.GetLevelHandle(h, "status")
-       if err != nil {
-               return nil, err
-       }
-       s, err := ac.GetValue(sh)
-       if err != nil {
-               return nil, err
+// Create per AppContext thread data
+func CreateAppContextData(key string) (bool, *Context) {
+       appContextData.Lock()
+       defer appContextData.Unlock()
+       _, ok := appContextData.Data[key]
+       // Create if doesn't exist
+       if !ok {
+               appContextData.Data[key] = &Context{}
+               appContextData.Data[key].Lock = &sync.Mutex{}
+               appContextData.Data[key].Running = false
+               // Initialize timer Map for the lifetime of the appContext
+               appContextData.Data[key].timerList = make(map[string]*time.Timer)
+               // Created appContext data (return true)
+               return true, appContextData.Data[key]
        }
-       acStatus := appcontext.AppContextStatus{}
-       js, _ := json.Marshal(s)
-       json.Unmarshal(js, &acStatus)
-
-       return &acStatus, nil
-
+       // Didn't create appContext data (return false)
+       return false, appContextData.Data[key]
 }
 
-type fn func(ac appcontext.AppContext, client *kubeclient.Client, res string, app string, cluster string, label string) error
-
-type statusfn func(client *kubeclient.Client, app string, cluster string, label string) error
-
-func addChan(instca *CompositeAppContext) chan bool {
-
-       instca.mutex.Lock()
-       c := make(chan bool)
-       instca.chans = append(instca.chans, c)
-       instca.mutex.Unlock()
-
-       return c
-}
-
-func deleteChan(instca *CompositeAppContext, c chan bool) error {
-
-       var i int
-       instca.mutex.Lock()
-       for i = 0; i < len(instca.chans); i++ {
-               if instca.chans[i] == c {
-                       break
-               }
+// Delete per AppContext thread data
+func DeleteAppContextData(key string) error {
+       appContextData.Lock()
+       defer appContextData.Unlock()
+       _, ok := appContextData.Data[key]
+       if ok {
+               delete(appContextData.Data, key)
        }
-
-       if i == len(instca.chans) {
-               instca.mutex.Unlock()
-               return pkgerrors.Errorf("Given channel was not found:")
-       }
-       instca.chans[i] = instca.chans[len(instca.chans)-1]
-       instca.chans = instca.chans[:len(instca.chans)-1]
-       instca.mutex.Unlock()
-
        return nil
 }
 
-func waitForDone(ac appcontext.AppContext) {
-       count := 0
-       for {
-               time.Sleep(1 * time.Second)
-               count++
-               if count == 60*60 {
-                       logutils.Info("Wait for done watcher running..", logutils.Fields{})
-                       count = 0
-               }
-               acStatus, err := getAppContextStatus(ac)
-               if err != nil {
-                       logutils.Error("Failed to get the app context status", logutils.Fields{
-                               "error": err,
-                       })
-                       return
-               }
-               if acStatus.Status == appcontext.AppContextStatusEnum.Instantiated ||
-                       acStatus.Status == appcontext.AppContextStatusEnum.InstantiateFailed {
-                       return
-               }
+// Read Max retries from configuration
+func getMaxRetries() int {
+       s := config.GetConfiguration().MaxRetries
+       if s == "" {
+               return -1
        }
-
-}
-
-func kickoffRetryWatcher(instca *CompositeAppContext, ac appcontext.AppContext, acStatus appcontext.AppContextStatus, wg *errgroup.Group) {
-
-       wg.Go(func() error {
-
-               var count int
-
-               count = 0
-               for {
-                       time.Sleep(1 * time.Second)
-                       count++
-                       if count == 60*60 {
-                               logutils.Info("Retry watcher running..", logutils.Fields{})
-                               count = 0
-                       }
-
-                       cStatus, err := getAppContextStatus(ac)
-                       if err != nil {
-                               logutils.Error("Failed to get the app context status", logutils.Fields{
-                                       "error": err,
-                               })
-                               return err
-                       }
-                       flag, err := getAppContextFlag(ac)
-                       if err != nil {
-                               logutils.Error("Failed to get the stop flag", logutils.Fields{
-                                       "error": err,
-                               })
-                               return err
-                       } else {
-                               if flag == true {
-                                       instca.mutex.Lock()
-                                       for i := 0; i < len(instca.chans); i++ {
-                                               instca.chans[i] <- true
-                                               logutils.Info("kickoffRetryWatcher - send an exit message", logutils.Fields{})
-                                       }
-                                       instca.mutex.Unlock()
-                                       break
-                               }
-                       }
-                       if acStatus.Status == appcontext.AppContextStatusEnum.Instantiating {
-                               if cStatus.Status == appcontext.AppContextStatusEnum.Instantiated ||
-                                       cStatus.Status == appcontext.AppContextStatusEnum.InstantiateFailed {
-                                       break
-                               }
-                       } else {
-                               if cStatus.Status == appcontext.AppContextStatusEnum.Terminated ||
-                                       cStatus.Status == appcontext.AppContextStatusEnum.TerminateFailed {
-                                       break
-                               }
-                       }
-
-               }
-               return nil
-       })
-
-}
-
-func getAppContextFlag(ac appcontext.AppContext) (bool, error) {
-       h, err := ac.GetCompositeAppHandle()
+       maxRetries, err := strconv.Atoi(s)
        if err != nil {
-               return false, err
-       }
-       sh, err := ac.GetLevelHandle(h, "stopflag")
-       if sh == nil {
-               return false, err
+               return -1
        } else {
-               v, err := ac.GetValue(sh)
-               if err != nil {
-                       return false, err
-               } else {
-                       return v.(bool), nil
+               if maxRetries < 0 {
+                       return -1
                }
        }
+       return maxRetries
 }
 
-func updateAppContextFlag(cid interface{}, sf bool) error {
-       ac := appcontext.AppContext{}
-       _, err := ac.LoadAppContext(cid)
-       if err != nil {
-               return err
-       }
-       hc, err := ac.GetCompositeAppHandle()
-       if err != nil {
-               return err
-       }
-       sh, err := ac.GetLevelHandle(hc, "stopflag")
-       if sh == nil {
-               _, err = ac.AddLevelValue(hc, "stopflag", sf)
-       } else {
-               err = ac.UpdateValue(sh, sf)
-       }
-       if err != nil {
-               return err
-       }
-       return nil
-}
-
-func applyFnComApp(instca *CompositeAppContext, acStatus appcontext.AppContextStatus, f fn, sfn statusfn, breakonError bool) error {
-       con := connector.Init(instca.cid)
-       //Cleanup
-       defer con.RemoveClient()
-       ac := appcontext.AppContext{}
-       h, err := ac.LoadAppContext(instca.cid)
-       if err != nil {
-               return err
-       }
-
-       // if terminating, wait for all retrying instantiate threads to exit
-       if acStatus.Status == appcontext.AppContextStatusEnum.Terminating {
-               waitForDone(ac)
-               err := updateAppContextFlag(instca.cid, false)
-               if err != nil {
-                       return err
-               }
-       }
-
-       // initialize appcontext status
-       err = initializeAppContextStatus(ac, acStatus)
-       if err != nil {
-               return err
-       }
-
-       // initialize the resource status values before proceeding with the function
-       err = initializeResourceStatus(ac, acStatus)
-       if err != nil {
-               logutils.Error("", logutils.Fields{"err": err})
-               return err
-       }
-
-       appsOrder, err := ac.GetAppInstruction("order")
-       if err != nil {
-               return err
-       }
-       var appList map[string][]string
-       json.Unmarshal([]byte(appsOrder.(string)), &appList)
-       logutils.Info("appsorder ", logutils.Fields{
-               "appsorder": appsOrder,
-               "string":    appList,
-       })
-       id, _ := ac.GetCompositeAppHandle()
-       g, _ := errgroup.WithContext(context.Background())
-       wg, _ := errgroup.WithContext(context.Background())
-       kickoffRetryWatcher(instca, ac, acStatus, wg)
-
-       // get namespace and level of cloudconfig to use for resources
-       namespace := "default"
-       level := "0"
-       appmeta, err := ac.GetCompositeAppMeta()
-       if err == nil {
-               namespace = appmeta.Namespace
-               level = appmeta.Level
-       }
-       logutils.Info("CloudConfig for this app will be looked up using level and namespace specified", logutils.Fields{
-               "level":     level,
-               "namespace": namespace,
-       })
-
-       // Iterate over all the subapps
-       for _, app := range appList["apporder"] {
-               appName := app
-               results := strings.Split(id.(string), "/")
-               label := results[2] + "-" + app
-               g.Go(func() error {
-                       clusterNames, err := ac.GetClusterNames(appName)
-                       if err != nil {
-                               return err
-                       }
-                       // Iterate over all clusters
-                       for k := 0; k < len(clusterNames); k++ {
-                               cluster := clusterNames[k]
-                               err = status.StartClusterWatcher(cluster)
-                               if err != nil {
-                                       logutils.Error("Error starting Cluster Watcher", logutils.Fields{
-                                               "error":   err,
-                                               "cluster": cluster,
-                                       })
-                               }
-                               g.Go(func() error {
-                                       c, err := con.GetClient(cluster, level, namespace)
-                                       if err != nil {
-                                               logutils.Error("Error in creating kubeconfig client", logutils.Fields{
-                                                       "error":   err,
-                                                       "cluster": cluster,
-                                                       "appName": appName,
-                                               })
-                                               return err
-                                       }
-                                       resorder, err := ac.GetResourceInstruction(appName, cluster, "order")
-                                       if err != nil {
-                                               logutils.Error("Resorder error ", logutils.Fields{"error": err})
-                                               return err
-                                       }
-                                       var aov map[string][]string
-                                       json.Unmarshal([]byte(resorder.(string)), &aov)
-                                       // Keep retrying for reachability
-                                       for {
-                                               done := allResourcesDone(ac, appName, cluster, aov)
-                                               if done {
-                                                       break
-                                               }
-
-                                               // Wait for cluster to be reachable
-                                               err := waitForClusterReady(instca, ac, acStatus, c, appName, cluster, aov)
-                                               if err != nil {
-                                                       // TODO: Add error handling
-                                                       return err
-                                               }
-                                               reachable := true
-                                               // Handle all resources in order
-                                               for i, res := range aov["resorder"] {
-                                                       err = f(ac, c, res, appName, cluster, label)
-                                                       if err != nil {
-                                                               logutils.Error("Error in resource %s: %v", logutils.Fields{
-                                                                       "error":    err,
-                                                                       "cluster":  cluster,
-                                                                       "resource": res,
-                                                               })
-                                                               // If failure is due to reachability issues start retrying
-                                                               if err = c.IsReachable(); err != nil {
-                                                                       reachable = false
-                                                                       break
-                                                               }
-                                                               if breakonError {
-                                                                       // handle status tracking before exiting if at least one resource got handled
-                                                                       if i > 0 {
-                                                                               serr := sfn(c, appName, cluster, label)
-                                                                               if serr != nil {
-                                                                                       logutils.Warn("Error handling status tracker", logutils.Fields{"error": serr})
-                                                                               }
-                                                                       }
-                                                                       return err
-                                                               }
-                                                       }
-                                               }
-                                               // Check if the break from loop due to reachabilty issues
-                                               if reachable != false {
-                                                       serr := sfn(c, appName, cluster, label)
-                                                       if serr != nil {
-                                                               logutils.Warn("Error handling status tracker", logutils.Fields{"error": serr})
-                                                       }
-                                                       // Done processing cluster without errors
-                                                       return nil
-                                               }
-                                       }
-                                       return nil
-                               })
-                       }
-                       return nil
-               })
-       }
-       // Wait for all subtasks to complete
-       if err := g.Wait(); err != nil {
-               uperr := updateEndingAppContextStatus(ac, h, true)
-               if uperr != nil {
-                       logutils.Error("Encountered error updating AppContext to Failed status", logutils.Fields{"error": uperr})
-               }
-               logutils.Error("Encountered error", logutils.Fields{
-                       "error": err,
-               })
-               return err
-       }
-       err = updateEndingAppContextStatus(ac, h, false)
-       if err != nil {
-               logutils.Error("Encountered error updating AppContext status", logutils.Fields{"error": err})
-               return err
-       }
-       if err := wg.Wait(); err != nil {
-               logutils.Error("Encountered error in watcher thread", logutils.Fields{"error": err})
-               return err
-       }
-       return nil
+// CompositeAppContext represents composite app
+type CompositeAppContext struct {
+       cid interface{}
 }
 
-// InstantiateComApp Instantiate Apps in Composite App
+// InstantiateComApp Instantiatep Aps in Composite App
 func (instca *CompositeAppContext) InstantiateComApp(cid interface{}) error {
        instca.cid = cid
-       instca.chans = []chan bool{}
-       instca.mutex = sync.Mutex{}
-       err := updateAppContextFlag(cid, false)
-       if err != nil {
-               logutils.Error("Encountered error updating AppContext flag", logutils.Fields{"error": err})
-               return err
-       }
-       go applyFnComApp(instca, appcontext.AppContextStatus{Status: appcontext.AppContextStatusEnum.Instantiating},
-               instantiateResource, addStatusTracker, true)
-
-       return nil
+       con := connector.NewProvider(instca.cid)
+       return HandleAppContext(instca.cid, nil, InstantiateEvent, &con)
 }
 
 // TerminateComApp Terminates Apps in Composite App
 func (instca *CompositeAppContext) TerminateComApp(cid interface{}) error {
        instca.cid = cid
-       instca.chans = []chan bool{}
-       instca.mutex = sync.Mutex{}
-       err := updateAppContextFlag(cid, true)
-       if err != nil {
-               logutils.Error("Encountered error updating AppContext flag", logutils.Fields{"error": err})
-               return err
-       }
-       go applyFnComApp(instca, appcontext.AppContextStatus{Status: appcontext.AppContextStatusEnum.Terminating},
-               terminateResource, deleteStatusTracker, false)
-       return nil
+       con := connector.NewProvider(instca.cid)
+       return HandleAppContext(instca.cid, nil, TerminateEvent, &con)
+}
+
+// UpdateComApp Updates Apps in Composite App
+func (instca *CompositeAppContext) UpdateComApp(cid interface{}, ucid interface{}) error {
+       instca.cid = cid
+       con := connector.NewProvider(instca.cid)
+       return HandleAppContext(ucid, instca.cid, UpdateEvent, &con)
 }
 
+// ReadComApp Reads resources in AppContext
 func (instca *CompositeAppContext) ReadComApp(cid interface{}) error {
        instca.cid = cid
-       instca.chans = []chan bool{}
-       instca.mutex = sync.Mutex{}
-       err := updateAppContextFlag(cid, false)
-       if err != nil {
-               logutils.Error("Encountered error updating AppContext flag", logutils.Fields{"error": err})
-               return err
-       }
-       go applyFnComApp(instca, appcontext.AppContextStatus{Status: appcontext.AppContextStatusEnum.Instantiating},
-               readResource, addStatusTracker, true)
-       return nil
+       con := connector.NewProvider(instca.cid)
+       return HandleAppContext(instca.cid, nil, ReadEvent, &con)
 }
diff --git a/central-controller/src/rsync/pkg/context/context_test.go b/central-controller/src/rsync/pkg/context/context_test.go
new file mode 100644 (file)
index 0000000..fa43605
--- /dev/null
@@ -0,0 +1,582 @@
+// SPDX-License-Identifier: Apache-2.0
+// Copyright (c) 2020 Intel Corporation
+
+package context_test
+
+import (
+       "testing"
+       "time"
+
+       "gitlab.com/project-emco/core/emco-base/src/orchestrator/pkg/appcontext"
+       "gitlab.com/project-emco/core/emco-base/src/orchestrator/pkg/infra/contextdb"
+       . "gitlab.com/project-emco/core/emco-base/src/rsync/pkg/context"
+       "gitlab.com/project-emco/core/emco-base/src/rsync/pkg/internal/utils"
+       . "gitlab.com/project-emco/core/emco-base/src/rsync/pkg/types"
+)
+
+func init() {
+       var edb *contextdb.MockConDb
+       edb = new(contextdb.MockConDb)
+       edb.Err = nil
+       contextdb.Db = edb
+}
+
+var TestCA CompositeApp = CompositeApp{
+       CompMetadata: appcontext.CompositeAppMeta{Project: "proj1", CompositeApp: "ca1", Version: "v1", Release: "r1",
+               DeploymentIntentGroup: "dig1", Namespace: "default", Level: "0"},
+       AppOrder: []string{"a1", "a2"},
+       Apps: map[string]*App{"a1": &App{
+               Name: "a1",
+               Clusters: map[string]*Cluster{"provider1+cluster1": &Cluster{
+                       Name: "provider1+cluster1",
+                       Resources: map[string]*AppResource{"r1": &AppResource{Name: "r1", Data: "a1c1r1"},
+                               "r2": &AppResource{Name: "r2", Data: "a1c1r2"},
+                       },
+                       ResOrder: []string{"r1", "r2"}}},
+       }, "a2": &App{
+               Name: "a2",
+               Clusters: map[string]*Cluster{"provider1+cluster1": &Cluster{
+                       Name: "provider1+cluster1",
+                       Resources: map[string]*AppResource{"r3": &AppResource{Name: "r3", Data: "a2c1r3"},
+                               "r4": &AppResource{Name: "r4", Data: "a2c1r4"},
+                       },
+                       ResOrder: []string{"r3", "r4"}},
+                       "provider1+cluster2": &Cluster{
+                               Name: "provider1+cluster2",
+                               Resources: map[string]*AppResource{"r3": &AppResource{Name: "r3", Data: "a2c2r3"},
+                                       "r4": &AppResource{Name: "r4", Data: "a2c2r4"},
+                               },
+                               ResOrder: []string{"r3", "r4"}}},
+       },
+       },
+}
+
+func TestInstantiateTerminate(t *testing.T) {
+
+       cid, _ := CreateCompApp(TestCA)
+       con := NewProvider(cid)
+
+       testCases := []struct {
+               label          string
+               expectedApply  map[string]string
+               expectedDelete map[string]string
+               Status         string
+               expectedError  error
+               event          RsyncEvent
+       }{
+               {
+                       expectedApply:  map[string]string{},
+                       expectedDelete: map[string]string{},
+                       expectedError:  nil,
+                       label:          "Read Resources",
+                       event:          ReadEvent,
+               },
+               {
+                       expectedApply:  map[string]string{"provider1+cluster1": "a1c1r1,a1c1r2,a2c1r3,a2c1r4", "provider1+cluster2": "a2c2r3,a2c2r4"},
+                       expectedDelete: map[string]string{},
+                       expectedError:  nil,
+                       label:          "Instantiate Resources",
+                       event:          InstantiateEvent,
+               },
+               {
+                       expectedApply:  map[string]string{"provider1+cluster1": "a1c1r1,a1c1r2,a2c1r3,a2c1r4", "provider1+cluster2": "a2c2r3,a2c2r4"},
+                       expectedDelete: map[string]string{"provider1+cluster1": "a1c1r1,a1c1r2,a2c1r3,a2c1r4", "provider1+cluster2": "a2c2r3,a2c2r4"},
+                       expectedError:  nil,
+                       label:          "Terminate Resources",
+                       event:          TerminateEvent,
+               },
+       }
+       for _, testCase := range testCases {
+               t.Run(testCase.label, func(t *testing.T) {
+                       _ = HandleAppContext(cid, nil, testCase.event, &con)
+                       time.Sleep(2 * time.Second)
+                       if !CompareMaps(testCase.expectedApply, LoadMap("apply")) {
+                               t.Error("Apply resources doesn't match", LoadMap("apply"))
+                       }
+                       if !CompareMaps(testCase.expectedDelete, LoadMap("delete")) {
+                               t.Error("Delete resources doesn't match", LoadMap("delete"))
+                       }
+               })
+       }
+}
+
+func TestUpdate(t *testing.T) {
+
+       testCases := []struct {
+               label          string
+               original       CompositeApp
+               updated        CompositeApp
+               expectedApply  map[string]string
+               expectedDelete map[string]string
+               expectedError  error
+       }{
+               {
+                       expectedApply:  map[string]string{"provider1+cluster1": "a1c1r1,a1c1r2,a1c1r1Updated,a1c1r3"},
+                       expectedDelete: map[string]string{"provider1+cluster1": "a1c1r2"},
+                       expectedError:  nil,
+                       label:          "Update with delete resource and Modify resource",
+                       original: CompositeApp{
+                               CompMetadata: appcontext.CompositeAppMeta{Project: "proj1", CompositeApp: "ca1", Version: "v1", Release: "r1",
+                                       DeploymentIntentGroup: "dig1", Namespace: "default", Level: "0"},
+                               AppOrder: []string{"a1"},
+                               Apps: map[string]*App{"a1": &App{
+                                       Name: "a1",
+                                       Clusters: map[string]*Cluster{"provider1+cluster1": &Cluster{
+                                               Name: "provider1+cluster1",
+                                               Resources: map[string]*AppResource{"r1": &AppResource{Name: "r1", Data: "a1c1r1"},
+                                                       "r2": &AppResource{Name: "r2", Data: "a1c1r2"},
+                                               },
+                                               ResOrder: []string{"r1", "r2"}}},
+                               },
+                               },
+                       },
+                       updated: CompositeApp{
+                               CompMetadata: appcontext.CompositeAppMeta{Project: "proj1", CompositeApp: "ca1", Version: "v2", Release: "r1",
+                                       DeploymentIntentGroup: "dig2", Namespace: "default", Level: "0"},
+                               AppOrder: []string{"a1"},
+                               Apps: map[string]*App{"a1": &App{
+                                       Name: "a1",
+                                       Clusters: map[string]*Cluster{"provider1+cluster1": &Cluster{
+                                               Name: "provider1+cluster1",
+                                               Resources: map[string]*AppResource{"r1": &AppResource{Name: "r1", Data: "a1c1r1Updated"},
+                                                       "r3": &AppResource{Name: "r3", Data: "a1c1r3"},
+                                               },
+                                               ResOrder: []string{"r1", "r3"}}},
+                               },
+                               },
+                       },
+               },
+               {
+                       expectedApply:  map[string]string{"provider1+cluster1": "a1c1r1,a1c1r2,a1c1r1Updated,a1c1r3,a2c1r3,a2c1r4", "provider1+cluster2": "a2c2r3,a2c2r4"},
+                       expectedDelete: map[string]string{"provider1+cluster1": "a1c1r2"},
+                       expectedError:  nil,
+                       label:          "Update with add new app",
+                       original: CompositeApp{
+                               CompMetadata: appcontext.CompositeAppMeta{Project: "proj1", CompositeApp: "ca1", Version: "v1", Release: "r1",
+                                       DeploymentIntentGroup: "dig1", Namespace: "default", Level: "0"},
+                               AppOrder: []string{"a1"},
+                               Apps: map[string]*App{"a1": &App{
+                                       Name: "a1",
+                                       Clusters: map[string]*Cluster{"provider1+cluster1": &Cluster{
+                                               Name: "provider1+cluster1",
+                                               Resources: map[string]*AppResource{"r1": &AppResource{Name: "r1", Data: "a1c1r1"},
+                                                       "r2": &AppResource{Name: "r2", Data: "a1c1r2"},
+                                               },
+                                               ResOrder: []string{"r1", "r2"}}},
+                               },
+                               },
+                       },
+                       updated: CompositeApp{
+                               CompMetadata: appcontext.CompositeAppMeta{Project: "proj1", CompositeApp: "ca1", Version: "v2", Release: "r1",
+                                       DeploymentIntentGroup: "dig2", Namespace: "default", Level: "0"},
+                               AppOrder: []string{"a1", "a2"},
+                               Apps: map[string]*App{"a1": &App{
+                                       Name: "a1",
+                                       Clusters: map[string]*Cluster{"provider1+cluster1": &Cluster{
+                                               Name: "provider1+cluster1",
+                                               Resources: map[string]*AppResource{"r1": &AppResource{Name: "r1", Data: "a1c1r1Updated"},
+                                                       "r3": &AppResource{Name: "r3", Data: "a1c1r3"},
+                                               },
+                                               ResOrder: []string{"r1", "r3"}}},
+                               },
+                                       "a2": &App{
+                                               Name: "a2",
+                                               Clusters: map[string]*Cluster{"provider1+cluster1": &Cluster{
+                                                       Name: "provider1+cluster1",
+                                                       Resources: map[string]*AppResource{"r3": &AppResource{Name: "r3", Data: "a2c1r3"},
+                                                               "r4": &AppResource{Name: "r4", Data: "a2c1r4"},
+                                                       },
+                                                       ResOrder: []string{"r3", "r4"}},
+                                                       "provider1+cluster2": &Cluster{
+                                                               Name: "provider1+cluster2",
+                                                               Resources: map[string]*AppResource{"r3": &AppResource{Name: "r3", Data: "a2c2r3"},
+                                                                       "r4": &AppResource{Name: "r4", Data: "a2c2r4"},
+                                                               },
+                                                               ResOrder: []string{"r3", "r4"}}},
+                                       },
+                               },
+                       },
+               },
+       }
+
+       for _, testCase := range testCases {
+               t.Run(testCase.label, func(t *testing.T) {
+                       cid, _ := CreateCompApp(testCase.original)
+                       ucid, _ := CreateCompApp(testCase.updated)
+                       con := NewProvider(cid)
+
+                       _ = HandleAppContext(cid, nil, InstantiateEvent, &con)
+                       _ = HandleAppContext(ucid, cid, UpdateEvent, &con)
+                       time.Sleep(2 * time.Second)
+
+                       if !CompareMaps(testCase.expectedApply, LoadMap("apply")) {
+                               t.Error("Apply resources doesn't match", LoadMap("apply"))
+                       }
+                       if !CompareMaps(testCase.expectedDelete, LoadMap("delete")) {
+                               t.Error("Delete resources doesn't match", LoadMap("delete"))
+                       }
+               })
+       }
+}
+
+func TestRollbackUpdate(t *testing.T) {
+
+       var original CompositeApp = CompositeApp{
+               CompMetadata: appcontext.CompositeAppMeta{Project: "proj1", CompositeApp: "ca1", Version: "v1", Release: "r1",
+                       DeploymentIntentGroup: "dig1", Namespace: "default", Level: "0"},
+               AppOrder: []string{"a1"},
+               Apps: map[string]*App{"a1": &App{
+                       Name: "a1",
+                       Clusters: map[string]*Cluster{"provider1+cluster1": &Cluster{
+                               Name: "provider1+cluster1",
+                               Resources: map[string]*AppResource{"r1": &AppResource{Name: "r1", Data: "a1c1r1"},
+                                       "r2": &AppResource{Name: "r2", Data: "a1c1r2"},
+                               },
+                               ResOrder: []string{"r1", "r2"}}},
+               },
+               },
+       }
+
+       var updated CompositeApp = CompositeApp{
+               CompMetadata: appcontext.CompositeAppMeta{Project: "proj1", CompositeApp: "ca1", Version: "v2", Release: "r1",
+                       DeploymentIntentGroup: "dig2", Namespace: "default", Level: "0"},
+               AppOrder: []string{"a1", "a2"},
+               Apps: map[string]*App{"a1": &App{
+                       Name: "a1",
+                       Clusters: map[string]*Cluster{"provider1+cluster1": &Cluster{
+                               Name: "provider1+cluster1",
+                               Resources: map[string]*AppResource{"r1": &AppResource{Name: "r1", Data: "a1c1r1"},
+                                       "r3": &AppResource{Name: "r3", Data: "a1c1r3"},
+                               },
+                               ResOrder: []string{"r1", "r3"}}},
+               },
+                       "a2": &App{
+                               Name: "a2",
+                               Clusters: map[string]*Cluster{"provider1+cluster1": &Cluster{
+                                       Name: "provider1+cluster1",
+                                       Resources: map[string]*AppResource{"r3": &AppResource{Name: "r3", Data: "a2c1r3"},
+                                               "r4": &AppResource{Name: "r4", Data: "a2c1r4"},
+                                       },
+                                       ResOrder: []string{"r3", "r4"}},
+                                       "provider1+cluster2": &Cluster{
+                                               Name: "provider1+cluster2",
+                                               Resources: map[string]*AppResource{"r3": &AppResource{Name: "r3", Data: "a2c2r3"},
+                                                       "r4": &AppResource{Name: "r4", Data: "a2c2r4"},
+                                               },
+                                               ResOrder: []string{"r3", "r4"}}},
+                       },
+               },
+       }
+
+       testCases := []struct {
+               label                     string
+               expectedOriginalResources map[string]string
+               expectedUpdatedResources  map[string]string
+               expectedError             error
+       }{
+               {
+                       expectedOriginalResources: map[string]string{"provider1+cluster1": "a1c1r1,a1c1r2", "provider1+cluster2": ""},
+                       expectedUpdatedResources:  map[string]string{"provider1+cluster1": "a1c1r1,a1c1r3,a2c1r3,a2c1r4", "provider1+cluster2": "a2c2r3,a2c2r4"},
+                       expectedError:             nil,
+                       label:                     "Test Update with rollback",
+               },
+       }
+
+       for _, testCase := range testCases {
+               t.Run(testCase.label, func(t *testing.T) {
+                       cid, _ := CreateCompApp(original)
+                       ucid, _ := CreateCompApp(updated)
+                       con := NewProvider(cid)
+
+                       _ = HandleAppContext(cid, nil, InstantiateEvent, &con)
+                       // UPDATE
+                       _ = HandleAppContext(ucid, cid, UpdateEvent, &con)
+                       //Update before previous is completed is not supported
+                       time.Sleep(1 * time.Second)
+                       if !CompareMaps(testCase.expectedUpdatedResources, LoadMap("resource")) {
+                               t.Error("Resources doesn't match", LoadMap("resource"))
+                       }
+                       // ROLLBACK 1
+                       _ = HandleAppContext(cid, ucid, UpdateEvent, &con)
+                       //Update before previous is completed is not supported
+                       time.Sleep(1 * time.Second)
+                       if !CompareMaps(testCase.expectedOriginalResources, LoadMap("resource")) {
+                               t.Error("Resources doesn't match", LoadMap("resource"))
+                       }
+                       // ROLLBACK 2
+                       _ = HandleAppContext(ucid, cid, UpdateEvent, &con)
+                       time.Sleep(1 * time.Second)
+                       if !CompareMaps(testCase.expectedUpdatedResources, LoadMap("resource")) {
+                               t.Error("Resources doesn't match", LoadMap("resource"))
+                       }
+               })
+       }
+}
+
+func TestStop(t *testing.T) {
+
+       cid, _ := CreateCompApp(TestCA)
+       con := NewProvider(cid)
+
+       testCases := []struct {
+               label          string
+               expectedApply  map[string]string
+               expectedDelete map[string]string
+               Status         string
+               expectedError  error
+               stopFlag       bool
+       }{
+               {
+                       expectedApply:  map[string]string{"provider1+cluster1": "a1c1r1,a1c1r2,a2c1r3,a2c1r4", "provider1+cluster2": "a2c2r3,a2c2r4"},
+                       expectedDelete: map[string]string{},
+                       expectedError:  nil,
+                       label:          "Stop call",
+               },
+       }
+       for _, testCase := range testCases {
+               t.Run(testCase.label, func(t *testing.T) {
+                       _ = HandleAppContext(cid, nil, InstantiateEvent, &con)
+                       time.Sleep(2 * time.Second)
+                       // Set AppContextFlag stop to true
+                       UpdateAppContextFlag(cid, StopFlagKey, true)
+                       _ = HandleAppContext(cid, nil, TerminateEvent, &con)
+                       time.Sleep(1 * time.Second)
+                       if !CompareMaps(testCase.expectedApply, LoadMap("apply")) {
+                               t.Error("Apply resources doesn't match", LoadMap("apply"))
+                       }
+                       if !CompareMaps(testCase.expectedDelete, LoadMap("delete")) {
+                               t.Error("Delete resources doesn't match", LoadMap("delete"))
+                       }
+               })
+       }
+}
+
+func TestInstantiateRestart(t *testing.T) {
+
+       cid, _ := CreateCompApp(TestCA)
+       con := NewProvider(cid)
+
+       testCases := []struct {
+               label         string
+               expectedApply map[string]string
+               //expectedDelete map[string]string
+               Status        string
+               expectedError error
+               event         RsyncEvent
+       }{
+               {
+                       expectedApply: map[string]string{"provider1+cluster1": "a1c1r1,a1c1r2,a2c1r3,a2c1r4", "provider1+cluster2": "a2c2r3,a2c2r4"},
+                       //expectedDelete: map[string]string{},
+                       expectedError: nil,
+                       label:         "Instantiate Resources after restart",
+                       event:         InstantiateEvent,
+               },
+       }
+       for _, testCase := range testCases {
+               t.Run(testCase.label, func(t *testing.T) {
+                       _, c := CreateAppContextData(cid)
+                       _ = c.EnqueueToAppContext(cid, nil, testCase.event)
+                       _ = RestartAppContext(cid, &con)
+                       time.Sleep(1 * time.Second)
+                       if !CompareMaps(testCase.expectedApply, LoadMap("apply")) {
+                               t.Error("Apply resources doesn't match", LoadMap("apply"))
+                       }
+               })
+       }
+}
+
+func TestTerminateWithInstantiate(t *testing.T) {
+
+       cid, _ := CreateCompApp(TestCA)
+       con := NewProvider(cid)
+
+       testCases := []struct {
+               label          string
+               expectedApply  map[string]string
+               expectedDelete map[string]string
+               Status         string
+               expectedError  error
+               stopFlag       bool
+       }{
+               {
+                       expectedApply:  map[string]string{"provider1+cluster1": "a1c1r1,a1c1r2,a2c1r3,a2c1r4", "provider1+cluster2": "a2c2r3,a2c2r4"},
+                       expectedDelete: map[string]string{"provider1+cluster1": "a1c1r1,a1c1r2,a2c1r3,a2c1r4", "provider1+cluster2": "a2c2r3,a2c2r4"},
+                       expectedError:  nil,
+                       label:          "Test Terminate With Instantiate Running",
+               },
+       }
+       for _, testCase := range testCases {
+               t.Run(testCase.label, func(t *testing.T) {
+                       _ = HandleAppContext(cid, nil, InstantiateEvent, &con)
+                       time.Sleep(1 * time.Millisecond)
+                       _ = HandleAppContext(cid, nil, TerminateEvent, &con)
+                       time.Sleep(2 * time.Second)
+                       if !CompareMaps(testCase.expectedApply, LoadMap("apply")) {
+                               t.Error("Apply resources doesn't match", LoadMap("apply"))
+                       }
+                       if !CompareMaps(testCase.expectedDelete, LoadMap("delete")) {
+                               t.Error("Delete resources doesn't match", LoadMap("delete"))
+                       }
+               })
+       }
+}
+
+func TestAppDependency(t *testing.T) {
+
+       var ca CompositeApp = CompositeApp{
+               CompMetadata: appcontext.CompositeAppMeta{Project: "proj1", CompositeApp: "ca1", Version: "v1", Release: "r1",
+                       DeploymentIntentGroup: "dig1", Namespace: "default", Level: "0"},
+               AppOrder: []string{"a1", "a2"},
+               Apps: map[string]*App{"a1": {
+                       Name: "a1",
+                       Clusters: map[string]*Cluster{"provider1+cluster1": {
+                               Name:      "provider1+cluster1",
+                               Resources: map[string]*AppResource{"r1": {Name: "r1", Data: "a1c1r1"}},
+                               ResOrder:  []string{"r1"}}},
+                       Dependency: map[string]*Criteria{"a2": {OpStatus: "Deployed", Wait: 1}},
+               }, "a2": {
+                       Name: "a2",
+                       Clusters: map[string]*Cluster{"provider1+cluster1": {
+                               Name:      "provider1+cluster1",
+                               Resources: map[string]*AppResource{"r3": {Name: "r3", Data: "a2c1r3"}},
+                               ResOrder:  []string{"r3"}},
+                               "provider1+cluster2": {
+                                       Name:      "provider1+cluster2",
+                                       Resources: map[string]*AppResource{"r3": {Name: "r3", Data: "a2c2r3"}},
+                                       ResOrder:  []string{"r3"}}},
+               },
+               },
+       }
+
+       cid, _ := CreateCompApp(ca)
+       con := NewProvider(cid)
+
+       testCases := []struct {
+               label             string
+               expectedResources map[string]string
+               Status            string
+               expectedError     error
+               event             RsyncEvent
+       }{
+               {
+                       expectedResources: map[string]string{"provider1+cluster1": "a2c1r3,a1c1r1", "provider1+cluster2": "a2c2r3"},
+                       expectedError:     nil,
+                       label:             "Instantiate Resources",
+                       event:             InstantiateEvent,
+               },
+       }
+       for _, testCase := range testCases {
+               t.Run(testCase.label, func(t *testing.T) {
+                       _ = HandleAppContext(cid, nil, testCase.event, &con)
+                       time.Sleep(5 * time.Second)
+                       if !CompareMaps(testCase.expectedResources, LoadMap("resource")) {
+                               t.Error("Apply resources doesn't match", LoadMap("resource"), testCase.expectedResources)
+                       }
+               })
+       }
+}
+
+func setSuccessForAllHooks(cid string, ca CompositeApp) {
+       acUtils, _ := utils.NewAppContextReference(cid)
+       for _, a := range ca.Apps {
+               for _, c := range a.Clusters {
+                       for _, d := range c.Dependency {
+                               for _, r := range d {
+                                       acUtils.SetResourceReadyStatus(a.Name, c.Name, r, string(SuccessStatus), true)
+                               }
+                       }
+               }
+       }
+}
+
+func TestHooks(t *testing.T) {
+
+       var ca CompositeApp = CompositeApp{
+               CompMetadata: appcontext.CompositeAppMeta{Project: "proj1", CompositeApp: "ca1", Version: "v1", Release: "r1",
+                       DeploymentIntentGroup: "dig1", Namespace: "default", Level: "0"},
+               AppOrder: []string{"a1"},
+               Apps: map[string]*App{"a1": {
+                       Name: "a1",
+                       Clusters: map[string]*Cluster{
+                               "provider1+cluster1": {
+                                       Name:       "provider1+cluster1",
+                                       Resources:  map[string]*AppResource{"r1+Job": {Name: "r1+Job", Data: "a1c1r1"}, "r2+ConfigMap": {Name: "r2+ConfigMap", Data: "a1c1r2"}, "r3+Pod": {Name: "r3+Pod", Data: "a1c1r3"}},
+                                       Dependency: map[string][]string{"pre-install": {"r1+Job"}, "post-install": {"r2+ConfigMap"}},
+                                       ResOrder:   []string{"r3+Pod"}},
+                               "provider1+cluster2": {
+                                       Name:       "provider1+cluster2",
+                                       Resources:  map[string]*AppResource{"r1+Job": {Name: "r1+Job", Data: "a1c2r1"}, "r2+ConfigMap": {Name: "r2+ConfigMap", Data: "a1c2r2"}, "r3+Pod": {Name: "r3+Pod", Data: "a1c2r3"}},
+                                       Dependency: map[string][]string{"pre-install": {"r1+Job"}, "post-install": {"r2+ConfigMap"}},
+                                       ResOrder:   []string{"r3+Pod"}}},
+               },
+               },
+       }
+
+       cid, _ := CreateCompApp(ca)
+       con := NewProvider(cid)
+
+       testCases := []struct {
+               label             string
+               expectedResources map[string]string
+               Status            string
+               expectedError     error
+               event             RsyncEvent
+       }{
+               {
+                       expectedResources: map[string]string{"provider1+cluster1": "a1c1r1,a1c1r3,a1c1r2", "provider1+cluster2": "a1c2r1,a1c2r3,a1c2r2"},
+                       expectedError:     nil,
+                       label:             "Instantiate Resources",
+                       event:             InstantiateEvent,
+               },
+       }
+       for _, testCase := range testCases {
+               t.Run(testCase.label, func(t *testing.T) {
+                       _ = HandleAppContext(cid, nil, testCase.event, &con)
+                       setSuccessForAllHooks(cid, ca)
+                       time.Sleep(5 * time.Second)
+                       if !CompareMaps(testCase.expectedResources, LoadMap("resource")) {
+                               t.Error("Apply resources doesn't match", LoadMap("resource"), testCase.expectedResources)
+                       }
+               })
+       }
+}
+
+func TestGetAllActiveContext(t *testing.T) {
+
+       cid, _ := CreateCompApp(TestCA)
+       _ = NewProvider(cid)
+
+       testCases := []struct {
+               label         string
+               event         RsyncEvent
+               expectedArray []string
+               expectedError error
+       }{
+               {
+                       label:         "Get all active contexts",
+                       event:         InstantiateEvent,
+                       expectedArray: []string{cid},
+                       expectedError: nil,
+               },
+       }
+       for _, testCase := range testCases {
+               t.Run(testCase.label, func(t *testing.T) {
+                       _, c := CreateAppContextData(cid)
+                       _ = c.EnqueueToAppContext(cid, nil, testCase.event)
+                       UpdateAppContextFlag(cid, StopFlagKey, true)
+                       cids, _ := GetAllActiveContext()
+                       time.Sleep(1 * time.Second)
+                       if len(testCase.expectedArray) == len(cids) {
+                               for i, v := range testCase.expectedArray {
+                                       if v == cids[i] {
+                                               continue
+                                       } else {
+                                               t.Error("Mismatch in elements", v, cids[i])
+                                       }
+                               }
+                       } else {
+                               t.Error("Mismatch in length of AllActiveContext", len(testCase.expectedArray), len(cids), cids)
+                       }
+               })
+       }
+}
diff --git a/central-controller/src/rsync/pkg/context/helpers.go b/central-controller/src/rsync/pkg/context/helpers.go
new file mode 100644 (file)
index 0000000..3c2eb16
--- /dev/null
@@ -0,0 +1,239 @@
+// SPDX-License-Identifier: Apache-2.0
+// Copyright (c) 2020 Intel Corporation
+
+package context
+
+import (
+       //      "bytes"
+       "encoding/json"
+       "fmt"
+
+       pkgerrors "github.com/pkg/errors"
+       "gitlab.com/project-emco/core/emco-base/src/orchestrator/pkg/appcontext"
+       "gitlab.com/project-emco/core/emco-base/src/orchestrator/pkg/infra/logutils"
+       . "gitlab.com/project-emco/core/emco-base/src/rsync/pkg/types"
+)
+
+// CreateCompApp creates a AppContext for a composite app, for testing
+func CreateCompApp(ca CompositeApp) (string, error) {
+
+       var compositeHandle interface{}
+       var err error
+
+       context := appcontext.AppContext{}
+       ctxval, err := context.InitAppContext()
+       if err != nil {
+               return "", pkgerrors.Wrap(err, "Error creating AppContext CompositeApp")
+       }
+       contextID := fmt.Sprintf("%v", ctxval)
+
+       if compositeHandle, err = context.CreateCompositeApp(); err != nil {
+               return "", pkgerrors.Wrap(err, "Error creating CompositeApp handle")
+       }
+
+       if err = context.AddCompositeAppMeta(ca.CompMetadata); err != nil {
+               return "", pkgerrors.Wrap(err, "Error Adding CompositeAppMeta")
+       }
+       appOrder, err := json.Marshal(map[string][]string{"apporder": ca.AppOrder})
+       if err != nil {
+               return "", pkgerrors.Wrap(err, "Error adding app order instruction")
+       }
+       _, err = context.AddInstruction(compositeHandle, "app", "order", string(appOrder))
+       if err != nil {
+               return "", pkgerrors.Wrap(err, "Error adding app order instruction")
+       }
+
+       for _, app := range ca.Apps {
+               a, err := context.AddApp(compositeHandle, app.Name)
+               if err != nil {
+                       return "", pkgerrors.Wrap(err, "Error Adding App")
+               }
+               if app.Dependency != nil {
+                       var dep []AppCriteria
+                       for i, j := range app.Dependency {
+                               l := AppCriteria{App: i, OpStatus: j.OpStatus, Wait: j.Wait}
+                               dep = append(dep, l)
+                       }
+                       dependency, err := json.Marshal(dep)
+                       if err != nil {
+                               return "", pkgerrors.Wrap(err, "Error adding depencency instruction")
+                       }
+                       _, err = context.AddLevelValue(a, "instruction/dependency", string(dependency))
+                       if err != nil {
+                               return "", pkgerrors.Wrap(err, "Error Adding depencency instruction")
+                       }
+               }
+               for _, cluster := range app.Clusters {
+                       c, err := context.AddCluster(a, cluster.Name)
+                       if err != nil {
+                               return "", pkgerrors.Wrap(err, "Error Adding Cluster")
+                       }
+                       resOrder, err := json.Marshal(map[string][]string{"resorder": cluster.ResOrder})
+                       _, err = context.AddInstruction(c, "resource", "order", string(resOrder))
+                       if err != nil {
+                               return "", pkgerrors.Wrap(err, "Error Adding resorder")
+                       }
+                       resdependency, err := json.Marshal(map[string]map[string][]string{"resdependency": cluster.Dependency})
+                       _, err = context.AddInstruction(c, "resource", "dependency", string(resdependency))
+                       if err != nil {
+                               return "", pkgerrors.Wrap(err, "Error Adding resdependency")
+                       }
+                       for _, res := range cluster.Resources {
+                               _, err = context.AddResource(c, res.Name, res.Data)
+                               if err != nil {
+                                       return "", pkgerrors.Wrap(err, "Error Adding Resource")
+                               }
+                       }
+               }
+       }
+       return contextID, nil
+}
+
+// ReadAppContext reads a composite app for AppContext
+func ReadAppContext(contextID interface{}) (CompositeApp, error) {
+       var ca CompositeApp
+
+       acID := fmt.Sprintf("%v", contextID)
+       ac := appcontext.AppContext{}
+       _, err := ac.LoadAppContext(acID)
+       if err != nil {
+               logutils.Error("", logutils.Fields{"err": err})
+               return CompositeApp{}, err
+       }
+
+       caMeta, err := ac.GetCompositeAppMeta()
+       // ignore error (in case appcontext has no metadata) VERIFY
+       if err == nil {
+               ca.CompMetadata = caMeta
+       }
+
+       appsOrder, err := ac.GetAppInstruction("order")
+       if err != nil {
+               return CompositeApp{}, err
+       }
+       var appList map[string][]string
+       json.Unmarshal([]byte(appsOrder.(string)), &appList)
+       ca.AppOrder = appList["apporder"]
+       appsList := make(map[string]*App)
+       for _, app := range appList["apporder"] {
+               clusterNames, err := ac.GetClusterNames(app)
+               if err != nil {
+                       return CompositeApp{}, err
+               }
+               //var clusterList []Cluster
+               clusterList := make(map[string]*Cluster)
+               for k := 0; k < len(clusterNames); k++ {
+                       cluster := clusterNames[k]
+                       resorder, err := ac.GetResourceInstruction(app, cluster, "order")
+                       if err != nil {
+                               logutils.Error("Resorder not found for cluster ", logutils.Fields{"cluster": cluster})
+                               // In Status AppContext some clusters may not have resorder
+                               // Only used to collect status
+                               continue
+                       }
+                       var aov map[string][]string
+                       json.Unmarshal([]byte(resorder.(string)), &aov)
+                       resList := make(map[string]*AppResource)
+                       for _, res := range aov["resorder"] {
+                               r := &AppResource{Name: res}
+                               resList[res] = r
+                       }
+                       clusterList[cluster] = &Cluster{Name: cluster, Resources: resList, ResOrder: aov["resorder"]}
+                       resdependency, err := ac.GetResourceInstruction(app, cluster, "dependency")
+                       if err != nil {
+                               // Not all applications have dependency
+                               continue
+                       }
+                       var dov map[string]map[string][]string
+                       err = json.Unmarshal([]byte(resdependency.(string)), &dov)
+                       if err != nil {
+                               logutils.Error("Res dependency Marshalling error, ignoring ", logutils.Fields{"cluster": cluster, "dependency": resdependency.(string)})
+                               continue
+                       }
+                       for _, lt := range dov["resdependency"] {
+                               for _, res := range lt {
+                                       r := &AppResource{Name: res}
+                                       //resList = append(resList, r)
+                                       resList[res] = r
+                               }
+                       }
+                       clusterList[cluster] = &Cluster{Name: cluster, Resources: resList, ResOrder: aov["resorder"], Dependency: dov["resdependency"]}
+               }
+               dep, err := ac.GetAppLevelInstruction(app, "dependency")
+               depList := make(map[string]*Criteria)
+               if err == nil {
+                       var a []AppCriteria
+                       // If instruction available read it
+                       json.Unmarshal([]byte(dep.(string)), &a)
+                       for _, crt := range a {
+                               depList[crt.App] = &Criteria{Wait: crt.Wait, OpStatus: crt.OpStatus}
+                       }
+               }
+               appsList[app] = &App{Name: app, Clusters: clusterList, Dependency: depList}
+       }
+       ca.Apps = appsList
+       return ca, nil
+}
+
+// PrintCompositeApp prints the composite app
+func PrintCompositeApp(ca CompositeApp) {
+
+       fmt.Printf("Metadata: %v\n", ca.CompMetadata)
+       fmt.Printf("AppOrder: %v\n", ca.AppOrder)
+       for _, app := range ca.Apps {
+               fmt.Println("")
+               fmt.Println("  App: ", app.Name)
+               fmt.Println("  Dependency: ", app.Dependency)
+               for _, cluster := range app.Clusters {
+
+                       fmt.Println("    Cluster: ", cluster.Name)
+                       fmt.Printf("      ResourceOrder: %v\n", cluster.ResOrder)
+                       fmt.Println("      Resources: ")
+                       for _, res := range cluster.Resources {
+                               fmt.Printf("        %v\n", res.Name)
+                       }
+               }
+       }
+}
+
+// FindApp finds app in the appcontext and returns true or false
+func FindApp(ca CompositeApp, app string) bool {
+       for _, a := range ca.Apps {
+               if app == a.Name {
+                       return true
+               }
+       }
+       return false
+}
+
+// FindCluster finds cluster in an app in the appcontext and returns true or false
+func FindCluster(ca CompositeApp, app string, cluster string) bool {
+       for _, a := range ca.Apps {
+               if app == a.Name {
+                       for _, c := range ca.Apps[app].Clusters {
+                               if cluster == c.Name {
+                                       return true
+                               }
+                       }
+               }
+       }
+       return false
+}
+
+// FindCluster finds resource in a cluster in an app in the appcontext and returns true or false
+func FindResource(ca CompositeApp, app, cluster, res string) bool {
+       for _, a := range ca.Apps {
+               if app == a.Name {
+                       for _, c := range ca.Apps[app].Clusters {
+                               if cluster == c.Name {
+                                       for _, r := range ca.Apps[app].Clusters[cluster].Resources {
+                                               if res == r.Name {
+                                                       return true
+                                               }
+                                       }
+                               }
+                       }
+               }
+       }
+       return false
+}
diff --git a/central-controller/src/rsync/pkg/context/mock.go b/central-controller/src/rsync/pkg/context/mock.go
new file mode 100644 (file)
index 0000000..dbc4f01
--- /dev/null
@@ -0,0 +1,306 @@
+// SPDX-License-Identifier: Apache-2.0
+// Copyright (c) 2020 Intel Corporation
+
+package context
+
+import (
+       "context"
+       "fmt"
+       "reflect"
+       "sort"
+       "strings"
+       "sync"
+
+       pkgerrors "github.com/pkg/errors"
+       "gitlab.com/project-emco/core/emco-base/src/orchestrator/pkg/appcontext"
+       . "gitlab.com/project-emco/core/emco-base/src/rsync/pkg/types"
+       //"time"
+)
+
+// Match stores information about resources applied in clusters
+type Match struct {
+       // Collects all resources that are deleted
+       DeleteMatchList sync.Map
+       // Collects all resources that are applied
+       ApplyMatchList sync.Map
+       // Collects all resources that are currently applied on the cluster
+       ResourceList sync.Map
+       // Resources committed
+       CommitList sync.Map
+}
+
+// MatchList to collect resources
+var MatchList Match
+
+// MockConnector mocks connector interface
+type MockConnector struct {
+       sync.Mutex
+       Clients *sync.Map
+       cid     string
+}
+
+func NewProvider(id interface{}) MockConnector {
+       MatchList.DeleteMatchList = sync.Map{}
+       MatchList.ApplyMatchList = sync.Map{}
+       MatchList.ResourceList = sync.Map{}
+       MatchList.CommitList = sync.Map{}
+
+       return MockConnector{
+               cid: fmt.Sprintf("%v", id),
+       }
+}
+
+func (c *MockConnector) GetClientProviders(app, cluster, level, namespace string) (ClientProvider, error) {
+       c.Lock()
+       defer c.Unlock()
+       if c.Clients == nil {
+               c.Clients = new(sync.Map)
+       }
+       _, ok := c.Clients.Load(cluster)
+       if !ok {
+               m := MockClient{cluster: cluster, retryCounter: 0, deletedCounter: 0}
+               m.lock = new(sync.Mutex)
+               c.Clients.Store(cluster, m)
+       }
+       m, _ := c.Clients.Load(cluster)
+       n := m.(MockClient)
+       return &n, nil
+}
+
+// MockClient mocks client
+type MockClient struct {
+       lock           *sync.Mutex
+       cluster        string
+       retryCounter   int
+       deletedCounter int
+       applyCounter   int
+}
+
+func (m *MockClient) Commit(ctx context.Context, ref interface{}) error {
+       str := fmt.Sprintf("%v", ref)
+       i, ok := MatchList.CommitList.Load(m.cluster)
+       var st string
+       if !ok {
+               st = string(str)
+       } else {
+               st = fmt.Sprintf("%v", i) + "," + string(str)
+       }
+       MatchList.CommitList.Store(m.cluster, st)
+       return nil
+}
+func (m *MockClient) Create(name string, ref interface{}, content []byte) (interface{}, error) {
+       return ref, nil
+}
+
+func (m *MockClient) TagResource(res []byte, l string) ([]byte, error) {
+       return res, nil
+}
+
+// Apply Collects resources applied to cluster
+func (m *MockClient) Apply(name string, ref interface{}, content []byte) (interface{}, error) {
+       m.lock.Lock()
+       defer m.lock.Unlock()
+       m.applyCounter = m.applyCounter + 1
+       // Simulate delay
+       //time.Sleep(1 * time.Millisecond)
+       if len(content) <= 0 {
+               return ref, nil
+       }
+       i, ok := MatchList.ApplyMatchList.Load(m.cluster)
+       var str string
+       if !ok {
+               str = string(content)
+       } else {
+               str = fmt.Sprintf("%v", i) + "," + string(content)
+       }
+       MatchList.ApplyMatchList.Store(m.cluster, str)
+
+       i, ok = MatchList.ResourceList.Load(m.cluster)
+       if !ok {
+               str = string(content)
+       } else {
+               x := fmt.Sprintf("%v", i)
+               if x != "" {
+                       str = fmt.Sprintf("%v", i) + "," + string(content)
+               } else {
+                       str = string(content)
+               }
+       }
+       MatchList.ResourceList.Store(m.cluster, str)
+       if ref != nil {
+               str = fmt.Sprintf("%v", ref) + "," + string(content)
+       } else {
+               str = string(content)
+       }
+       return str, nil
+}
+
+// Delete Collects resources deleted from cluster
+func (m *MockClient) Delete(name string, ref interface{}, content []byte) (interface{}, error) {
+       m.lock.Lock()
+       defer m.lock.Unlock()
+       m.deletedCounter = m.deletedCounter + 1
+       if len(content) <= 0 {
+               return nil, nil
+       }
+       i, ok := MatchList.DeleteMatchList.Load(m.cluster)
+       var str string
+       if !ok {
+               str = string(content)
+       } else {
+               str = fmt.Sprintf("%v", i) + "," + string(content)
+       }
+       MatchList.DeleteMatchList.Store(m.cluster, str)
+
+       // Remove the resource from resourcre list
+       i, ok = MatchList.ResourceList.Load(m.cluster)
+       if !ok {
+               fmt.Println("Deleting resource not applied on cluster", m.cluster)
+               return nil, pkgerrors.Errorf("Deleting resource not applied on cluster " + m.cluster)
+       } else {
+               // Delete it from the string
+               a := strings.Split(fmt.Sprintf("%v", i), ",")
+               for idx, v := range a {
+                       if v == string(content) {
+                               a = append(a[:idx], a[idx+1:]...)
+                               break
+                       }
+               }
+               if len(a) > 0 {
+                       str = strings.Join(a, ",")
+               } else {
+                       str = ""
+               }
+               MatchList.ResourceList.Store(m.cluster, str)
+       }
+       if ref != nil {
+               str = fmt.Sprintf("%v", ref) + "," + string(content)
+       } else {
+               str = string(content)
+       }
+       return str, nil
+}
+
+func (m *MockClient) Get(name string, gvkRes []byte) ([]byte, error) {
+       b := []byte("test")
+       return b, nil
+}
+func (m *MockClient) IsReachable() error {
+       if m.cluster == "provider1+cluster1" {
+               if m.retryCounter < 0 {
+                       fmt.Println("Counter: ", m.retryCounter)
+                       m.retryCounter = m.retryCounter + 1
+                       return pkgerrors.Errorf("Unreachable: " + m.cluster)
+               }
+       }
+       return nil
+}
+
+func (m *MockClient) StartClusterWatcher() error {
+       return nil
+}
+
+func (m *MockClient) ApplyStatusCR(name string, content []byte) error {
+       return nil
+}
+
+func (m *MockClient) DeleteStatusCR(name string, content []byte) error {
+       return nil
+}
+func (m *MockClient) ApplyConfig(ctx context.Context, config interface{}) error {
+       return nil
+}
+
+func (m *MockClient) DeleteConfig(ctx context.Context, config interface{}) error {
+       return nil
+}
+
+func (m *MockClient) CleanClientProvider() error {
+       return nil
+}
+
+func LoadMap(str string) map[string]string {
+       m := make(map[string]string)
+       if str == "apply" {
+               MatchList.ApplyMatchList.Range(func(k, v interface{}) bool {
+                       m[fmt.Sprint(k)] = v.(string)
+                       return true
+               })
+       } else if str == "delete" {
+               MatchList.DeleteMatchList.Range(func(k, v interface{}) bool {
+                       m[fmt.Sprint(k)] = v.(string)
+                       return true
+               })
+       } else if str == "resource" {
+               MatchList.ResourceList.Range(func(k, v interface{}) bool {
+                       m[fmt.Sprint(k)] = v.(string)
+                       return true
+               })
+       } else if str == "commit" {
+               MatchList.CommitList.Range(func(k, v interface{}) bool {
+                       m[fmt.Sprint(k)] = v.(string)
+                       return true
+               })
+       }
+       return m
+}
+
+func CompareMaps(m, n map[string]string) bool {
+       var m1, n1 map[string][]string
+       m1 = make(map[string][]string)
+       n1 = make(map[string][]string)
+       for k, v := range m {
+               a := strings.Split(v, ",")
+               sort.Strings(a)
+               m1[k] = a
+       }
+       for k, v := range n {
+               a := strings.Split(v, ",")
+               sort.Strings(a)
+               n1[k] = a
+       }
+       return reflect.DeepEqual(m1, n1)
+}
+
+func GetAppContextStatus(cid interface{}, key string) (string, error) {
+       //var acStatus appcontext.AppContextStatus = appcontext.AppContextStatus{}
+       ac := appcontext.AppContext{}
+       _, err := ac.LoadAppContext(cid)
+       if err != nil {
+               return "", err
+       }
+       hc, err := ac.GetCompositeAppHandle()
+       if err != nil {
+               return "", err
+       }
+       dsh, err := ac.GetLevelHandle(hc, key)
+       if dsh != nil {
+               v, err := ac.GetValue(dsh)
+               if err != nil {
+                       return "", err
+               }
+               str := fmt.Sprintf("%v", v)
+               return str, nil
+       }
+       return "", err
+}
+
+func UpdateAppContextFlag(cid interface{}, key string, b bool) error {
+       ac := appcontext.AppContext{}
+       _, err := ac.LoadAppContext(cid)
+       if err != nil {
+               return err
+       }
+       h, err := ac.GetCompositeAppHandle()
+       if err != nil {
+
+               return err
+       }
+       sh, err := ac.GetLevelHandle(h, key)
+       if sh == nil {
+               _, err = ac.AddLevelValue(h, key, b)
+       } else {
+               err = ac.UpdateValue(sh, b)
+       }
+       return err
+}
diff --git a/central-controller/src/rsync/pkg/context/queueUtils.go b/central-controller/src/rsync/pkg/context/queueUtils.go
new file mode 100644 (file)
index 0000000..79decdd
--- /dev/null
@@ -0,0 +1,176 @@
+// SPDX-License-Identifier: Apache-2.0
+// Copyright (c) 2020 Intel Corporation
+
+package context
+
+import (
+       "encoding/json"
+       "fmt"
+
+       pkgerrors "github.com/pkg/errors"
+       "gitlab.com/project-emco/core/emco-base/src/orchestrator/pkg/appcontext"
+       log "gitlab.com/project-emco/core/emco-base/src/orchestrator/pkg/infra/logutils"
+       types "gitlab.com/project-emco/core/emco-base/src/rsync/pkg/types"
+)
+
+type AppContextQueueUtils struct {
+       ac appcontext.AppContext
+}
+
+// GetAppContextQueue shall return the AppContextQueue
+func (aq *AppContextQueueUtils) GetAppContextQueue() (types.AppContextQueue, error) {
+
+       h, err := aq.ac.GetCompositeAppHandle()
+       if err != nil {
+               log.Error("Error getting CompAppHandle", log.Fields{"err": err})
+               return types.AppContextQueue{}, err
+       }
+
+       qKey := types.AppContextEventQueueKey
+
+       qh, err := aq.ac.GetLevelHandle(h, qKey)
+       if err != nil {
+               log.Info("Error in getting the AppContextQueue Level handle", log.Fields{"err": err})
+               return types.AppContextQueue{}, err
+       }
+       if qh != nil {
+               v, err := aq.ac.GetValue(qh)
+               if err != nil {
+                       log.Error("Error getting vale for the AppQ handle", log.Fields{"err": err})
+               }
+
+               acQ := types.AppContextQueue{}
+               js, err := json.Marshal(v)
+               if err != nil {
+                       log.Error("Marshal Error in GetAppContextQueue", log.Fields{"err": err})
+                       return types.AppContextQueue{}, err
+               }
+               err = json.Unmarshal(js, &acQ)
+               if err != nil {
+                       log.Error("UnMarshal Error in GetAppContextQueue", log.Fields{"err": err})
+                       return types.AppContextQueue{}, err
+               }
+               return acQ, nil
+
+       }
+       log.Info("AppContextQueue Level handle is NULL", log.Fields{})
+       return types.AppContextQueue{}, err
+}
+
+// GetAppContextQueuePeek shall return the String value at the peak of the AppContextQueue
+func (aq *AppContextQueueUtils) GetAppContextQueuePeek() (types.AppContextQueueElement, error) {
+       acQ, err := aq.GetAppContextQueue()
+       if err != nil {
+               log.Error("Error in getting AppContextQueue", log.Fields{"err": err})
+               return types.AppContextQueueElement{}, err
+       }
+       q := acQ.AcQueue
+       if len(q) == 0 {
+               return types.AppContextQueueElement{}, pkgerrors.Errorf("No element in AppContextQueue")
+       }
+
+       return q[0], nil
+}
+
+// GetAppContextQueueLength shall return the length of the AppContextQueue
+func (aq *AppContextQueueUtils) GetAppContextQueueLength() (int, error) {
+       acQ, err := aq.GetAppContextQueue()
+       if err != nil {
+               log.Error("Error in getting AppContextQueue", log.Fields{"err": err})
+               return 0, err
+       }
+       q := acQ.AcQueue
+       if len(q) == 0 {
+               log.Info("The length of AppContextQueue is 0", log.Fields{"err": err})
+               return 0, nil
+       }
+       return len(q), nil
+}
+
+// Enqueue shall append new Q-Elemenet in the string format
+func (aq *AppContextQueueUtils) Enqueue(qElement types.AppContextQueueElement) (bool, error) {
+
+       acQ, err := aq.GetAppContextQueue()
+       if err != nil {
+               log.Info("No existing AppContextQueue, Creating AppContextQueue", log.Fields{"err": err})
+               return aq.CreateQueue(qElement)
+       }
+       if len(acQ.AcQueue) >= 1 {
+               q := acQ.AcQueue
+               q = append(q, qElement)
+               return aq.UpdateQueue(q)
+       }
+       return false, nil
+}
+
+func (aq *AppContextQueueUtils) UpdateQueue(q []types.AppContextQueueElement) (bool, error) {
+       h, err := aq.ac.GetCompositeAppHandle()
+       if err != nil {
+               log.Error("Error in getting CompApp handle in UpdateQueue", log.Fields{"err": err})
+               return false, err
+       }
+
+       qKey := types.AppContextEventQueueKey
+
+       qHandle, err := aq.ac.GetLevelHandle(h, qKey)
+       if err != nil {
+               log.Error("Error in getting Qhandle", log.Fields{"err": err})
+               return false, err
+       }
+       acQ := types.AppContextQueue{AcQueue: q}
+       err = aq.ac.UpdateValue(qHandle, acQ)
+       if err != nil {
+               log.Error("Error in updating Qhandle", log.Fields{"err": err})
+               return false, err
+       }
+
+       return true, nil
+}
+
+func (aq *AppContextQueueUtils) CreateQueue(qElement types.AppContextQueueElement) (bool, error) {
+       h, err := aq.ac.GetCompositeAppHandle()
+       if err != nil {
+               log.Error("Error in getting CompApp handle in CreateQueue", log.Fields{"err": err})
+               return false, err
+       }
+       var q []types.AppContextQueueElement
+       q = append(q, qElement)
+       acQ := types.AppContextQueue{AcQueue: q}
+
+       qKey := types.AppContextEventQueueKey
+       qHandle, err := aq.ac.AddLevelValue(h, qKey, acQ)
+       if err != nil {
+               log.Error("Error in Adding AppContextQueue Level", log.Fields{"err": err})
+               return false, err
+       }
+       qhandle := fmt.Sprintf("%v", qHandle)
+       log.Info("AppContextQueue created :: Qhandle :: ", log.Fields{"qhandle": qhandle})
+       return true, nil
+}
+func (aq *AppContextQueueUtils) FindFirstPending() (int, types.AppContextQueueElement) {
+
+       q, err := aq.GetAppContextQueue()
+       if err != nil {
+               return -1, types.AppContextQueueElement{}
+       }
+       for i, v := range q.AcQueue {
+               if v.Status == "Pending" {
+                       return i, v
+               }
+       }
+       return -1, types.AppContextQueueElement{}
+}
+func (aq *AppContextQueueUtils) UpdateStatus(index int, status string) error {
+       acQ, err := aq.GetAppContextQueue()
+       if err != nil {
+               log.Error("Error in getting AppContextQueue", log.Fields{"err": err})
+               return err
+       }
+       q := acQ.AcQueue
+       if index >= len(q) || index < 0 {
+               return pkgerrors.Errorf("Invalid index AppContextQueue")
+       }
+       q[index].Status = status
+       _, err = aq.UpdateQueue(q)
+       return err
+}
diff --git a/central-controller/src/rsync/pkg/context/restart.go b/central-controller/src/rsync/pkg/context/restart.go
new file mode 100644 (file)
index 0000000..de57cb1
--- /dev/null
@@ -0,0 +1,112 @@
+// SPDX-License-Identifier: Apache-2.0
+// Copyright (c) 2021 Intel Corporation
+
+package context
+
+/*
+restart.go contains all the functions required for resuming the RYSNC once it restarts
+*/
+
+import (
+       "fmt"
+       "strings"
+
+       pkgerrors "github.com/pkg/errors"
+       "gitlab.com/project-emco/core/emco-base/src/orchestrator/pkg/infra/contextdb"
+       "gitlab.com/project-emco/core/emco-base/src/orchestrator/pkg/infra/logutils"
+       "gitlab.com/project-emco/core/emco-base/src/rsync/pkg/connector"
+)
+
+const prefix string = "/activecontext/"
+
+// RecordActiveContext shall insert into contextDB a key and value like /activecontext/99999999888/->99999999888. 99999999888 is sample AppcontextID
+// It shall take in activeContextID
+func RecordActiveContext(acID string) (bool, error) {
+
+       exists, _ := ifContextIDActive(acID)
+       if exists {
+               logutils.Info("ContextID already active", logutils.Fields{"acID": acID})
+               return false, nil
+       }
+
+       k := prefix + acID + "/"
+       err := contextdb.Db.Put(k, acID)
+       if err != nil {
+               logutils.Info("Error saving the active contextID", logutils.Fields{"err": err.Error(), "contextID": acID})
+               return false, pkgerrors.Errorf("Error:: %s saving contextID:: %s", err.Error(), acID)
+       }
+
+       return true, nil
+}
+
+// GetAllActiveContext shall return all the active contextIDs
+func GetAllActiveContext() ([]string, error) {
+       aContexts, err := contextdb.Db.GetAllKeys(prefix)
+       if err != nil {
+               logutils.Info("No active context handles for restart", logutils.Fields{})
+               return nil, nil
+       }
+       aCtxIDs := make([]string, len(aContexts))
+       for i, s := range aContexts {
+               str := fmt.Sprintf("%v", s)
+               key := strings.Split(str, "/")
+               if len(key) == 4 && key[1] == "activecontext" {
+                       aCtxIDs[i] = key[2]
+               }
+       }
+       return aCtxIDs, nil
+}
+
+// ifContextIDActive takes in a contextID and checks if its active or not
+func ifContextIDActive(acID string) (bool, error) {
+
+       k := prefix + acID + "/"
+       var value string
+       err := contextdb.Db.Get(k, &value)
+       if err != nil {
+               return false, nil
+       }
+
+       return true, nil
+
+}
+
+// DeleteActiveContextRecord deletes an active contextID
+func DeleteActiveContextRecord(acID string) (bool, error) {
+       exists, _ := ifContextIDActive(acID)
+       if !exists {
+               logutils.Info("ContextID not active", logutils.Fields{"acID": acID})
+               return false, pkgerrors.Errorf("Error deleting, contextID:: %s not active", acID)
+       }
+       k := prefix + acID + "/"
+       err := contextdb.Db.Delete(k)
+       if err != nil {
+               logutils.Info("Error deleting the contextID", logutils.Fields{"acID": acID, "Error": err.Error()})
+               return false, pkgerrors.Errorf("Error:: %s deleting contextID:: %s ", err.Error(), acID)
+       }
+       return true, nil
+}
+
+// RestoreActiveContext shall be called everytime the rsync restarts.
+// It makes sure that the AppContexts which were in active state before rsync
+// got cancelled, are restored and queued up again for processing.
+func RestoreActiveContext() error {
+       logutils.Info("Restoring active context....", logutils.Fields{})
+       acIDs, err := GetAllActiveContext()
+       if err != nil {
+               logutils.Info("Error getting all active contextIDs while restoring", logutils.Fields{})
+               return nil
+       }
+
+       logutils.Info("Total active contexts to be restored", logutils.Fields{"Total active contextIDs to be restored": len(acIDs)})
+
+       for _, acID := range acIDs {
+               con := connector.NewProvider(acID)
+               err = RestartAppContext(acID, &con)
+               if err != nil {
+                       logutils.Info("Error in restoring active contextID in HandleAppContext", logutils.Fields{"acID": acID, "Error": err})
+                       return nil
+               }
+       }
+       return nil
+}
diff --git a/central-controller/src/rsync/pkg/context/routines.go b/central-controller/src/rsync/pkg/context/routines.go
new file mode 100644 (file)
index 0000000..086b7b1
--- /dev/null
@@ -0,0 +1,691 @@
+// SPDX-License-Identifier: Apache-2.0
+// Copyright (c) 2020 Intel Corporation
+
+package context
+
+import (
+       "bytes"
+       "context"
+       "fmt"
+       "time"
+
+       pkgerrors "github.com/pkg/errors"
+       "gitlab.com/project-emco/core/emco-base/src/orchestrator/pkg/appcontext"
+       log "gitlab.com/project-emco/core/emco-base/src/orchestrator/pkg/infra/logutils"
+       "gitlab.com/project-emco/core/emco-base/src/rsync/pkg/depend"
+       "gitlab.com/project-emco/core/emco-base/src/rsync/pkg/internal/utils"
+       "gitlab.com/project-emco/core/emco-base/src/rsync/pkg/status"
+       . "gitlab.com/project-emco/core/emco-base/src/rsync/pkg/types"
+       "golang.org/x/sync/errgroup"
+)
+
+// Check status of AppContext against the event to see if it is valid
+func (c *Context) checkStateChange(e RsyncEvent) (StateChange, bool, error) {
+       var supported bool = false
+       var err error
+       var dState, cState appcontext.AppContextStatus
+       var event StateChange
+
+       event, ok := StateChanges[e]
+       if !ok {
+               return StateChange{}, false, pkgerrors.Errorf("Invalid Event %s:", e)
+       }
+       // Check Stop flag return error no processing desired
+       sFlag, err := c.acRef.GetAppContextFlag(StopFlagKey)
+       if err != nil {
+               return event, false, pkgerrors.Errorf("AppContext Error: %s:", err)
+       }
+       if sFlag {
+               return event, false, pkgerrors.Errorf("Stop flag set for context: %s", c.acID)
+       }
+       // Check PendingTerminate Flag
+       tFlag, err := c.acRef.GetAppContextFlag(PendingTerminateFlagKey)
+       if err != nil {
+               return event, false, pkgerrors.Errorf("AppContext Error: %s:", err)
+       }
+
+       if tFlag && e != TerminateEvent {
+               return event, false, pkgerrors.Errorf("Terminate Flag is set, Ignoring event: %s:", e)
+       }
+       // Update the desired state of the AppContext based on this event
+       state, err := c.acRef.GetAppContextStatus(CurrentStateKey)
+       if err != nil {
+               return event, false, err
+       }
+       for _, s := range event.SState {
+               if s == state.Status {
+                       supported = true
+                       break
+               }
+       }
+       if !supported {
+               //Exception to state machine, if event is terminate and the current state is already
+               // terminated, don't change the status to TerminateFailed
+               if e == TerminateEvent && state.Status == appcontext.AppContextStatusEnum.Terminated {
+                       return event, false, pkgerrors.Errorf("Invalid Source state %s for the Event %s:", state, e)
+               }
+               return event, true, pkgerrors.Errorf("Invalid Source state %s for the Event %s:", state, e)
+       } else {
+               dState.Status = event.DState
+               cState.Status = event.CState
+       }
+       // Event is supported. Update Desired state and current state
+       err = c.acRef.UpdateAppContextStatus(DesiredStateKey, dState)
+       if err != nil {
+               return event, false, err
+       }
+       err = c.acRef.UpdateAppContextStatus(CurrentStateKey, cState)
+       if err != nil {
+               return event, false, err
+       }
+       err = c.acRef.UpdateAppContextStatus(StatusKey, cState)
+       if err != nil {
+               return event, false, err
+       }
+       return event, true, nil
+}
+
+// UpdateQStatus updates status of an element in the queue
+func (c *Context) UpdateQStatus(index int, status string) error {
+       qUtils := &AppContextQueueUtils{ac: c.acRef.GetAppContextHandle()}
+       c.Lock.Lock()
+       defer c.Lock.Unlock()
+       if err := qUtils.UpdateStatus(index, status); err != nil {
+               return err
+       }
+       return nil
+}
+
+// If terminate event recieved set flag to ignore other events
+func (c *Context) terminateContextRoutine() {
+       // Set Terminate Flag to Pending
+       if err := c.acRef.UpdateAppContextFlag(PendingTerminateFlagKey, true); err != nil {
+               return
+       }
+       // Make all waiting goroutines to stop waiting
+       if c.cancel != nil {
+               c.cancel()
+       }
+}
+
+// Start Main Thread for handling
+func (c *Context) startMainThread(a interface{}, con Connector) error {
+       acID := fmt.Sprintf("%v", a)
+
+       ref, err := utils.NewAppContextReference(acID)
+       if err != nil {
+               return err
+       }
+       // Read AppContext into CompositeApp structure
+       c.ca, err = ReadAppContext(a)
+       if err != nil {
+               log.Error("Fatal! error reading appContext", log.Fields{"err": err})
+               return err
+       }
+       c.acID = acID
+       c.con = con
+       c.acRef = ref
+       // Wait for 2 secs
+       c.waitTime = 2
+       c.maxRetry = getMaxRetries()
+       // Check flags in AppContext to create if they don't exist and add default values
+       _, err = c.acRef.GetAppContextStatus(CurrentStateKey)
+       // If CurrentStateKey doesn't exist assuming this is the very first event for the appcontext
+       if err != nil {
+               as := appcontext.AppContextStatus{Status: appcontext.AppContextStatusEnum.Created}
+               if err := c.acRef.UpdateAppContextStatus(CurrentStateKey, as); err != nil {
+                       return err
+               }
+       }
+       _, err = c.acRef.GetAppContextFlag(StopFlagKey)
+       // Assume doesn't exist and add
+       if err != nil {
+               if err := c.acRef.UpdateAppContextFlag(StopFlagKey, false); err != nil {
+                       return err
+               }
+       }
+       _, err = c.acRef.GetAppContextFlag(PendingTerminateFlagKey)
+       // Assume doesn't exist and add
+       if err != nil {
+               if err := c.acRef.UpdateAppContextFlag(PendingTerminateFlagKey, false); err != nil {
+                       return err
+               }
+       }
+       _, err = c.acRef.GetAppContextStatus(StatusKey)
+       // If CurrentStateKey doesn't exist assuming this is the very first event for the appcontext
+       if err != nil {
+               as := appcontext.AppContextStatus{Status: appcontext.AppContextStatusEnum.Created}
+               if err := c.acRef.UpdateAppContextStatus(StatusKey, as); err != nil {
+                       return err
+               }
+       }
+       // Read the statusAcID to use with status
+       c.statusAcID, err = c.acRef.GetStatusAppContext(StatusAppContextIDKey)
+       if err != nil {
+               // Use appcontext as status appcontext also
+               c.statusAcID = c.acID
+               c.scRef = c.acRef
+       } else {
+               scRef, err := utils.NewAppContextReference(c.statusAcID)
+               if err != nil {
+                       return err
+               }
+               c.scRef = scRef
+       }
+       // Intialize dependency management
+       c.dm = depend.NewDependManager(c.acID)
+       // Start Routine to handle AppContext
+       go c.appContextRoutine()
+       return nil
+}
+
+// Handle AppContext
+func (c *Context) appContextRoutine() {
+       var lctx context.Context
+       var l context.Context
+       var lGroup *errgroup.Group
+       var lDone context.CancelFunc
+       var op RsyncOperation
+
+       qUtils := &AppContextQueueUtils{ac: c.acRef.GetAppContextHandle()}
+       // Create context for the running threads
+       ctx, done := context.WithCancel(context.Background())
+       gGroup, gctx := errgroup.WithContext(ctx)
+       // Stop all running goroutines
+       defer done()
+       // Start thread to watch for external stop flag
+       gGroup.Go(func() error {
+               ticker := time.NewTicker(1 * time.Second)
+               for {
+                       select {
+                       case <-ticker.C:
+                               flag, err := c.acRef.GetAppContextFlag(StopFlagKey)
+                               if err != nil {
+                                       done()
+                               } else if flag == true {
+                                       log.Info("Forced stop context", log.Fields{})
+                                       // Forced Stop from outside
+                                       done()
+                               }
+                       case <-gctx.Done():
+                               log.Info("Context done", log.Fields{})
+                               return gctx.Err()
+                       }
+               }
+       })
+       // Go over all messages
+       for {
+               // Get first event to process
+               c.Lock.Lock()
+               index, ele := qUtils.FindFirstPending()
+               if index >= 0 {
+                       c.Lock.Unlock()
+                       e := ele.Event
+                       state, skip, err := c.checkStateChange(e)
+                       // Event is not valid event for the current state of AppContext
+                       if err != nil {
+                               log.Error("State Change Error", log.Fields{"error": err})
+                               if err := c.UpdateQStatus(index, "Skip"); err != nil {
+                                       break
+                               }
+                               if !skip {
+                                       // Update status with error
+                                       err = c.acRef.UpdateAppContextStatus(StatusKey, appcontext.AppContextStatus{Status: state.ErrState})
+                                       if err != nil {
+                                               break
+                                       }
+                                       // Update Current status with error
+                                       err = c.acRef.UpdateAppContextStatus(CurrentStateKey, appcontext.AppContextStatus{Status: state.ErrState})
+                                       if err != nil {
+                                               break
+                                       }
+                               }
+                               // Continue to process more events
+                               continue
+                       }
+                       // Create a derived context
+                       l, lDone = context.WithCancel(ctx)
+                       lGroup, lctx = errgroup.WithContext(l)
+                       c.Lock.Lock()
+                       c.cancel = lDone
+                       c.Lock.Unlock()
+                       switch e {
+                       case InstantiateEvent:
+                               op = OpApply
+                       case TerminateEvent:
+                               op = OpDelete
+                       case ReadEvent:
+                               op = OpRead
+                       case UpdateEvent:
+                               // In Instantiate Phase find out resources that need to be modified and
+                               // set skip to be true for those that match
+                               // This is done to avoid applying resources that have no differences
+                               if err := c.updateModifyPhase(ele); err != nil {
+                                       break
+                               }
+                               op = OpApply
+                               // Enqueue Modify Phase for the AppContext that is being updated to
+                               go HandleAppContext(ele.UCID, c.acID, UpdateDeleteEvent, c.con)
+                       case UpdateDeleteEvent:
+                               // Update AppContext to decide what needs update
+                               if err := c.updateDeletePhase(ele); err != nil {
+                                       break
+                               }
+                               op = OpDelete
+                       case AddChildContextEvent:
+                               log.Error("Not Implemented", log.Fields{"event": e})
+                               if err := c.UpdateQStatus(index, "Skip"); err != nil {
+                                       break
+                               }
+                               continue
+                       default:
+                               log.Error("Unknown event", log.Fields{"event": e})
+                               if err := c.UpdateQStatus(index, "Skip"); err != nil {
+                                       break
+                               }
+                               continue
+                       }
+                       lGroup.Go(func() error {
+                               return c.run(lctx, lGroup, op, e)
+                       })
+                       // Wait for all subtasks to complete
+                       log.Info("Wait for all subtasks to complete", log.Fields{})
+                       if err := lGroup.Wait(); err != nil {
+                               log.Error("Failed run", log.Fields{"error": err})
+                               // Mark the event in Queue
+                               if err := c.UpdateQStatus(index, "Error"); err != nil {
+                                       break
+                               }
+                               // Update failed status
+                               err = c.acRef.UpdateAppContextStatus(StatusKey, appcontext.AppContextStatus{Status: state.ErrState})
+                               if err != nil {
+                                       break
+                               }
+                               // Update Current status with error
+                               err = c.acRef.UpdateAppContextStatus(CurrentStateKey, appcontext.AppContextStatus{Status: state.ErrState})
+                               if err != nil {
+                                       break
+                               }
+                               continue
+                       }
+                       log.Info("Success all subtasks completed", log.Fields{})
+                       // Mark the event in Queue
+                       if err := c.UpdateQStatus(index, "Done"); err != nil {
+                               break
+                       }
+
+                       // Success - Update Status for the AppContext to match the Desired State
+                       ds, _ := c.acRef.GetAppContextStatus(DesiredStateKey)
+                       err = c.acRef.UpdateAppContextStatus(StatusKey, ds)
+                       err = c.acRef.UpdateAppContextStatus(CurrentStateKey, ds)
+
+               } else {
+                       // Done Processing all elements in queue
+                       log.Info("Done Processing - no new messages", log.Fields{"context": c.acID})
+                       // Set the TerminatePending Flag to false before exiting
+                       _ = c.acRef.UpdateAppContextFlag(PendingTerminateFlagKey, false)
+                       // release the active contextIDs
+                       ok, err := DeleteActiveContextRecord(c.acID)
+                       if !ok {
+                               log.Info("Deleting activeContextID failed", log.Fields{"context": c.acID, "error": err})
+                       }
+                       c.Running = false
+                       c.Lock.Unlock()
+                       return
+               }
+       }
+       // Any error in reading/updating appContext is considered
+       // fatal and all processing stopped for the AppContext
+       // Set running flag to false before exiting
+       c.Lock.Lock()
+       // release the active contextIDs
+       ok, err := DeleteActiveContextRecord(c.acID)
+       if !ok {
+               log.Info("Deleting activeContextID failed", log.Fields{"context": c.acID, "error": err})
+       }
+       c.Running = false
+       c.Lock.Unlock()
+}
+
+// Iterate over the appcontext to mark apps/cluster/resources that doesn't need to be deleted
+func (c *Context) updateDeletePhase(e AppContextQueueElement) error {
+
+       // Read Update AppContext into CompositeApp structure
+       uca, err := ReadAppContext(e.UCID)
+       if err != nil {
+               log.Error("Fatal! error reading appContext", log.Fields{"err": err})
+               return err
+       }
+       // Iterate over all the subapps and mark all apps, clusters and resources
+       // that shouldn't be deleted
+       for _, app := range c.ca.Apps {
+               foundApp := FindApp(uca, app.Name)
+               // If app not found that will be deleted (skip false)
+               if foundApp {
+                       // Check if any clusters are deleted
+                       for _, cluster := range app.Clusters {
+                               foundCluster := FindCluster(uca, app.Name, cluster.Name)
+                               if foundCluster {
+                                       // Check if any resources are deleted
+                                       var resCnt int = 0
+                                       for _, res := range cluster.Resources {
+                                               foundRes := FindResource(uca, app.Name, cluster.Name, res.Name)
+                                               if foundRes {
+                                                       // If resource found in both appContext don't delete it
+                                                       res.Skip = true
+                                               } else {
+                                                       // Resource found to be deleted
+                                                       resCnt++
+                                               }
+                                       }
+                                       // No resources marked for deletion, mark this cluster for not deleting
+                                       if resCnt == 0 {
+                                               cluster.Skip = true
+                                       }
+                               }
+                       }
+               }
+       }
+       return nil
+}
+
+// Iterate over the appcontext to mark apps/cluster/resources that doesn't need to be Modified
+func (c *Context) updateModifyPhase(e AppContextQueueElement) error {
+       // Read Update from AppContext into CompositeApp structure
+       uca, err := ReadAppContext(e.UCID)
+       if err != nil {
+               log.Error("Fatal! error reading appContext", log.Fields{"err": err})
+               return err
+       }
+       //acUtils := &utils.AppContextUtils{Ac: c.ac}
+       // Load update appcontext also
+       uRef, err := utils.NewAppContextReference(e.UCID)
+       if err != nil {
+               return err
+       }
+       //updateUtils := &utils.AppContextUtils{Ac: uac}
+       // Iterate over all the subapps and mark all apps, clusters and resources
+       // that match exactly and shouldn't be changed
+       for _, app := range c.ca.Apps {
+               foundApp := FindApp(uca, app.Name)
+               if foundApp {
+                       // Check if any clusters are modified
+                       for _, cluster := range app.Clusters {
+                               foundCluster := FindCluster(uca, app.Name, cluster.Name)
+                               if foundCluster {
+                                       diffRes := false
+                                       // Check if any resources are added or modified
+                                       for _, res := range cluster.Resources {
+                                               foundRes := FindResource(uca, app.Name, cluster.Name, res.Name)
+                                               if foundRes {
+                                                       // Read the resource from both AppContext and Compare
+                                                       cRes, _, err1 := c.acRef.GetRes(res.Name, app.Name, cluster.Name)
+                                                       uRes, _, err2 := uRef.GetRes(res.Name, app.Name, cluster.Name)
+                                                       if err1 != nil || err2 != nil {
+                                                               log.Error("Fatal Error: reading resources", log.Fields{"err1": err1, "err2": err2})
+                                                               return err1
+                                                       }
+                                                       if bytes.Equal(cRes, uRes) {
+                                                               res.Skip = true
+                                                       } else {
+                                                               log.Info("Update Resource Diff found::", log.Fields{"resource": res.Name, "cluster": cluster})
+                                                               diffRes = true
+                                                       }
+                                               } else {
+                                                       // Found a new resource that is added to the cluster
+                                                       diffRes = true
+                                               }
+                                       }
+                                       // If no resources diff, skip cluster
+                                       if !diffRes {
+                                               cluster.Skip = true
+                                       }
+                               }
+                       }
+               }
+       }
+       return nil
+}
+
+// Iterate over the appcontext to apply/delete/read resources
+func (c *Context) run(ctx context.Context, g *errgroup.Group, op RsyncOperation, e RsyncEvent) error {
+
+       if op == OpApply {
+               // Setup dependency before starting app and cluster threads
+               // Only for Apply for now
+               for _, a := range c.ca.AppOrder {
+                       app := a
+                       if len(c.ca.Apps[app].Dependency) > 0 {
+                               c.dm.AddDependency(app, c.ca.Apps[app].Dependency)
+                       }
+               }
+       }
+       // Iterate over all the subapps and start go Routines per app
+       for _, a := range c.ca.AppOrder {
+               app := a
+               // If marked to skip then no processing needed
+               if c.ca.Apps[app].Skip {
+                       log.Info("Update Skipping App::", log.Fields{"App": app})
+                       // Reset bit and skip app
+                       t := c.ca.Apps[app]
+                       t.Skip = false
+                       continue
+               }
+               g.Go(func() error {
+                       err := c.runApp(ctx, g, op, app, e)
+                       if op == OpApply {
+                               // Notify dependency that app got deployed
+                               c.dm.NotifyAppliedStatus(app)
+                       }
+                       return err
+               })
+       }
+       return nil
+}
+
+func (c *Context) runApp(ctx context.Context, g *errgroup.Group, op RsyncOperation, app string, e RsyncEvent) error {
+
+       if op == OpApply {
+               // Check if any dependency and wait for dependencies to be met
+               if err := c.dm.WaitForDependency(ctx, app); err != nil {
+                       return err
+               }
+       }
+       // Iterate over all clusters
+       for _, cluster := range c.ca.Apps[app].Clusters {
+               // If marked to skip then no processing needed
+               if cluster.Skip {
+                       log.Info("Update Skipping Cluster::", log.Fields{"App": app, "cluster": cluster})
+                       // Reset bit and skip cluster
+                       cluster.Skip = false
+                       continue
+               }
+               cluster := cluster.Name
+               g.Go(func() error {
+                       return c.runCluster(ctx, op, e, app, cluster)
+               })
+       }
+       return nil
+}
+
+func (c *Context) runCluster(ctx context.Context, op RsyncOperation, e RsyncEvent, app, cluster string) error {
+       log.Info(" runCluster::", log.Fields{"app": app, "cluster": cluster})
+       namespace, level := c.acRef.GetNamespace()
+       cl, err := c.con.GetClientProviders(app, cluster, level, namespace)
+       if err != nil {
+               log.Error("Error in creating client", log.Fields{"error": err, "cluster": cluster, "app": app})
+               return err
+       }
+       defer cl.CleanClientProvider()
+       // Start cluster watcher if there are resources to be watched
+       // case like admin cloud has no resources
+       if len(c.ca.Apps[app].Clusters[cluster].ResOrder) > 0 {
+               err = cl.StartClusterWatcher()
+               if err != nil {
+                       log.Error("Error starting Cluster Watcher", log.Fields{
+                               "error":   err,
+                               "cluster": cluster,
+                       })
+                       return err
+               }
+       }
+       r := resProvd{app: app, cluster: cluster, cl: cl, context: *c}
+       // Timer key
+       key := app + depend.SEPARATOR + cluster
+       switch e {
+       case InstantiateEvent:
+               // Apply config for the cluster if there are any resources to be applied
+               if len(c.ca.Apps[app].Clusters[cluster].ResOrder) > 0 {
+                       err = cl.ApplyConfig(ctx, nil)
+                       if err != nil {
+                               return err
+                       }
+               }
+               // Check if delete of status tracker is scheduled, if so stop and delete the timer
+               c.StopDeleteStatusCRTimer(key)
+               // Based on the discussions in Helm handling of CRD's
+               // https://helm.sh/docs/chart_best_practices/custom_resource_definitions/
+               if len(c.ca.Apps[app].Clusters[cluster].Dependency["crd-install"]) > 0 {
+                       // Create CRD Resources if they don't exist
+                       log.Info("Creating CRD Resources if they don't exist", log.Fields{"App": app, "cluster": cluster, "hooks": c.ca.Apps[app].Clusters[cluster].Dependency["crd-install"]})
+                       _, err := r.handleResources(ctx, OpCreate, c.ca.Apps[app].Clusters[cluster].Dependency["crd-install"])
+                       if err != nil {
+                               return err
+                       }
+               }
+               if len(c.ca.Apps[app].Clusters[cluster].Dependency["pre-install"]) > 0 {
+                       log.Info("Installing preinstall hooks", log.Fields{"App": app, "cluster": cluster, "hooks": c.ca.Apps[app].Clusters[cluster].Dependency["pre-install"]})
+                       // Add Status tracking
+                       if err := r.addStatusTracker(status.PreInstallHookLabel); err != nil {
+                               return err
+                       }
+                       // Install Preinstall hooks with wait
+                       _, err := r.handleResourcesWithWait(ctx, op, c.ca.Apps[app].Clusters[cluster].Dependency["pre-install"])
+                       if err != nil {
+                               r.deleteStatusTracker(status.PreInstallHookLabel)
+                               return err
+                       }
+                       // Delete Status tracking, will be added after the main resources are added
+                       r.deleteStatusTracker(status.PreInstallHookLabel)
+                       log.Info("Done Installing preinstall hooks", log.Fields{"App": app, "cluster": cluster, "hooks": c.ca.Apps[app].Clusters[cluster].Dependency["pre-install"]})
+               }
+               // Install main resources without wait
+               log.Info("Installing main resources", log.Fields{"App": app, "cluster": cluster, "resources": c.ca.Apps[app].Clusters[cluster].ResOrder})
+               i, err := r.handleResources(ctx, op, c.ca.Apps[app].Clusters[cluster].ResOrder)
+               // handle status tracking before exiting if at least one resource got handled
+               if i > 0 {
+                       // Add Status tracking
+                       r.addStatusTracker("")
+               }
+               if err != nil {
+                       log.Error("Error installing resources for app", log.Fields{"App": app, "cluster": cluster, "resources": c.ca.Apps[app].Clusters[cluster].ResOrder})
+                       return err
+               }
+               log.Info("Done Installing main resources", log.Fields{"App": app, "cluster": cluster, "resources": c.ca.Apps[app].Clusters[cluster].ResOrder})
+               if len(c.ca.Apps[app].Clusters[cluster].Dependency["post-install"]) > 0 {
+                       log.Info("Installing Post-install Hooks", log.Fields{"App": app, "cluster": cluster, "hooks": c.ca.Apps[app].Clusters[cluster].Dependency["post-install"]})
+                       // Install Postinstall hooks with wait
+                       _, err = r.handleResourcesWithWait(ctx, op, c.ca.Apps[app].Clusters[cluster].Dependency["post-install"])
+                       if err != nil {
+                               return err
+                       }
+                       log.Info("Done Installing Post-install Hooks", log.Fields{"App": app, "cluster": cluster, "hooks": c.ca.Apps[app].Clusters[cluster].Dependency["post-install"]})
+               }
+       case TerminateEvent:
+               // Apply Predelete hooks with wait
+               if len(c.ca.Apps[app].Clusters[cluster].Dependency["pre-delete"]) > 0 {
+                       log.Info("Deleting pre-delete Hooks", log.Fields{"App": app, "cluster": cluster, "hooks": c.ca.Apps[app].Clusters[cluster].Dependency["pre-delete"]})
+                       _, err = r.handleResourcesWithWait(ctx, OpApply, c.ca.Apps[app].Clusters[cluster].Dependency["pre-delete"])
+                       if err != nil {
+                               return err
+                       }
+                       log.Info("Done Deleting pre-delete Hooks", log.Fields{"App": app, "cluster": cluster, "hooks": c.ca.Apps[app].Clusters[cluster].Dependency["pre-delete"]})
+               }
+               // Delete main resources without wait
+               _, err = r.handleResources(ctx, op, c.ca.Apps[app].Clusters[cluster].ResOrder)
+               if err != nil {
+                       return err
+               }
+               // Apply Postdelete hooks with wait
+               if len(c.ca.Apps[app].Clusters[cluster].Dependency["post-delete"]) > 0 {
+                       log.Info("Deleting post-delete Hooks", log.Fields{"App": app, "cluster": cluster, "hooks": c.ca.Apps[app].Clusters[cluster].Dependency["post-delete"]})
+                       _, err = r.handleResourcesWithWait(ctx, OpApply, c.ca.Apps[app].Clusters[cluster].Dependency["post-delete"])
+                       if err != nil {
+                               return err
+                       }
+                       log.Info("Done Deleting post-delete Hooks", log.Fields{"App": app, "cluster": cluster, "hooks": c.ca.Apps[app].Clusters[cluster].Dependency["post-delete"]})
+               }
+               var rl []string
+               // Delete all hook resources also
+               // Ignore errors - There can be errors if the hook resources are not applied
+               // like rollback hooks and test hooks
+               for _, d := range c.ca.Apps[app].Clusters[cluster].Dependency {
+                       rl = append(rl, d...)
+               }
+               // Ignore errors
+               _, _ = r.handleResources(ctx, op, rl)
+
+               // Delete config for the cluster if applied
+               if len(c.ca.Apps[app].Clusters[cluster].ResOrder) > 0 {
+                       err = cl.DeleteConfig(ctx, nil)
+                       if err != nil {
+                               return err
+                       }
+               }
+               // Check if delete of status tracker is scheduled, if so stop and delete the timer
+               // before scheduling a new one
+               c.StopDeleteStatusCRTimer(key)
+               timer := ScheduleDeleteStatusTracker(c.statusAcID, app, cluster, level, namespace, c.con)
+               c.UpdateDeleteStatusCRTimer(key, timer)
+       case UpdateEvent, UpdateDeleteEvent:
+               // Update and Rollback hooks are not supported at this time
+               var rl []string
+               // Find resources to handle based on skip bit
+               resOrder := c.ca.Apps[app].Clusters[cluster].ResOrder
+               for _, res := range resOrder {
+                       // If marked to skip then no processing needed
+                       if !c.ca.Apps[app].Clusters[cluster].Resources[res].Skip {
+                               rl = append(rl, res)
+                       }
+               }
+               // Handle main resources without wait
+               _, err = r.handleResources(ctx, op, rl)
+               if err != nil {
+                       return err
+               }
+               // Add Status tracking if not already applied for the cluster
+               if op == OpApply {
+                       r.addStatusTracker("")
+               }
+       }
+       return nil
+}
+
+// Schedule delete status tracker to run after 2 mins
+// This gives time for delete status to be recorded in the monitor CR
+func ScheduleDeleteStatusTracker(acID, app, cluster, level, namespace string, con Connector) *time.Timer {
+
+       DurationOfTime := time.Duration(120) * time.Second
+       label := acID + "-" + app
+       b, err := status.GetStatusCR(label, "")
+       if err != nil {
+               log.Error("Failed to get status CR for deleting", log.Fields{"error": err, "label": label})
+               return &time.Timer{}
+       }
+
+       f := func() {
+               cl, err := con.GetClientProviders(app, cluster, level, namespace)
+               if err != nil {
+                       log.Error("Error in creating client", log.Fields{"error": err, "cluster": cluster, "app": app})
+                       return
+               }
+               defer cl.CleanClientProvider()
+               if err = cl.DeleteStatusCR(label, b); err != nil {
+                       log.Info("Failed to delete res", log.Fields{"error": err, "app": app, "label": label})
+                       return
+               }
+       }
+       // Schedule for running at a later time
+       handle := time.AfterFunc(DurationOfTime, f)
+       return handle
+}
index 308db7f..9bc8e05 100644 (file)
@@ -4,8 +4,9 @@
 package db
 
 import (
-       "github.com/open-ness/EMCO/src/orchestrator/pkg/infra/db"
-       log "github.com/open-ness/EMCO/src/orchestrator/pkg/infra/logutils"
+       "gitlab.com/project-emco/core/emco-base/src/orchestrator/pkg/infra/db"
+       log "gitlab.com/project-emco/core/emco-base/src/orchestrator/pkg/infra/logutils"
+       mtypes "gitlab.com/project-emco/core/emco-base/src/orchestrator/pkg/module/types"
 
        pkgerrors "github.com/pkg/errors"
 )
@@ -14,36 +15,59 @@ type clientDbInfo struct {
        storeName    string // name of the mongodb collection to use for client documents
        tagNamespace string // attribute key name for the namespace section of a CloudConfig
        tagConfig    string // attribute key name for the kubeconfig section of a CloudConfig
+       tagMeta      string // attribute key name for the GitOps related Objects
 }
 
 // ClusterKey is the key structure that is used in the database
 type CloudConfigKey struct {
-       Provider  string `json:"provider"`
-       Cluster   string `json:"cluster"`
+       Provider  string `json:"cloudConfigClusterProvider"`
+       Cluster   string `json:"cloudConfigCluster"`
        Level     string `json:"level"`
        Namespace string `json:"namespace"`
 }
 
 // CloudConfig contains the parameters that specify access to a cloud at any level
 type CloudConfig struct {
-       Provider  string `json:"provider"`
-       Cluster   string `json:"cluster"`
+       Provider  string `json:"cloudConfigClusterProvider"`
+       Cluster   string `json:"cloudConfigCluster"`
        Level     string `json:"level"`
        Namespace string `json:"namespace"`
        Config    string `json:"config"`
 }
 
 type KubeConfig struct {
-       Config string `json:"config"`
+       Config string `json:"config" encrypted:""`
+}
+
+// ClusterSyncObjectKey is the key structure that is used in the database
+type ClusterSyncObjectsKey struct {
+       ClusterProviderName    string `json:"clusterProvider"`
+       ClusterSyncObjectsName string `json:"clusterSyncObject"`
+}
+
+// CloudConfig contains the parameters that specify access to a cloud at any level
+type CloudGitOpsConfig struct {
+       Provider  string            `json:"cloudConfigClusterProvider"`
+       Cluster   string            `json:"cloudConfigCluster"`
+       Level     string            `json:"level"`
+       Namespace string            `json:"namespace"`
+       Config    mtypes.GitOpsSpec `json:"gitOps"`
 }
 
 // CloudConfigManager is an interface that exposes the Cloud Config functionality
 type CloudConfigManager interface {
        GetCloudConfig(provider string, cluster string, level string, namespace string) (CloudConfig, error)
        CreateCloudConfig(provider string, cluster string, level string, namespace string, config string) (CloudConfig, error)
-       GetNamespace(provider string, cluster string) (CloudConfig, error)                   // level-0 only
-       SetNamespace(provider string, cluster string, namespace string) (CloudConfig, error) // level-0 only
+       GetNamespace(provider string, cluster string) (string, error)         // level-0 only
+       SetNamespace(provider string, cluster string, namespace string) error // level-0 only
        DeleteCloudConfig(provider string, cluster string, level string, namespace string) error
+       CreateClusterSyncObjects(provider string, pr mtypes.ClusterSyncObjects, exists bool) (mtypes.ClusterSyncObjects, error)
+       GetClusterSyncObjects(provider, syncobject string) (mtypes.ClusterSyncObjects, error)
+       GetClusterSyncObjectsValue(provider, syncobject, syncobjectkey string) (interface{}, error)
+       GetAllClusterSyncObjects(provider string) ([]mtypes.ClusterSyncObjects, error)
+       DeleteClusterSyncObjects(provider, syncobject string) error
+       CreateGitOpsConfig(provider string, cluster string, gs mtypes.GitOpsSpec, level string, namespace string) (CloudGitOpsConfig, error)
+       GetGitOpsConfig(provider string, cluster string, level string, namespace string) (CloudGitOpsConfig, error)
 }
 
 // CloudConfigClient implements CloudConfigManager
@@ -57,9 +81,10 @@ type CloudConfigClient struct {
 func NewCloudConfigClient() *CloudConfigClient {
        return &CloudConfigClient{
                db: clientDbInfo{
-                       storeName:    "cloudconfig",
+                       storeName:    "resources",
                        tagNamespace: "namespace",
                        tagConfig:    "config",
+                       tagMeta:      "meta",
                },
        }
 }
@@ -69,8 +94,8 @@ func unmarshal(values [][]byte) (KubeConfig, error) {
                kc := KubeConfig{}
                err := db.DBconn.Unmarshal(values[0], &kc)
                if err != nil {
-                       log.Error("Failed unmarshaling Value", log.Fields{})
-                       return KubeConfig{}, pkgerrors.Wrap(err, "Failed unmarshaling Value")
+                       log.Error("Failed unmarshalling Value", log.Fields{})
+                       return KubeConfig{}, err
                }
                return kc, nil
        }
@@ -194,6 +219,7 @@ func (c *CloudConfigClient) GetNamespace(provider string, cluster string) (strin
                log.Error("Could not fetch the CloudConfig so can't return namespace", log.Fields{})
                return "", pkgerrors.Wrap(err, "Could not fetch the CloudConfig so can't return namespace")
        }
+
        if len(values) > 1 {
                log.Error("Multiple CloudConfigs were returned, which was unexpected", log.Fields{})
                return "", pkgerrors.New("Multiple CloudConfigs were returned, which was unexpected")
@@ -230,3 +256,217 @@ func (c *CloudConfigClient) DeleteCloudConfig(provider string, cluster string, l
 
        return nil
 }
+
+func (c *CloudConfigClient) CreateClusterSyncObjects(provider string, p mtypes.ClusterSyncObjects, exists bool) (mtypes.ClusterSyncObjects, error) {
+       key := ClusterSyncObjectsKey{
+               ClusterProviderName:    provider,
+               ClusterSyncObjectsName: p.Metadata.Name,
+       }
+
+       //Check if this ClusterSyncObjects already exists
+       _, err := c.GetClusterSyncObjects(provider, p.Metadata.Name)
+       if err == nil && !exists {
+               return mtypes.ClusterSyncObjects{}, pkgerrors.New("Cluster Sync Objects already exists")
+       }
+
+       err = db.DBconn.Insert(c.db.storeName, key, nil, c.db.tagMeta, p)
+       if err != nil {
+               return mtypes.ClusterSyncObjects{}, pkgerrors.Wrap(err, "Creating DB Entry")
+       }
+
+       return p, nil
+}
+
+// GetClusterSyncObjects returns the Cluster Sync objects for corresponding provider and sync object name
+func (c *CloudConfigClient) GetClusterSyncObjects(provider, syncobject string) (mtypes.ClusterSyncObjects, error) {
+       //Construct key and tag to select entry
+       key := ClusterSyncObjectsKey{
+               ClusterProviderName:    provider,
+               ClusterSyncObjectsName: syncobject,
+       }
+
+       value, err := db.DBconn.Find(c.db.storeName, key, c.db.tagMeta)
+       if err != nil {
+               return mtypes.ClusterSyncObjects{}, err
+       } else if len(value) == 0 {
+               return mtypes.ClusterSyncObjects{}, pkgerrors.New("Cluster sync object not found")
+       }
+
+       //value is a byte array
+       if value != nil {
+               ckvp := mtypes.ClusterSyncObjects{}
+               err = db.DBconn.Unmarshal(value[0], &ckvp)
+               if err != nil {
+                       return mtypes.ClusterSyncObjects{}, err
+               }
+               return ckvp, nil
+       }
+
+       return mtypes.ClusterSyncObjects{}, pkgerrors.New("Unknown Error")
+}
+
+// DeleteClusterSyncObjects the  ClusterSyncObjects from database
+func (c *CloudConfigClient) DeleteClusterSyncObjects(provider, syncobject string) error {
+       //Construct key and tag to select entry
+       key := ClusterSyncObjectsKey{
+               ClusterProviderName:    provider,
+               ClusterSyncObjectsName: syncobject,
+       }
+
+       err := db.DBconn.Remove(c.db.storeName, key)
+       return err
+}
+
+// GetClusterSyncObjectsValue returns the value of the key from the corresponding provider and Sync Object name
+func (c *CloudConfigClient) GetClusterSyncObjectsValue(provider, syncobject, syncobjectkey string) (interface{}, error) {
+       //Construct key and tag to select entry
+       key := ClusterSyncObjectsKey{
+               ClusterProviderName:    provider,
+               ClusterSyncObjectsName: syncobject,
+       }
+
+       value, err := db.DBconn.Find(c.db.storeName, key, c.db.tagMeta)
+       if err != nil {
+               return mtypes.ClusterSyncObjects{}, err
+       } else if len(value) == 0 {
+               return mtypes.ClusterSyncObjects{}, pkgerrors.New("Cluster sync object not found")
+       }
+
+       //value is a byte array
+       if value != nil {
+               ckvp := mtypes.ClusterSyncObjects{}
+               err = db.DBconn.Unmarshal(value[0], &ckvp)
+               if err != nil {
+                       return nil, err
+               }
+
+               for _, kvmap := range ckvp.Spec.Kv {
+                       if val, ok := kvmap[syncobjectkey]; ok {
+                               return struct {
+                                       Value interface{} `json:"value"`
+                               }{Value: val}, nil
+                       }
+               }
+               return nil, pkgerrors.New("Cluster Sync Object key value not found")
+       }
+
+       return nil, pkgerrors.New("Unknown Error")
+}
+
+// GetAllClusterSyncObjects returns the Cluster Sync Objects for corresponding provider
+func (c *CloudConfigClient) GetAllClusterSyncObjects(provider string) ([]mtypes.ClusterSyncObjects, error) {
+       //Construct key and tag to select the entry
+       key := ClusterSyncObjectsKey{
+               ClusterProviderName:    provider,
+               ClusterSyncObjectsName: "",
+       }
+       values, err := db.DBconn.Find(c.db.storeName, key, c.db.tagMeta)
+       if err != nil {
+               return []mtypes.ClusterSyncObjects{}, err
+       }
+
+       resp := make([]mtypes.ClusterSyncObjects, 0)
+       for _, value := range values {
+               cp := mtypes.ClusterSyncObjects{}
+               err = db.DBconn.Unmarshal(value, &cp)
+               if err != nil {
+                       return []mtypes.ClusterSyncObjects{}, err
+               }
+               resp = append(resp, cp)
+       }
+
+       return resp, nil
+}
+
+// CreateGitOpsConfig allows to create a new cloud config entry to hold a kubeconfig for access
+func (c *CloudConfigClient) CreateGitOpsConfig(provider string, cluster string, gs mtypes.GitOpsSpec, level string, namespace string) (CloudGitOpsConfig, error) {
+
+       key := CloudConfigKey{
+               Provider:  provider,
+               Cluster:   cluster,
+               Level:     level,
+               Namespace: namespace,
+       }
+
+       // check if it already exists
+       _, err := c.GetGitOpsConfig(provider, cluster, level, namespace)
+       if err == nil {
+               log.Error("CloudConfig already exists", log.Fields{})
+               return CloudGitOpsConfig{}, pkgerrors.New("CloudConfig already exists")
+       }
+       log.Info("Inserting in gs db", log.Fields{"gs": gs})
+       err = db.DBconn.Insert(c.db.storeName, key, nil, c.db.tagMeta, gs)
+       if err != nil {
+               log.Error("Failure inserting CloudConfig", log.Fields{})
+               return CloudGitOpsConfig{}, pkgerrors.Wrap(err, "Failure inserting CloudConfig")
+       }
+
+       cc := CloudGitOpsConfig{
+               Provider:  provider,
+               Cluster:   cluster,
+               Level:     level,
+               Namespace: namespace,
+               Config:    gs,
+       }
+
+       return cc, nil
+}
+
+// GetGitOpsConfig allows to create a new cloud config entry to hold a kubeconfig for access
+func (c *CloudConfigClient) GetGitOpsConfig(provider string, cluster string, level string, namespace string) (CloudGitOpsConfig, error) {
+
+       key := CloudConfigKey{
+               Provider:  provider,
+               Cluster:   cluster,
+               Level:     level,
+               Namespace: namespace,
+       }
+
+       value, err := db.DBconn.Find(c.db.storeName, key, c.db.tagMeta)
+       if err != nil {
+               log.Error("Failure inserting CloudConfig", log.Fields{})
+               return CloudGitOpsConfig{}, pkgerrors.Wrap(err, "Failure inserting CloudConfig")
+       }
+       log.Info("Get in gs db", log.Fields{"value": value})
+
+       cp := mtypes.GitOpsSpec{}
+       err = db.DBconn.Unmarshal(value[0], &cp)
+       if err != nil {
+               return CloudGitOpsConfig{}, err
+       }
+
+       cc := CloudGitOpsConfig{
+               Provider:  provider,
+               Cluster:   cluster,
+               Level:     level,
+               Namespace: namespace,
+               Config:    cp,
+       }
+
+       return cc, nil
+}
+
+// DeleteGitOpsConfig deletes a cloud config entry
+func (c *CloudConfigClient) DeleteGitOpsConfig(provider string, cluster string, level string, namespace string) error {
+       key := CloudConfigKey{
+               Provider:  provider,
+               Cluster:   cluster,
+               Level:     level,
+               Namespace: namespace,
+       }
+
+       // check if it doesn't exist
+       _, err := c.GetGitOpsConfig(provider, cluster, level, namespace)
+       if err != nil {
+               log.Error("Could not fetch the CloudConfig so not deleting", log.Fields{})
+               return pkgerrors.New("Could not fetch the GitOpsConfig so not deleting")
+       }
+
+       err = db.DBconn.Remove(c.db.storeName, key)
+       if err != nil {
+               log.Error("Could not delete the GitOpsConfig", log.Fields{})
+               return pkgerrors.Wrap(err, "Could not delete the GitOpsConfig")
+       }
+
+       return nil
+}
diff --git a/central-controller/src/rsync/pkg/depend/depend.go b/central-controller/src/rsync/pkg/depend/depend.go
new file mode 100644 (file)
index 0000000..9318399
--- /dev/null
@@ -0,0 +1,298 @@
+// SPDX-License-Identifier: Apache-2.0
+// Copyright (c) 2020 Intel Corporation
+
+package depend
+
+import (
+       "context"
+       "reflect"
+       "strings"
+       "sync"
+       "time"
+
+       log "gitlab.com/project-emco/core/emco-base/src/orchestrator/pkg/infra/logutils"
+       "gitlab.com/project-emco/core/emco-base/src/rsync/pkg/internal/utils"
+       "gitlab.com/project-emco/core/emco-base/src/rsync/pkg/types"
+)
+
+type DependManager struct {
+       acID string
+       // Per App Ready channels to notify
+       readyCh map[string][]appData
+       // Per App Deploy channels to notify
+       deployedCh map[string][]appData
+       // Per app channels to wait on
+       appCh map[string][]chan struct{}
+       // Single Resource succeed channels
+       // Map of app+cluster inside map is of resource
+       resCh map[string]map[string]resData
+       sync.RWMutex
+}
+
+type resData struct {
+       res string
+       // Chan to report if resource is ready/success
+       ch chan struct{}
+}
+
+type appData struct {
+       app string
+       crt types.Criteria
+       // Chan to report if app meets Criteria
+       ch chan struct{}
+}
+type DependManagerList struct {
+       dm map[string]*DependManager
+       sync.RWMutex
+}
+
+var dmList DependManagerList
+
+func init() {
+       dmList.dm = make(map[string]*DependManager)
+}
+
+const SEPARATOR = "+"
+
+// New Manager for acID
+func NewDependManager(acID string) *DependManager {
+       d := DependManager{
+               acID: acID,
+       }
+       d.deployedCh = make(map[string][]appData)
+       d.readyCh = make(map[string][]appData)
+       d.appCh = make(map[string][]chan struct{})
+       d.resCh = make(map[string]map[string]resData)
+       dmList.Lock()
+       dmList.dm[acID] = &d
+       dmList.Unlock()
+       return &d
+}
+
+// Function registers an app for dependency
+func (dm *DependManager) AddDependency(app string, dep map[string]*types.Criteria) error {
+
+       dm.Lock()
+       defer dm.Unlock()
+
+       log.Info("AddDependency", log.Fields{"app": app, "dep": dep})
+       for d, c := range dep {
+               depLabel := d
+               ch := make(chan struct{}, 1)
+               data := appData{app: app, crt: *c, ch: ch}
+               if c.OpStatus == types.OpStatusReady {
+                       dm.readyCh[depLabel] = append(dm.readyCh[depLabel], data)
+               } else if c.OpStatus == types.OpStatusDeployed {
+                       dm.deployedCh[depLabel] = append(dm.deployedCh[depLabel], data)
+               } else {
+                       // Ignore it
+                       continue
+               }
+               // Add all channels to per app list
+               dm.appCh[app] = append(dm.appCh[app], ch)
+       }
+       return nil
+}
+
+// WaitResourceDependency waits for the resource to be Success
+func (dm *DependManager) WaitResourceDependency(ctx context.Context, app, cluster, name string) error {
+
+       key := app + SEPARATOR + cluster
+       ch := make(chan struct{}, 1)
+       dm.Lock()
+       // Add channels to wait list
+       if len(dm.resCh[key]) == 0 {
+               dm.resCh[key] = make(map[string]resData)
+       }
+       dm.resCh[key][name] = resData{res: name, ch: ch}
+       dm.Unlock()
+       // Remove the channel from the list on function return
+       defer func() {
+               dm.Lock()
+               delete(dm.resCh[key], name)
+               dm.Unlock()
+       }()
+       // Start with wait time of 1 sec and then change it to
+       // 30 secs to avoid missing first notification
+       waitTime := 1
+       for {
+               select {
+               // Wait for wait time before checking if resource is ready
+               case <-time.After(time.Duration(waitTime) * time.Second):
+                       // Context is canceled
+                       if ctx.Err() != nil {
+                               return ctx.Err()
+                       }
+                       waitTime = 30
+                       b := dm.GetResourceReadyStatus(app, cluster, name)
+                       if b {
+                               return nil
+                       } else {
+                               continue
+                       }
+               case <-ctx.Done():
+                       return ctx.Err()
+               case <-ch:
+                       // Channel notified and resource is ready
+                       return nil
+               }
+       }
+}
+func (dm *DependManager) ClearChannels(app string) {
+       dm.Lock()
+       // Find all the entries for the app in deployedCh and readyCh
+       for _, x := range []map[string][]appData{dm.deployedCh, dm.readyCh} {
+               for _, d := range x {
+                       for i := len(d) - 1; i >= 0; i-- {
+                               if d[i].app == app {
+                                       d = append(d[:i], d[i+1:]...)
+                               }
+                       }
+               }
+       }
+       delete(dm.appCh, app)
+       dm.Unlock()
+}
+
+//WaitForDependency waits for all dependecies to be met for an app
+func (dm *DependManager) WaitForDependency(ctx context.Context, app string) error {
+
+       var cases []reflect.SelectCase
+       dm.RLock()
+       if len(dm.appCh[app]) <= 0 {
+               dm.RUnlock()
+               return nil
+       }
+       log.Info("WaitForDependency", log.Fields{"app": app})
+       // Add the case for ctx done
+       cases = append(cases, reflect.SelectCase{
+               Dir:  reflect.SelectRecv,
+               Chan: reflect.ValueOf(ctx.Done()),
+       })
+       for _, ch := range dm.appCh[app] {
+               cases = append(cases, reflect.SelectCase{
+                       Dir:  reflect.SelectRecv,
+                       Chan: reflect.ValueOf(ch),
+               })
+       }
+       dm.RUnlock()
+       // When wait is done remove all channels form the Dependency arrays
+       defer dm.ClearChannels(app)
+       num := len(cases) - 1
+       // Wait for all channels to be available
+       for i := 0; i < num; i++ {
+               // Wait for all channels
+               index, _, _ := reflect.Select(cases)
+               switch index {
+               case 0:
+                       // case <- ctx.Done()
+                       return ctx.Err()
+               default:
+                       // Delete the channel from list
+                       log.Info("WaitForDependency: Coming out of wait", log.Fields{"app": app, "index": index})
+                       // Some channel is done, remove it from the list
+                       cases = append(cases[:index], cases[index+1:]...)
+                       continue
+               }
+       }
+       return nil
+}
+
+func (dm *DependManager) NotifyAppliedStatus(app string) {
+       // Read deployed channel
+       dm.RLock()
+       dl := dm.deployedCh[app]
+       dm.RUnlock()
+       dm.NotifyStatus(dl)
+}
+
+func (dm *DependManager) NotifyReadyStatus(app string) {
+       // Read ready channel
+       dm.RLock()
+       dl := dm.readyCh[app]
+       dm.RUnlock()
+       dm.NotifyStatus(dl)
+}
+
+func (dm *DependManager) NotifyStatus(dl []appData) {
+       for _, d := range dl {
+               // Wait and notify channels
+               go func(d appData) {
+                       if d.crt.Wait != 0 {
+                               time.Sleep(time.Duration(d.crt.Wait) * time.Second)
+                       }
+                       d.ch <- struct{}{}
+               }(d)
+       }
+}
+
+// Inform waiting threads of App Ready
+func ResourcesReady(acID, app, cluster string) {
+
+       dmList.RLock()
+       // Check if AppContext has dependency
+       dm, ok := dmList.dm[acID]
+       if !ok {
+               dmList.RUnlock()
+               return
+       }
+       dmList.RUnlock()
+       key := app + SEPARATOR + cluster
+       // If no app is waiting for ready status of the app
+       // Not further processing needed
+       dm.RLock()
+       if len(dm.readyCh[app]) == 0 && len(dm.resCh[key]) == 0 {
+               dm.RUnlock()
+               return
+       }
+       length := len(dm.readyCh[app])
+       dm.RUnlock()
+       if length > 0 {
+               // Inform waiting apps
+               go func() {
+                       // Check in appContext if app is ready on all clusters inform ready status
+                       acUtils, err := utils.NewAppContextReference(acID)
+                       if err != nil {
+                               return
+                       }
+                       if acUtils.CheckAppReadyOnAllClusters(app) {
+                               // Notify the apps waiting for the app to be ready
+                               dm.NotifyReadyStatus(app)
+                       }
+               }()
+       }
+       dm.RLock()
+       res := dm.resCh[app]
+       dm.RUnlock()
+       if len(res) > 0 {
+               go func() {
+                       for _, r := range res {
+                               b := dm.GetResourceReadyStatus(app, cluster, r.res)
+                               if b {
+                                       // If succeded inform the waiting channel
+                                       r.ch <- struct{}{}
+                               }
+                       }
+               }()
+       }
+}
+
+func (dm *DependManager) GetResourceReadyStatus(app, cluster, res string) bool {
+       var resStatus bool
+       acUtils, err := utils.NewAppContextReference(dm.acID)
+       if err != nil {
+               return false
+       }
+       result := strings.SplitN(res, "+", 2)
+       if len(result) != 2 {
+               log.Error("Invalid resource name format::", log.Fields{"res": res})
+               return false
+       }
+       // In case of Pod and Job Success state is used for Hook readiness
+       if result[1] == "Pod" || result[1] == "Job" {
+               resStatus = acUtils.GetResourceReadyStatus(app, cluster, res, string(types.SuccessStatus))
+       } else {
+               resStatus = acUtils.GetResourceReadyStatus(app, cluster, res, string(types.ReadyStatus))
+       }
+       return resStatus
+}
diff --git a/central-controller/src/rsync/pkg/depend/depend_test.go b/central-controller/src/rsync/pkg/depend/depend_test.go
new file mode 100644 (file)
index 0000000..c624c5a
--- /dev/null
@@ -0,0 +1,12 @@
+// SPDX-License-Identifier: Apache-2.0
+// Copyright (c) 2020 Intel Corporation
+
+package depend_test
+
+import (
+       "testing"
+)
+
+func DependTest(t *testing.T) {
+
+}
diff --git a/central-controller/src/rsync/pkg/gitops/emcogit/emcogit.go b/central-controller/src/rsync/pkg/gitops/emcogit/emcogit.go
new file mode 100644 (file)
index 0000000..eccb252
--- /dev/null
@@ -0,0 +1,161 @@
+// SPDX-License-Identifier: Apache-2.0
+// Copyright (c) 2022 Intel Corporation
+
+package emcogit
+
+import (
+       "context"
+
+       emcogithub "gitlab.com/project-emco/core/emco-base/src/rsync/pkg/gitops/emcogithub"
+
+       "github.com/fluxcd/go-git-providers/gitprovider"
+       pkgerrors "github.com/pkg/errors"
+)
+
+/*
+       Helper function to convert interface to []gitprovider.CommitFile
+       params: files interface{}
+       return: []gitprovider.CommitFile
+*/
+func convertToCommitFile(ref interface{}) []gitprovider.CommitFile {
+       var exists bool
+       switch ref.(type) {
+       case []gitprovider.CommitFile:
+               exists = true
+       default:
+               exists = false
+       }
+       var rf []gitprovider.CommitFile
+       // Create rf is doesn't exist
+       if !exists {
+               rf = []gitprovider.CommitFile{}
+       } else {
+               rf = ref.([]gitprovider.CommitFile)
+       }
+       return rf
+}
+
+/*
+       Helper function to convert interface to gitprovider.Client
+       params: files interface{}
+       return: gitprovider.Client
+*/
+func convertToClient(c interface{}) gitprovider.Client {
+       return c.(gitprovider.Client)
+}
+
+/*
+       Function to create git client
+       params : git token
+       return : git client, error
+*/
+func CreateClient(gitToken string, gitType string) (interface{}, error) {
+       switch gitType {
+       case "github":
+               c, err := emcogithub.CreateClient(gitToken)
+               if err != nil {
+                       return nil, err
+               }
+               return c, nil
+       }
+       //Add other types like gitlab, bitbucket etc
+       return nil, pkgerrors.New("Git Provider type not supported")
+}
+
+/*
+       Function to create a new Repo in github
+       params : context, git client, Repository Name, User Name, description
+       return : nil/error
+*/
+func CreateRepo(ctx context.Context, c interface{}, repoName string, userName string, desc string, gitType string) error {
+
+       switch gitType {
+       case "github":
+               err := emcogithub.CreateRepo(ctx, convertToClient(c), repoName, userName, desc)
+               if err != nil {
+                       return err
+               }
+               return nil
+       }
+       //Add other types like gitlab, bitbucket etc
+       return pkgerrors.New("Git Provider type not supported")
+
+}
+
+/*
+       Function to delete repo
+       params : context, git client , user name, repo name
+       return : nil/error
+*/
+func DeleteRepo(ctx context.Context, c interface{}, userName string, repoName string, gitType string) error {
+
+       switch gitType {
+       case "github":
+               err := emcogithub.DeleteRepo(ctx, convertToClient(c), userName, repoName)
+               if err != nil {
+                       return err
+               }
+               return nil
+       }
+       //Add other types like gitlab, bitbucket etc
+       return pkgerrors.New("Git Provider type not supported")
+}
+
+/*
+       Function to commit multiple files to the github repo
+       params : context, git client, User Name, Repo Name, Branch Name, Commit Message, files
+       return : nil/error
+*/
+func CommitFiles(ctx context.Context, c interface{}, userName string, repoName string, branch string, commitMessage string, files interface{}, gitType string) error {
+
+       switch gitType {
+       case "github":
+               err := emcogithub.CommitFiles(ctx, convertToClient(c), userName, repoName, branch, commitMessage, convertToCommitFile(files))
+               if err != nil {
+                       return err
+               }
+               return nil
+       }
+       //Add other types like gitlab, bitbucket etc
+       return pkgerrors.New("Git Provider type not supported")
+}
+
+/*
+       Function to Add file to the commit
+       params : path , content, files
+       return : files
+*/
+func Add(path string, content string, files interface{}, gitType string) interface{} {
+       switch gitType {
+       case "github":
+               ref := emcogithub.Add(path, content, convertToCommitFile(files))
+               return ref
+       }
+       //Add other types like gitlab, bitbucket etc
+       return nil
+}
+
+/*
+       Function to Delete file from the commit
+       params : path, files
+       return : files
+*/
+func Delete(path string, files interface{}, gitType string) interface{} {
+       switch gitType {
+       case "github":
+               ref := emcogithub.Delete(path, convertToCommitFile(files))
+               return ref
+       }
+       //Add other types like gitlab, bitbucket etc
+       return nil
+}
+
+func GetFiles(ctx context.Context, c interface{}, userName, repoName, branch, path, gitType string) (interface{}, error) {
+       switch gitType {
+       case "github":
+               ref, err := emcogithub.GetFiles(ctx, convertToClient(c), userName, repoName, branch, path)
+               return ref, err
+       }
+       //Add other types like gitlab, bitbucket etc
+       return nil, nil
+}
diff --git a/central-controller/src/rsync/pkg/gitops/emcogithub/emcogithub.go b/central-controller/src/rsync/pkg/gitops/emcogithub/emcogithub.go
new file mode 100644 (file)
index 0000000..4cc1d62
--- /dev/null
@@ -0,0 +1,177 @@
+// SPDX-License-Identifier: Apache-2.0
+// Copyright (c) 2022 Intel Corporation
+
+package emcogithub
+
+import (
+       "context"
+
+       "github.com/fluxcd/go-git-providers/github"
+       "github.com/fluxcd/go-git-providers/gitprovider"
+       log "gitlab.com/project-emco/core/emco-base/src/orchestrator/pkg/infra/logutils"
+)
+
+const (
+       githubDomain = "github.com"
+)
+
+/*
+       Function to create gitprovider githubClient
+       params : github token
+       return : gitprovider github client, error
+*/
+func CreateClient(githubToken string) (gitprovider.Client, error) {
+       c, err := github.NewClient(gitprovider.WithOAuth2Token(githubToken), gitprovider.WithDestructiveAPICalls(true))
+       if err != nil {
+               return nil, err
+       }
+       return c, nil
+}
+
+/*
+       Function to create a new Repo in github
+       params : context, github client, Repository Name, User Name, description
+       return : nil/error
+*/
+func CreateRepo(ctx context.Context, c gitprovider.Client, repoName string, userName string, desc string) error {
+
+       // create repo reference
+       userRepoRef := getRepoRef(userName, repoName)
+
+       // Create repoinfo reference
+       userRepoInfo := gitprovider.RepositoryInfo{
+               Description: &desc,
+               Visibility:  gitprovider.RepositoryVisibilityVar(gitprovider.RepositoryVisibilityPublic),
+       }
+
+       // Create the repository
+       _, err := c.UserRepositories().Create(ctx, userRepoRef, userRepoInfo, &gitprovider.RepositoryCreateOptions{
+               AutoInit:        gitprovider.BoolVar(true),
+               LicenseTemplate: gitprovider.LicenseTemplateVar(gitprovider.LicenseTemplateApache2),
+       })
+
+       if err != nil {
+               return err
+       }
+       log.Info("Repo Created", log.Fields{})
+
+       return nil
+}
+
+/*
+       Function to commit multiple files to the github repo
+       params : context, github client, User Name, Repo Name, Branch Name, Commit Message, files ([]gitprovider.CommitFile)
+       return : nil/error
+*/
+func CommitFiles(ctx context.Context, c gitprovider.Client, userName string, repoName string, branch string, commitMessage string, files []gitprovider.CommitFile) error {
+
+       // create repo reference
+       userRepoRef := getRepoRef(userName, repoName)
+
+       userRepo, err := c.UserRepositories().Get(ctx, userRepoRef)
+       if err != nil {
+               return err
+       }
+       //Commit file to this repo
+       _, err = userRepo.Commits().Create(ctx, branch, commitMessage, files)
+
+       if err != nil {
+               return err
+       }
+       return nil
+}
+
+/*
+       Function to delete repo
+       params : context, gitprovider client , user name, repo name
+       return : nil/error
+*/
+func DeleteRepo(ctx context.Context, c gitprovider.Client, userName string, repoName string) error {
+
+       // create repo reference
+       userRepoRef := getRepoRef(userName, repoName)
+       // get the reference of the repo to be deleted
+       userRepo, err := c.UserRepositories().Get(ctx, userRepoRef)
+
+       if err != nil {
+               return err
+       }
+       //delete repo
+       err = userRepo.Delete(ctx)
+
+       if err != nil {
+               return err
+       }
+
+       return nil
+}
+
+/*
+       Internal function to create a repo refercnce
+       params : user name, repo name
+       return : repo reference
+*/
+func getRepoRef(userName string, repoName string) gitprovider.UserRepositoryRef {
+       // Create the user reference
+       userRef := gitprovider.UserRef{
+               Domain:    githubDomain,
+               UserLogin: userName,
+       }
+
+       // Create the repo reference
+       userRepoRef := gitprovider.UserRepositoryRef{
+               UserRef:        userRef,
+               RepositoryName: repoName,
+       }
+
+       return userRepoRef
+}
+
+/*
+       Function to Add file to the commit
+       params : path , content, files (gitprovider commitfile array)
+       return : files (gitprovider commitfile array)
+*/
+func Add(path string, content string, files []gitprovider.CommitFile) []gitprovider.CommitFile {
+       files = append(files, gitprovider.CommitFile{
+               Path:    &path,
+               Content: &content,
+       })
+
+       return files
+}
+
+/*
+       Function to Delete file from the commit
+       params : path, files (gitprovider commitfile array)
+       return : files (gitprovider commitfile array)
+*/
+func Delete(path string, files []gitprovider.CommitFile) []gitprovider.CommitFile {
+       files = append(files, gitprovider.CommitFile{
+               Path:    &path,
+               Content: nil,
+       })
+
+       return files
+}
+
+/*
+       Function to get files to the github repo
+       params : context, github client, User Name, Repo Name, Branch Name, path)
+       return : []*gitprovider.CommitFile, nil/error
+*/
+func GetFiles(ctx context.Context, c gitprovider.Client, userName string, repoName string, branch string, path string) ([]*gitprovider.CommitFile, error) {
+
+       // create repo reference
+       userRepoRef := getRepoRef(userName, repoName)
+       userRepo, err := c.UserRepositories().Get(ctx, userRepoRef)
+       if err != nil {
+               return nil, err
+       }
+       // Read the files
+       cf, err := userRepo.Files().Get(ctx, path, branch)
+       if err != nil {
+               return nil, err
+       }
+       return cf, nil
+}
diff --git a/central-controller/src/rsync/pkg/gitops/gitsupport/gitsupport.go b/central-controller/src/rsync/pkg/gitops/gitsupport/gitsupport.go
new file mode 100644 (file)
index 0000000..6d0b79f
--- /dev/null
@@ -0,0 +1,269 @@
+// SPDX-License-Identifier: Apache-2.0
+// Copyright (c) 2022 Intel Corporation
+
+package gitsupport
+
+import (
+       "context"
+       "fmt"
+       log "gitlab.com/project-emco/core/emco-base/src/orchestrator/pkg/infra/logutils"
+       "strings"
+       "time"
+
+       "github.com/fluxcd/go-git-providers/gitprovider"
+       pkgerrors "github.com/pkg/errors"
+       v1alpha1 "gitlab.com/project-emco/core/emco-base/src/monitor/pkg/apis/k8splugin/v1alpha1"
+       "gitlab.com/project-emco/core/emco-base/src/rsync/pkg/db"
+       emcogit "gitlab.com/project-emco/core/emco-base/src/rsync/pkg/gitops/emcogit"
+       "gitlab.com/project-emco/core/emco-base/src/rsync/pkg/internal/utils"
+       "gitlab.com/project-emco/core/emco-base/src/rsync/pkg/status"
+)
+
+type GitProvider struct {
+       Cid       string
+       Cluster   string
+       App       string
+       Namespace string
+       Level     string
+       GitType   string
+       GitToken  string
+       UserName  string
+       Branch    string
+       RepoName  string
+       Url       string
+       Client    gitprovider.Client
+}
+
+/*
+       Function to create a New gitProivider
+       params : cid, app, cluster, level, namespace string
+       return : GitProvider, error
+*/
+func NewGitProvider(cid, app, cluster, level, namespace string) (*GitProvider, error) {
+
+       result := strings.SplitN(cluster, "+", 2)
+
+       c, err := utils.GetGitOpsConfig(cluster, level, namespace)
+       if err != nil {
+               return nil, err
+       }
+       // Read from database
+       ccc := db.NewCloudConfigClient()
+       refObject, err := ccc.GetClusterSyncObjects(result[0], c.Props.GitOpsReferenceObject)
+
+       if err != nil {
+               log.Error("Invalid refObject :", log.Fields{"refObj": c.Props.GitOpsReferenceObject, "error": err})
+               return nil, err
+       }
+
+       kvRef := refObject.Spec.Kv
+
+       var gitType, gitToken, branch, userName, repoName string
+
+       for _, kvpair := range kvRef {
+               log.Info("kvpair", log.Fields{"kvpair": kvpair})
+               v, ok := kvpair["gitType"]
+               if ok {
+                       gitType = fmt.Sprintf("%v", v)
+                       continue
+               }
+               v, ok = kvpair["gitToken"]
+               if ok {
+                       gitToken = fmt.Sprintf("%v", v)
+                       continue
+               }
+               v, ok = kvpair["repoName"]
+               if ok {
+                       repoName = fmt.Sprintf("%v", v)
+                       continue
+               }
+               v, ok = kvpair["userName"]
+               if ok {
+                       userName = fmt.Sprintf("%v", v)
+                       continue
+               }
+               v, ok = kvpair["branch"]
+               if ok {
+                       branch = fmt.Sprintf("%v", v)
+                       continue
+               }
+       }
+       if len(gitType) <= 0 || len(gitToken) <= 0 || len(branch) <= 0 || len(userName) <= 0 || len(repoName) <= 0 {
+               log.Error("Missing information for Git", log.Fields{"gitType": gitType, "token": gitToken, "branch": branch, "userName": userName, "repoName": repoName})
+               return nil, pkgerrors.Errorf("Missing Information for Git")
+       }
+
+       p := GitProvider{
+               Cid:       cid,
+               App:       app,
+               Cluster:   cluster,
+               Level:     level,
+               Namespace: namespace,
+               GitType:   gitType,
+               GitToken:  gitToken,
+               Branch:    branch,
+               UserName:  userName,
+               RepoName:  repoName,
+               Url:       "https://" + gitType + ".com/" + userName + "/" + repoName,
+       }
+       client, err := emcogit.CreateClient(gitToken, gitType)
+       if err != nil {
+               log.Error("Error getting git client", log.Fields{"err": err})
+               return nil, err
+       }
+       p.Client = client.(gitprovider.Client)
+       return &p, nil
+}
+
+/*
+       Function to get path of files stored in git
+       params : string
+       return : string
+*/
+
+func (p *GitProvider) GetPath(t string) string {
+       return "clusters/" + p.Cluster + "/" + t + "/" + p.Cid + "/app/" + p.App + "/"
+}
+
+/*
+       Function to create a new resource if the not already existing
+       params : name string, ref interface{}, content []byte
+       return : interface{}, error
+*/
+func (p *GitProvider) Create(name string, ref interface{}, content []byte) (interface{}, error) {
+
+       path := p.GetPath("context") + name + ".yaml"
+       ref = emcogit.Add(path, string(content), ref, p.GitType)
+       return ref, nil
+}
+
+/*
+       Function to apply resource to the cluster
+       params : name string, ref interface{}, content []byte
+       return : interface{}, error
+*/
+func (p *GitProvider) Apply(name string, ref interface{}, content []byte) (interface{}, error) {
+
+       path := p.GetPath("context") + name + ".yaml"
+       ref = emcogit.Add(path, string(content), ref, p.GitType)
+       return ref, nil
+
+}
+
+/*
+       Function to delete resource from the cluster
+       params : name string, ref interface{}, content []byte
+       return : interface{}, error
+*/
+func (p *GitProvider) Delete(name string, ref interface{}, content []byte) (interface{}, error) {
+
+       path := p.GetPath("context") + name + ".yaml"
+       ref = emcogit.Delete(path, ref, p.GitType)
+       return ref, nil
+
+}
+
+/*
+       Function to get resource from the cluster
+       params : name string, gvkRes []byte
+       return : []byte, error
+*/
+func (p *GitProvider) Get(name string, gvkRes []byte) ([]byte, error) {
+
+       return []byte{}, nil
+}
+
+/*
+       Function to commit resources to the cluster
+       params : ctx context.Context, ref interface{}
+       return : error
+*/
+func (p *GitProvider) Commit(ctx context.Context, ref interface{}) error {
+
+       var exists bool
+       switch ref.(type) {
+       case []gitprovider.CommitFile:
+               exists = true
+       default:
+               exists = false
+
+       }
+       // Check for rf
+       if !exists {
+               log.Error("Commit: No ref found", log.Fields{})
+               return nil
+       }
+       err := emcogit.CommitFiles(ctx, p.Client, p.UserName, p.RepoName, p.Branch, "Commit for "+p.GetPath("context"), ref.([]gitprovider.CommitFile), p.GitType)
+
+       return err
+}
+
+/*
+       Function for cluster reachablity test
+       params : null
+       return : error
+*/
+func (p *GitProvider) IsReachable() error {
+       return nil
+}
+
+// Wait time between reading git status (seconds)
+var waitTime int = 60
+
+// StartClusterWatcher watches for CR changes in git location
+// go routine starts and reads after waitTime
+// Thread exists when the AppContext is deleted
+func (p *GitProvider) StartClusterWatcher() error {
+       // Start thread to sync monitor CR
+       go func() error {
+               ctx := context.Background()
+               for {
+                       select {
+                       case <-time.After(time.Duration(waitTime) * time.Second):
+                               if ctx.Err() != nil {
+                                       return ctx.Err()
+                               }
+                               // Check if AppContext doesn't exist then exit the thread
+                               if _, err := utils.NewAppContextReference(p.Cid); err != nil {
+                                       // Delete the Status CR updated by Monitor running on the cluster
+                                       p.DeleteClusterStatusCR()
+                                       // AppContext deleted - Exit thread
+                                       return nil
+                               }
+                               path := p.GetPath("status")
+                               // Read file
+                               c, err := emcogit.GetFiles(ctx, p.Client, p.UserName, p.RepoName, p.Branch, path, p.GitType)
+                               if err != nil {
+                                       log.Error("Status file not available", log.Fields{"error": err, "cluster": p.Cluster, "resource": path})
+                                       continue
+                               }
+                               cp := c.([]*gitprovider.CommitFile)
+                               if len(cp) > 0 {
+                                       // Only one file expected in the location
+                                       content := &v1alpha1.ResourceBundleState{}
+                                       _, err := utils.DecodeYAMLData(*cp[0].Content, content)
+                                       if err != nil {
+                                               log.Error("", log.Fields{"error": err, "cluster": p.Cluster, "resource": path})
+                                               return err
+                                       }
+                                       status.HandleResourcesStatus(p.Cid, p.App, p.Cluster, content)
+                               }
+                       // Check if the context is canceled
+                       case <-ctx.Done():
+                               return ctx.Err()
+                       }
+               }
+       }()
+       return nil
+}
+
+// DeleteClusterStatusCR deletes the status CR provided by the monitor on the cluster
+func (p *GitProvider) DeleteClusterStatusCR() error {
+       // Delete the status CR
+       path := p.GetPath("status") + p.Cid + "-" + p.App
+       rf := []gitprovider.CommitFile{}
+       ref := emcogit.Delete(path, rf, p.GitType)
+       err := emcogit.CommitFiles(context.Background(), p.Client, p.UserName, p.RepoName, p.Branch,
+               "Commit for Delete Status CR "+p.GetPath("status"), ref, p.GitType)
+       return err
+}
index 1acf6a6..29c4a84 100644 (file)
@@ -8,8 +8,8 @@ import (
        "encoding/json"
        "log"
 
-       con "github.com/open-ness/EMCO/src/rsync/pkg/context"
-       "github.com/open-ness/EMCO/src/rsync/pkg/grpc/installapp"
+       con "gitlab.com/project-emco/core/emco-base/src/rsync/pkg/context"
+       "gitlab.com/project-emco/core/emco-base/src/rsync/pkg/grpc/installapp"
 )
 
 type installappServer struct {
index 4f61d63..1b48ed0 100644 (file)
@@ -9,7 +9,7 @@ import (
        reflect "reflect"
 
        gomock "github.com/golang/mock/gomock"
-       installapp "github.com/open-ness/EMCO/src/rsync/pkg/grpc/installapp"
+       installapp "gitlab.com/project-emco/core/emco-base/src/rsync/pkg/grpc/installapp"
        grpc "google.golang.org/grpc"
 )
 
diff --git a/central-controller/src/rsync/pkg/grpc/mock_readynotify/readynotify.mock.go b/central-controller/src/rsync/pkg/grpc/mock_readynotify/readynotify.mock.go
new file mode 100644 (file)
index 0000000..ae1a07a
--- /dev/null
@@ -0,0 +1,373 @@
+// Code generated by MockGen. DO NOT EDIT.
+// Source: readynotify/readynotify.pb.go
+
+// Package mock_readynotify is a generated GoMock package.
+package mock_readynotify
+
+import (
+       context "context"
+       reflect "reflect"
+
+       gomock "github.com/golang/mock/gomock"
+       readynotify "gitlab.com/project-emco/core/emco-base/src/rsync/pkg/grpc/readynotify"
+       context0 "golang.org/x/net/context"
+       grpc "google.golang.org/grpc"
+       metadata "google.golang.org/grpc/metadata"
+)
+
+// MockReadyNotifyClient is a mock of ReadyNotifyClient interface.
+type MockReadyNotifyClient struct {
+       ctrl     *gomock.Controller
+       recorder *MockReadyNotifyClientMockRecorder
+}
+
+// MockReadyNotifyClientMockRecorder is the mock recorder for MockReadyNotifyClient.
+type MockReadyNotifyClientMockRecorder struct {
+       mock *MockReadyNotifyClient
+}
+
+// NewMockReadyNotifyClient creates a new mock instance.
+func NewMockReadyNotifyClient(ctrl *gomock.Controller) *MockReadyNotifyClient {
+       mock := &MockReadyNotifyClient{ctrl: ctrl}
+       mock.recorder = &MockReadyNotifyClientMockRecorder{mock}
+       return mock
+}
+
+// EXPECT returns an object that allows the caller to indicate expected use.
+func (m *MockReadyNotifyClient) EXPECT() *MockReadyNotifyClientMockRecorder {
+       return m.recorder
+}
+
+// Alert mocks base method.
+func (m *MockReadyNotifyClient) Alert(ctx context0.Context, in *readynotify.Topic, opts ...grpc.CallOption) (readynotify.ReadyNotify_AlertClient, error) {
+       m.ctrl.T.Helper()
+       varargs := []interface{}{ctx, in}
+       for _, a := range opts {
+               varargs = append(varargs, a)
+       }
+       ret := m.ctrl.Call(m, "Alert", varargs...)
+       ret0, _ := ret[0].(readynotify.ReadyNotify_AlertClient)
+       ret1, _ := ret[1].(error)
+       return ret0, ret1
+}
+
+// Alert indicates an expected call of Alert.
+func (mr *MockReadyNotifyClientMockRecorder) Alert(ctx, in interface{}, opts ...interface{}) *gomock.Call {
+       mr.mock.ctrl.T.Helper()
+       varargs := append([]interface{}{ctx, in}, opts...)
+       return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Alert", reflect.TypeOf((*MockReadyNotifyClient)(nil).Alert), varargs...)
+}
+
+// Unsubscribe mocks base method.
+func (m *MockReadyNotifyClient) Unsubscribe(ctx context0.Context, in *readynotify.Topic, opts ...grpc.CallOption) (*readynotify.UnsubscribeResponse, error) {
+       m.ctrl.T.Helper()
+       varargs := []interface{}{ctx, in}
+       for _, a := range opts {
+               varargs = append(varargs, a)
+       }
+       ret := m.ctrl.Call(m, "Unsubscribe", varargs...)
+       ret0, _ := ret[0].(*readynotify.UnsubscribeResponse)
+       ret1, _ := ret[1].(error)
+       return ret0, ret1
+}
+
+// Unsubscribe indicates an expected call of Unsubscribe.
+func (mr *MockReadyNotifyClientMockRecorder) Unsubscribe(ctx, in interface{}, opts ...interface{}) *gomock.Call {
+       mr.mock.ctrl.T.Helper()
+       varargs := append([]interface{}{ctx, in}, opts...)
+       return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Unsubscribe", reflect.TypeOf((*MockReadyNotifyClient)(nil).Unsubscribe), varargs...)
+}
+
+// MockReadyNotify_AlertClient is a mock of ReadyNotify_AlertClient interface.
+type MockReadyNotify_AlertClient struct {
+       ctrl     *gomock.Controller
+       recorder *MockReadyNotify_AlertClientMockRecorder
+}
+
+// MockReadyNotify_AlertClientMockRecorder is the mock recorder for MockReadyNotify_AlertClient.
+type MockReadyNotify_AlertClientMockRecorder struct {
+       mock *MockReadyNotify_AlertClient
+}
+
+// NewMockReadyNotify_AlertClient creates a new mock instance.
+func NewMockReadyNotify_AlertClient(ctrl *gomock.Controller) *MockReadyNotify_AlertClient {
+       mock := &MockReadyNotify_AlertClient{ctrl: ctrl}
+       mock.recorder = &MockReadyNotify_AlertClientMockRecorder{mock}
+       return mock
+}
+
+// EXPECT returns an object that allows the caller to indicate expected use.
+func (m *MockReadyNotify_AlertClient) EXPECT() *MockReadyNotify_AlertClientMockRecorder {
+       return m.recorder
+}
+
+// CloseSend mocks base method.
+func (m *MockReadyNotify_AlertClient) CloseSend() error {
+       m.ctrl.T.Helper()
+       ret := m.ctrl.Call(m, "CloseSend")
+       ret0, _ := ret[0].(error)
+       return ret0
+}
+
+// CloseSend indicates an expected call of CloseSend.
+func (mr *MockReadyNotify_AlertClientMockRecorder) CloseSend() *gomock.Call {
+       mr.mock.ctrl.T.Helper()
+       return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "CloseSend", reflect.TypeOf((*MockReadyNotify_AlertClient)(nil).CloseSend))
+}
+
+// Context mocks base method.
+func (m *MockReadyNotify_AlertClient) Context() context.Context {
+       m.ctrl.T.Helper()
+       ret := m.ctrl.Call(m, "Context")
+       ret0, _ := ret[0].(context.Context)
+       return ret0
+}
+
+// Context indicates an expected call of Context.
+func (mr *MockReadyNotify_AlertClientMockRecorder) Context() *gomock.Call {
+       mr.mock.ctrl.T.Helper()
+       return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Context", reflect.TypeOf((*MockReadyNotify_AlertClient)(nil).Context))
+}
+
+// Header mocks base method.
+func (m *MockReadyNotify_AlertClient) Header() (metadata.MD, error) {
+       m.ctrl.T.Helper()
+       ret := m.ctrl.Call(m, "Header")
+       ret0, _ := ret[0].(metadata.MD)
+       ret1, _ := ret[1].(error)
+       return ret0, ret1
+}
+
+// Header indicates an expected call of Header.
+func (mr *MockReadyNotify_AlertClientMockRecorder) Header() *gomock.Call {
+       mr.mock.ctrl.T.Helper()
+       return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Header", reflect.TypeOf((*MockReadyNotify_AlertClient)(nil).Header))
+}
+
+// Recv mocks base method.
+func (m *MockReadyNotify_AlertClient) Recv() (*readynotify.Notification, error) {
+       m.ctrl.T.Helper()
+       ret := m.ctrl.Call(m, "Recv")
+       ret0, _ := ret[0].(*readynotify.Notification)
+       ret1, _ := ret[1].(error)
+       return ret0, ret1
+}
+
+// Recv indicates an expected call of Recv.
+func (mr *MockReadyNotify_AlertClientMockRecorder) Recv() *gomock.Call {
+       mr.mock.ctrl.T.Helper()
+       return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Recv", reflect.TypeOf((*MockReadyNotify_AlertClient)(nil).Recv))
+}
+
+// RecvMsg mocks base method.
+func (m_2 *MockReadyNotify_AlertClient) RecvMsg(m interface{}) error {
+       m_2.ctrl.T.Helper()
+       ret := m_2.ctrl.Call(m_2, "RecvMsg", m)
+       ret0, _ := ret[0].(error)
+       return ret0
+}
+
+// RecvMsg indicates an expected call of RecvMsg.
+func (mr *MockReadyNotify_AlertClientMockRecorder) RecvMsg(m interface{}) *gomock.Call {
+       mr.mock.ctrl.T.Helper()
+       return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "RecvMsg", reflect.TypeOf((*MockReadyNotify_AlertClient)(nil).RecvMsg), m)
+}
+
+// SendMsg mocks base method.
+func (m_2 *MockReadyNotify_AlertClient) SendMsg(m interface{}) error {
+       m_2.ctrl.T.Helper()
+       ret := m_2.ctrl.Call(m_2, "SendMsg", m)
+       ret0, _ := ret[0].(error)
+       return ret0
+}
+
+// SendMsg indicates an expected call of SendMsg.
+func (mr *MockReadyNotify_AlertClientMockRecorder) SendMsg(m interface{}) *gomock.Call {
+       mr.mock.ctrl.T.Helper()
+       return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SendMsg", reflect.TypeOf((*MockReadyNotify_AlertClient)(nil).SendMsg), m)
+}
+
+// Trailer mocks base method.
+func (m *MockReadyNotify_AlertClient) Trailer() metadata.MD {
+       m.ctrl.T.Helper()
+       ret := m.ctrl.Call(m, "Trailer")
+       ret0, _ := ret[0].(metadata.MD)
+       return ret0
+}
+
+// Trailer indicates an expected call of Trailer.
+func (mr *MockReadyNotify_AlertClientMockRecorder) Trailer() *gomock.Call {
+       mr.mock.ctrl.T.Helper()
+       return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Trailer", reflect.TypeOf((*MockReadyNotify_AlertClient)(nil).Trailer))
+}
+
+// MockReadyNotifyServer is a mock of ReadyNotifyServer interface.
+type MockReadyNotifyServer struct {
+       ctrl     *gomock.Controller
+       recorder *MockReadyNotifyServerMockRecorder
+}
+
+// MockReadyNotifyServerMockRecorder is the mock recorder for MockReadyNotifyServer.
+type MockReadyNotifyServerMockRecorder struct {
+       mock *MockReadyNotifyServer
+}
+
+// NewMockReadyNotifyServer creates a new mock instance.
+func NewMockReadyNotifyServer(ctrl *gomock.Controller) *MockReadyNotifyServer {
+       mock := &MockReadyNotifyServer{ctrl: ctrl}
+       mock.recorder = &MockReadyNotifyServerMockRecorder{mock}
+       return mock
+}
+
+// EXPECT returns an object that allows the caller to indicate expected use.
+func (m *MockReadyNotifyServer) EXPECT() *MockReadyNotifyServerMockRecorder {
+       return m.recorder
+}
+
+// Alert mocks base method.
+func (m *MockReadyNotifyServer) Alert(arg0 *readynotify.Topic, arg1 readynotify.ReadyNotify_AlertServer) error {
+       m.ctrl.T.Helper()
+       ret := m.ctrl.Call(m, "Alert", arg0, arg1)
+       ret0, _ := ret[0].(error)
+       return ret0
+}
+
+// Alert indicates an expected call of Alert.
+func (mr *MockReadyNotifyServerMockRecorder) Alert(arg0, arg1 interface{}) *gomock.Call {
+       mr.mock.ctrl.T.Helper()
+       return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Alert", reflect.TypeOf((*MockReadyNotifyServer)(nil).Alert), arg0, arg1)
+}
+
+// Unsubscribe mocks base method.
+func (m *MockReadyNotifyServer) Unsubscribe(arg0 context0.Context, arg1 *readynotify.Topic) (*readynotify.UnsubscribeResponse, error) {
+       m.ctrl.T.Helper()
+       ret := m.ctrl.Call(m, "Unsubscribe", arg0, arg1)
+       ret0, _ := ret[0].(*readynotify.UnsubscribeResponse)
+       ret1, _ := ret[1].(error)
+       return ret0, ret1
+}
+
+// Unsubscribe indicates an expected call of Unsubscribe.
+func (mr *MockReadyNotifyServerMockRecorder) Unsubscribe(arg0, arg1 interface{}) *gomock.Call {
+       mr.mock.ctrl.T.Helper()
+       return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Unsubscribe", reflect.TypeOf((*MockReadyNotifyServer)(nil).Unsubscribe), arg0, arg1)
+}
+
+// MockReadyNotify_AlertServer is a mock of ReadyNotify_AlertServer interface.
+type MockReadyNotify_AlertServer struct {
+       ctrl     *gomock.Controller
+       recorder *MockReadyNotify_AlertServerMockRecorder
+}
+
+// MockReadyNotify_AlertServerMockRecorder is the mock recorder for MockReadyNotify_AlertServer.
+type MockReadyNotify_AlertServerMockRecorder struct {
+       mock *MockReadyNotify_AlertServer
+}
+
+// NewMockReadyNotify_AlertServer creates a new mock instance.
+func NewMockReadyNotify_AlertServer(ctrl *gomock.Controller) *MockReadyNotify_AlertServer {
+       mock := &MockReadyNotify_AlertServer{ctrl: ctrl}
+       mock.recorder = &MockReadyNotify_AlertServerMockRecorder{mock}
+       return mock
+}
+
+// EXPECT returns an object that allows the caller to indicate expected use.
+func (m *MockReadyNotify_AlertServer) EXPECT() *MockReadyNotify_AlertServerMockRecorder {
+       return m.recorder
+}
+
+// Context mocks base method.
+func (m *MockReadyNotify_AlertServer) Context() context.Context {
+       m.ctrl.T.Helper()
+       ret := m.ctrl.Call(m, "Context")
+       ret0, _ := ret[0].(context.Context)
+       return ret0
+}
+
+// Context indicates an expected call of Context.
+func (mr *MockReadyNotify_AlertServerMockRecorder) Context() *gomock.Call {
+       mr.mock.ctrl.T.Helper()
+       return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Context", reflect.TypeOf((*MockReadyNotify_AlertServer)(nil).Context))
+}
+
+// RecvMsg mocks base method.
+func (m_2 *MockReadyNotify_AlertServer) RecvMsg(m interface{}) error {
+       m_2.ctrl.T.Helper()
+       ret := m_2.ctrl.Call(m_2, "RecvMsg", m)
+       ret0, _ := ret[0].(error)
+       return ret0
+}
+
+// RecvMsg indicates an expected call of RecvMsg.
+func (mr *MockReadyNotify_AlertServerMockRecorder) RecvMsg(m interface{}) *gomock.Call {
+       mr.mock.ctrl.T.Helper()
+       return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "RecvMsg", reflect.TypeOf((*MockReadyNotify_AlertServer)(nil).RecvMsg), m)
+}
+
+// Send mocks base method.
+func (m *MockReadyNotify_AlertServer) Send(arg0 *readynotify.Notification) error {
+       m.ctrl.T.Helper()
+       ret := m.ctrl.Call(m, "Send", arg0)
+       ret0, _ := ret[0].(error)
+       return ret0
+}
+
+// Send indicates an expected call of Send.
+func (mr *MockReadyNotify_AlertServerMockRecorder) Send(arg0 interface{}) *gomock.Call {
+       mr.mock.ctrl.T.Helper()
+       return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Send", reflect.TypeOf((*MockReadyNotify_AlertServer)(nil).Send), arg0)
+}
+
+// SendHeader mocks base method.
+func (m *MockReadyNotify_AlertServer) SendHeader(arg0 metadata.MD) error {
+       m.ctrl.T.Helper()
+       ret := m.ctrl.Call(m, "SendHeader", arg0)
+       ret0, _ := ret[0].(error)
+       return ret0
+}
+
+// SendHeader indicates an expected call of SendHeader.
+func (mr *MockReadyNotify_AlertServerMockRecorder) SendHeader(arg0 interface{}) *gomock.Call {
+       mr.mock.ctrl.T.Helper()
+       return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SendHeader", reflect.TypeOf((*MockReadyNotify_AlertServer)(nil).SendHeader), arg0)
+}
+
+// SendMsg mocks base method.
+func (m_2 *MockReadyNotify_AlertServer) SendMsg(m interface{}) error {
+       m_2.ctrl.T.Helper()
+       ret := m_2.ctrl.Call(m_2, "SendMsg", m)
+       ret0, _ := ret[0].(error)
+       return ret0
+}
+
+// SendMsg indicates an expected call of SendMsg.
+func (mr *MockReadyNotify_AlertServerMockRecorder) SendMsg(m interface{}) *gomock.Call {
+       mr.mock.ctrl.T.Helper()
+       return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SendMsg", reflect.TypeOf((*MockReadyNotify_AlertServer)(nil).SendMsg), m)
+}
+
+// SetHeader mocks base method.
+func (m *MockReadyNotify_AlertServer) SetHeader(arg0 metadata.MD) error {
+       m.ctrl.T.Helper()
+       ret := m.ctrl.Call(m, "SetHeader", arg0)
+       ret0, _ := ret[0].(error)
+       return ret0
+}
+
+// SetHeader indicates an expected call of SetHeader.
+func (mr *MockReadyNotify_AlertServerMockRecorder) SetHeader(arg0 interface{}) *gomock.Call {
+       mr.mock.ctrl.T.Helper()
+       return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SetHeader", reflect.TypeOf((*MockReadyNotify_AlertServer)(nil).SetHeader), arg0)
+}
+
+// SetTrailer mocks base method.
+func (m *MockReadyNotify_AlertServer) SetTrailer(arg0 metadata.MD) {
+       m.ctrl.T.Helper()
+       m.ctrl.Call(m, "SetTrailer", arg0)
+}
+
+// SetTrailer indicates an expected call of SetTrailer.
+func (mr *MockReadyNotify_AlertServerMockRecorder) SetTrailer(arg0 interface{}) *gomock.Call {
+       mr.mock.ctrl.T.Helper()
+       return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SetTrailer", reflect.TypeOf((*MockReadyNotify_AlertServer)(nil).SetTrailer), arg0)
+}
index d5270be..9028b1f 100644 (file)
@@ -8,8 +8,8 @@ import (
        "log"
        "sync"
 
-       "github.com/open-ness/EMCO/src/orchestrator/pkg/infra/logutils"
-       pb "github.com/open-ness/EMCO/src/rsync/pkg/grpc/readynotify"
+       "gitlab.com/project-emco/core/emco-base/src/orchestrator/pkg/infra/logutils"
+       pb "gitlab.com/project-emco/core/emco-base/src/rsync/pkg/grpc/readynotify"
 )
 
 // readyNotifyServer will be initialized by NewReadyNotifyServer() and
@@ -39,11 +39,15 @@ func (s *readyNotifyServer) Alert(topic *pb.Topic, stream pb.ReadyNotify_AlertSe
        s.alertNotify[appContextID][client] = stream
        s.streamChannel[stream] = make(chan int)
        c := s.streamChannel[stream]
+       ctx := stream.Context()
        s.mutex.Unlock()
 
        // Keep stream open
        for {
                select {
+               case <-ctx.Done():
+                       logutils.Info("[ReadyNotify gRPC] Client has disconnected", logutils.Fields{"client": client})
+                       return nil
                case <-c:
                        log.Printf("[ReadyNotify gRPC] stop channel got triggered for the client = %s\n", client)
                        return nil
index f2d2267..81e417f 100644 (file)
@@ -10,9 +10,25 @@ import (
        "testing"
        "time"
 
-       pb "github.com/open-ness/EMCO/src/rsync/pkg/grpc/readynotify"
+       pb "gitlab.com/project-emco/core/emco-base/src/rsync/pkg/grpc/readynotify"
+       "google.golang.org/grpc/metadata"
 )
 
+type mockReadyNotify_AlertServer struct {
+}
+
+func (x mockReadyNotify_AlertServer) Send(m *pb.Notification) error { return nil }
+func (x mockReadyNotify_AlertServer) SetHeader(metadata.MD) error   { return nil }
+func (x mockReadyNotify_AlertServer) SendHeader(metadata.MD) error  { return nil }
+func (x mockReadyNotify_AlertServer) SetTrailer(metadata.MD)        {}
+func (x mockReadyNotify_AlertServer) Context() context.Context {
+       ctx, cancel := context.WithTimeout(context.Background(), 1*time.Millisecond)
+       defer cancel()
+       return ctx
+}
+func (x mockReadyNotify_AlertServer) SendMsg(m interface{}) error { return nil }
+func (x mockReadyNotify_AlertServer) RecvMsg(m interface{}) error { return nil }
+
 func Test_readyNotifyServer_Alert(t *testing.T) {
        type fields struct {
                name          string
@@ -47,7 +63,7 @@ func Test_readyNotifyServer_Alert(t *testing.T) {
                                        ClientName: "dtc",
                                        AppContext: "123345",
                                },
-                               stream: nil,
+                               stream: mockReadyNotify_AlertServer{},
                        },
                        wantErr: false,
                },
@@ -65,7 +81,7 @@ func Test_readyNotifyServer_Alert(t *testing.T) {
                                        ClientName: "dtc",
                                        AppContext: "123345",
                                },
-                               stream: nil,
+                               stream: mockReadyNotify_AlertServer{},
                        },
                        wantErr: false,
                },
diff --git a/central-controller/src/rsync/pkg/grpc/register.go b/central-controller/src/rsync/pkg/grpc/register.go
deleted file mode 100644 (file)
index 603b0b0..0000000
+++ /dev/null
@@ -1,48 +0,0 @@
-// SPDX-License-Identifier: Apache-2.0
-// Copyright (c) 2020 Intel Corporation
-
-package grpc
-
-import (
-       "os"
-       "strconv"
-       "strings"
-
-       log "github.com/open-ness/EMCO/src/orchestrator/pkg/infra/logutils"
-)
-
-const default_host = "localhost"
-const default_port = 9031
-const default_rsync_name = "rsync"
-const ENV_RSYNC_NAME = "RSYNC_NAME"
-
-func GetServerHostPort() (string, int) {
-
-       // expect name of this rsync program to be in env variable "RSYNC_NAME" - e.g. RSYNC_NAME="rsync"
-       serviceName := os.Getenv(ENV_RSYNC_NAME)
-       if serviceName == "" {
-               serviceName = default_rsync_name
-               log.Info("Using default name for RSYNC service name", log.Fields{
-                       "Name": serviceName,
-               })
-       }
-
-       // expect service name to be in env variable - e.g. RSYNC_SERVICE_HOST
-       host := os.Getenv(strings.ToUpper(serviceName) + "_SERVICE_HOST")
-       if host == "" {
-               host = default_host
-               log.Info("Using default host for rsync gRPC controller", log.Fields{
-                       "Host": host,
-               })
-       }
-
-       // expect service port to be in env variable - e.g. RSYNC_SERVICE_PORT
-       port, err := strconv.Atoi(os.Getenv(strings.ToUpper(serviceName) + "_SERVICE_PORT"))
-       if err != nil || port < 0 {
-               port = default_port
-               log.Info("Using default port for rsync gRPC controller", log.Fields{
-                       "Port": port,
-               })
-       }
-       return host, port
-}
diff --git a/central-controller/src/rsync/pkg/grpc/updateapp/updateapp.pb.go b/central-controller/src/rsync/pkg/grpc/updateapp/updateapp.pb.go
new file mode 100644 (file)
index 0000000..0914826
--- /dev/null
@@ -0,0 +1,525 @@
+// SPDX-License-Identifier: Apache-2.0
+// Copyright (c) 2020 Intel Corporation
+
+// Code generated by protoc-gen-go. DO NOT EDIT.
+// versions:
+//     protoc-gen-go v1.24.0
+//     protoc        v3.12.4
+// source: updateapp.proto
+
+package updateapp
+
+import (
+       context "context"
+       proto "github.com/golang/protobuf/proto"
+       grpc "google.golang.org/grpc"
+       codes "google.golang.org/grpc/codes"
+       status "google.golang.org/grpc/status"
+       protoreflect "google.golang.org/protobuf/reflect/protoreflect"
+       protoimpl "google.golang.org/protobuf/runtime/protoimpl"
+       reflect "reflect"
+       sync "sync"
+)
+
+const (
+       // Verify that this generated code is sufficiently up-to-date.
+       _ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)
+       // Verify that runtime/protoimpl is sufficiently up-to-date.
+       _ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
+)
+
+// This is a compile-time assertion that a sufficiently up-to-date version
+// of the legacy proto package is being used.
+const _ = proto.ProtoPackageIsVersion4
+
+type UpdateAppRequest struct {
+       state         protoimpl.MessageState
+       sizeCache     protoimpl.SizeCache
+       unknownFields protoimpl.UnknownFields
+
+       UpdateFromAppContext string `protobuf:"bytes,1,opt,name=update_from_appContext,json=updateFromAppContext,proto3" json:"update_from_appContext,omitempty"`
+       UpdateToAppContext   string `protobuf:"bytes,2,opt,name=update_to_appContext,json=updateToAppContext,proto3" json:"update_to_appContext,omitempty"`
+}
+
+func (x *UpdateAppRequest) Reset() {
+       *x = UpdateAppRequest{}
+       if protoimpl.UnsafeEnabled {
+               mi := &file_updateapp_proto_msgTypes[0]
+               ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+               ms.StoreMessageInfo(mi)
+       }
+}
+
+func (x *UpdateAppRequest) String() string {
+       return protoimpl.X.MessageStringOf(x)
+}
+
+func (*UpdateAppRequest) ProtoMessage() {}
+
+func (x *UpdateAppRequest) ProtoReflect() protoreflect.Message {
+       mi := &file_updateapp_proto_msgTypes[0]
+       if protoimpl.UnsafeEnabled && x != nil {
+               ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+               if ms.LoadMessageInfo() == nil {
+                       ms.StoreMessageInfo(mi)
+               }
+               return ms
+       }
+       return mi.MessageOf(x)
+}
+
+// Deprecated: Use UpdateAppRequest.ProtoReflect.Descriptor instead.
+func (*UpdateAppRequest) Descriptor() ([]byte, []int) {
+       return file_updateapp_proto_rawDescGZIP(), []int{0}
+}
+
+func (x *UpdateAppRequest) GetUpdateFromAppContext() string {
+       if x != nil {
+               return x.UpdateFromAppContext
+       }
+       return ""
+}
+
+func (x *UpdateAppRequest) GetUpdateToAppContext() string {
+       if x != nil {
+               return x.UpdateToAppContext
+       }
+       return ""
+}
+
+type UpdateAppResponse struct {
+       state         protoimpl.MessageState
+       sizeCache     protoimpl.SizeCache
+       unknownFields protoimpl.UnknownFields
+
+       AppContextUpdated       bool   `protobuf:"varint,1,opt,name=app_context_updated,json=appContextUpdated,proto3" json:"app_context_updated,omitempty"`
+       AppContextUpdateMessage string `protobuf:"bytes,2,opt,name=app_context_update_message,json=appContextUpdateMessage,proto3" json:"app_context_update_message,omitempty"`
+}
+
+func (x *UpdateAppResponse) Reset() {
+       *x = UpdateAppResponse{}
+       if protoimpl.UnsafeEnabled {
+               mi := &file_updateapp_proto_msgTypes[1]
+               ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+               ms.StoreMessageInfo(mi)
+       }
+}
+
+func (x *UpdateAppResponse) String() string {
+       return protoimpl.X.MessageStringOf(x)
+}
+
+func (*UpdateAppResponse) ProtoMessage() {}
+
+func (x *UpdateAppResponse) ProtoReflect() protoreflect.Message {
+       mi := &file_updateapp_proto_msgTypes[1]
+       if protoimpl.UnsafeEnabled && x != nil {
+               ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+               if ms.LoadMessageInfo() == nil {
+                       ms.StoreMessageInfo(mi)
+               }
+               return ms
+       }
+       return mi.MessageOf(x)
+}
+
+// Deprecated: Use UpdateAppResponse.ProtoReflect.Descriptor instead.
+func (*UpdateAppResponse) Descriptor() ([]byte, []int) {
+       return file_updateapp_proto_rawDescGZIP(), []int{1}
+}
+
+func (x *UpdateAppResponse) GetAppContextUpdated() bool {
+       if x != nil {
+               return x.AppContextUpdated
+       }
+       return false
+}
+
+func (x *UpdateAppResponse) GetAppContextUpdateMessage() string {
+       if x != nil {
+               return x.AppContextUpdateMessage
+       }
+       return ""
+}
+
+type RollbackAppRequest struct {
+       state         protoimpl.MessageState
+       sizeCache     protoimpl.SizeCache
+       unknownFields protoimpl.UnknownFields
+
+       RollbackFromAppContext string `protobuf:"bytes,1,opt,name=rollback_from_appContext,json=rollbackFromAppContext,proto3" json:"rollback_from_appContext,omitempty"`
+       RollbackToAppContext   string `protobuf:"bytes,2,opt,name=rollback_to_appContext,json=rollbackToAppContext,proto3" json:"rollback_to_appContext,omitempty"`
+}
+
+func (x *RollbackAppRequest) Reset() {
+       *x = RollbackAppRequest{}
+       if protoimpl.UnsafeEnabled {
+               mi := &file_updateapp_proto_msgTypes[2]
+               ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+               ms.StoreMessageInfo(mi)
+       }
+}
+
+func (x *RollbackAppRequest) String() string {
+       return protoimpl.X.MessageStringOf(x)
+}
+
+func (*RollbackAppRequest) ProtoMessage() {}
+
+func (x *RollbackAppRequest) ProtoReflect() protoreflect.Message {
+       mi := &file_updateapp_proto_msgTypes[2]
+       if protoimpl.UnsafeEnabled && x != nil {
+               ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+               if ms.LoadMessageInfo() == nil {
+                       ms.StoreMessageInfo(mi)
+               }
+               return ms
+       }
+       return mi.MessageOf(x)
+}
+
+// Deprecated: Use RollbackAppRequest.ProtoReflect.Descriptor instead.
+func (*RollbackAppRequest) Descriptor() ([]byte, []int) {
+       return file_updateapp_proto_rawDescGZIP(), []int{2}
+}
+
+func (x *RollbackAppRequest) GetRollbackFromAppContext() string {
+       if x != nil {
+               return x.RollbackFromAppContext
+       }
+       return ""
+}
+
+func (x *RollbackAppRequest) GetRollbackToAppContext() string {
+       if x != nil {
+               return x.RollbackToAppContext
+       }
+       return ""
+}
+
+type RollbackAppResponse struct {
+       state         protoimpl.MessageState
+       sizeCache     protoimpl.SizeCache
+       unknownFields protoimpl.UnknownFields
+
+       AppContextRolledback      bool   `protobuf:"varint,1,opt,name=app_context_rolledback,json=appContextRolledback,proto3" json:"app_context_rolledback,omitempty"`
+       AppContextRollbackMessage string `protobuf:"bytes,2,opt,name=app_context_rollback_message,json=appContextRollbackMessage,proto3" json:"app_context_rollback_message,omitempty"`
+}
+
+func (x *RollbackAppResponse) Reset() {
+       *x = RollbackAppResponse{}
+       if protoimpl.UnsafeEnabled {
+               mi := &file_updateapp_proto_msgTypes[3]
+               ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+               ms.StoreMessageInfo(mi)
+       }
+}
+
+func (x *RollbackAppResponse) String() string {
+       return protoimpl.X.MessageStringOf(x)
+}
+
+func (*RollbackAppResponse) ProtoMessage() {}
+
+func (x *RollbackAppResponse) ProtoReflect() protoreflect.Message {
+       mi := &file_updateapp_proto_msgTypes[3]
+       if protoimpl.UnsafeEnabled && x != nil {
+               ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+               if ms.LoadMessageInfo() == nil {
+                       ms.StoreMessageInfo(mi)
+               }
+               return ms
+       }
+       return mi.MessageOf(x)
+}
+
+// Deprecated: Use RollbackAppResponse.ProtoReflect.Descriptor instead.
+func (*RollbackAppResponse) Descriptor() ([]byte, []int) {
+       return file_updateapp_proto_rawDescGZIP(), []int{3}
+}
+
+func (x *RollbackAppResponse) GetAppContextRolledback() bool {
+       if x != nil {
+               return x.AppContextRolledback
+       }
+       return false
+}
+
+func (x *RollbackAppResponse) GetAppContextRollbackMessage() string {
+       if x != nil {
+               return x.AppContextRollbackMessage
+       }
+       return ""
+}
+
+var File_updateapp_proto protoreflect.FileDescriptor
+
+var file_updateapp_proto_rawDesc = []byte{
+       0x0a, 0x0f, 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, 0x61, 0x70, 0x70, 0x2e, 0x70, 0x72, 0x6f, 0x74,
+       0x6f, 0x22, 0x7a, 0x0a, 0x10, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x41, 0x70, 0x70, 0x52, 0x65,
+       0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x34, 0x0a, 0x16, 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, 0x5f,
+       0x66, 0x72, 0x6f, 0x6d, 0x5f, 0x61, 0x70, 0x70, 0x43, 0x6f, 0x6e, 0x74, 0x65, 0x78, 0x74, 0x18,
+       0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x14, 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, 0x46, 0x72, 0x6f,
+       0x6d, 0x41, 0x70, 0x70, 0x43, 0x6f, 0x6e, 0x74, 0x65, 0x78, 0x74, 0x12, 0x30, 0x0a, 0x14, 0x75,
+       0x70, 0x64, 0x61, 0x74, 0x65, 0x5f, 0x74, 0x6f, 0x5f, 0x61, 0x70, 0x70, 0x43, 0x6f, 0x6e, 0x74,
+       0x65, 0x78, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x12, 0x75, 0x70, 0x64, 0x61, 0x74,
+       0x65, 0x54, 0x6f, 0x41, 0x70, 0x70, 0x43, 0x6f, 0x6e, 0x74, 0x65, 0x78, 0x74, 0x22, 0x80, 0x01,
+       0x0a, 0x11, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x41, 0x70, 0x70, 0x52, 0x65, 0x73, 0x70, 0x6f,
+       0x6e, 0x73, 0x65, 0x12, 0x2e, 0x0a, 0x13, 0x61, 0x70, 0x70, 0x5f, 0x63, 0x6f, 0x6e, 0x74, 0x65,
+       0x78, 0x74, 0x5f, 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x08,
+       0x52, 0x11, 0x61, 0x70, 0x70, 0x43, 0x6f, 0x6e, 0x74, 0x65, 0x78, 0x74, 0x55, 0x70, 0x64, 0x61,
+       0x74, 0x65, 0x64, 0x12, 0x3b, 0x0a, 0x1a, 0x61, 0x70, 0x70, 0x5f, 0x63, 0x6f, 0x6e, 0x74, 0x65,
+       0x78, 0x74, 0x5f, 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, 0x5f, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67,
+       0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x17, 0x61, 0x70, 0x70, 0x43, 0x6f, 0x6e, 0x74,
+       0x65, 0x78, 0x74, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65,
+       0x22, 0x84, 0x01, 0x0a, 0x12, 0x52, 0x6f, 0x6c, 0x6c, 0x62, 0x61, 0x63, 0x6b, 0x41, 0x70, 0x70,
+       0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x38, 0x0a, 0x18, 0x72, 0x6f, 0x6c, 0x6c, 0x62,
+       0x61, 0x63, 0x6b, 0x5f, 0x66, 0x72, 0x6f, 0x6d, 0x5f, 0x61, 0x70, 0x70, 0x43, 0x6f, 0x6e, 0x74,
+       0x65, 0x78, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x16, 0x72, 0x6f, 0x6c, 0x6c, 0x62,
+       0x61, 0x63, 0x6b, 0x46, 0x72, 0x6f, 0x6d, 0x41, 0x70, 0x70, 0x43, 0x6f, 0x6e, 0x74, 0x65, 0x78,
+       0x74, 0x12, 0x34, 0x0a, 0x16, 0x72, 0x6f, 0x6c, 0x6c, 0x62, 0x61, 0x63, 0x6b, 0x5f, 0x74, 0x6f,
+       0x5f, 0x61, 0x70, 0x70, 0x43, 0x6f, 0x6e, 0x74, 0x65, 0x78, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28,
+       0x09, 0x52, 0x14, 0x72, 0x6f, 0x6c, 0x6c, 0x62, 0x61, 0x63, 0x6b, 0x54, 0x6f, 0x41, 0x70, 0x70,
+       0x43, 0x6f, 0x6e, 0x74, 0x65, 0x78, 0x74, 0x22, 0x8c, 0x01, 0x0a, 0x13, 0x52, 0x6f, 0x6c, 0x6c,
+       0x62, 0x61, 0x63, 0x6b, 0x41, 0x70, 0x70, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12,
+       0x34, 0x0a, 0x16, 0x61, 0x70, 0x70, 0x5f, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x78, 0x74, 0x5f, 0x72,
+       0x6f, 0x6c, 0x6c, 0x65, 0x64, 0x62, 0x61, 0x63, 0x6b, 0x18, 0x01, 0x20, 0x01, 0x28, 0x08, 0x52,
+       0x14, 0x61, 0x70, 0x70, 0x43, 0x6f, 0x6e, 0x74, 0x65, 0x78, 0x74, 0x52, 0x6f, 0x6c, 0x6c, 0x65,
+       0x64, 0x62, 0x61, 0x63, 0x6b, 0x12, 0x3f, 0x0a, 0x1c, 0x61, 0x70, 0x70, 0x5f, 0x63, 0x6f, 0x6e,
+       0x74, 0x65, 0x78, 0x74, 0x5f, 0x72, 0x6f, 0x6c, 0x6c, 0x62, 0x61, 0x63, 0x6b, 0x5f, 0x6d, 0x65,
+       0x73, 0x73, 0x61, 0x67, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x19, 0x61, 0x70, 0x70,
+       0x43, 0x6f, 0x6e, 0x74, 0x65, 0x78, 0x74, 0x52, 0x6f, 0x6c, 0x6c, 0x62, 0x61, 0x63, 0x6b, 0x4d,
+       0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x32, 0x7d, 0x0a, 0x09, 0x75, 0x70, 0x64, 0x61, 0x74, 0x65,
+       0x61, 0x70, 0x70, 0x12, 0x34, 0x0a, 0x09, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x41, 0x70, 0x70,
+       0x12, 0x11, 0x2e, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x41, 0x70, 0x70, 0x52, 0x65, 0x71, 0x75,
+       0x65, 0x73, 0x74, 0x1a, 0x12, 0x2e, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x41, 0x70, 0x70, 0x52,
+       0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, 0x3a, 0x0a, 0x0b, 0x52, 0x6f, 0x6c,
+       0x6c, 0x62, 0x61, 0x63, 0x6b, 0x41, 0x70, 0x70, 0x12, 0x13, 0x2e, 0x52, 0x6f, 0x6c, 0x6c, 0x62,
+       0x61, 0x63, 0x6b, 0x41, 0x70, 0x70, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x14, 0x2e,
+       0x52, 0x6f, 0x6c, 0x6c, 0x62, 0x61, 0x63, 0x6b, 0x41, 0x70, 0x70, 0x52, 0x65, 0x73, 0x70, 0x6f,
+       0x6e, 0x73, 0x65, 0x22, 0x00, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
+}
+
+var (
+       file_updateapp_proto_rawDescOnce sync.Once
+       file_updateapp_proto_rawDescData = file_updateapp_proto_rawDesc
+)
+
+func file_updateapp_proto_rawDescGZIP() []byte {
+       file_updateapp_proto_rawDescOnce.Do(func() {
+               file_updateapp_proto_rawDescData = protoimpl.X.CompressGZIP(file_updateapp_proto_rawDescData)
+       })
+       return file_updateapp_proto_rawDescData
+}
+
+var file_updateapp_proto_msgTypes = make([]protoimpl.MessageInfo, 4)
+var file_updateapp_proto_goTypes = []interface{}{
+       (*UpdateAppRequest)(nil),    // 0: UpdateAppRequest
+       (*UpdateAppResponse)(nil),   // 1: UpdateAppResponse
+       (*RollbackAppRequest)(nil),  // 2: RollbackAppRequest
+       (*RollbackAppResponse)(nil), // 3: RollbackAppResponse
+}
+var file_updateapp_proto_depIdxs = []int32{
+       0, // 0: updateapp.UpdateApp:input_type -> UpdateAppRequest
+       2, // 1: updateapp.RollbackApp:input_type -> RollbackAppRequest
+       1, // 2: updateapp.UpdateApp:output_type -> UpdateAppResponse
+       3, // 3: updateapp.RollbackApp:output_type -> RollbackAppResponse
+       2, // [2:4] is the sub-list for method output_type
+       0, // [0:2] is the sub-list for method input_type
+       0, // [0:0] is the sub-list for extension type_name
+       0, // [0:0] is the sub-list for extension extendee
+       0, // [0:0] is the sub-list for field type_name
+}
+
+func init() { file_updateapp_proto_init() }
+func file_updateapp_proto_init() {
+       if File_updateapp_proto != nil {
+               return
+       }
+       if !protoimpl.UnsafeEnabled {
+               file_updateapp_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} {
+                       switch v := v.(*UpdateAppRequest); i {
+                       case 0:
+                               return &v.state
+                       case 1:
+                               return &v.sizeCache
+                       case 2:
+                               return &v.unknownFields
+                       default:
+                               return nil
+                       }
+               }
+               file_updateapp_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} {
+                       switch v := v.(*UpdateAppResponse); i {
+                       case 0:
+                               return &v.state
+                       case 1:
+                               return &v.sizeCache
+                       case 2:
+                               return &v.unknownFields
+                       default:
+                               return nil
+                       }
+               }
+               file_updateapp_proto_msgTypes[2].Exporter = func(v interface{}, i int) interface{} {
+                       switch v := v.(*RollbackAppRequest); i {
+                       case 0:
+                               return &v.state
+                       case 1:
+                               return &v.sizeCache
+                       case 2:
+                               return &v.unknownFields
+                       default:
+                               return nil
+                       }
+               }
+               file_updateapp_proto_msgTypes[3].Exporter = func(v interface{}, i int) interface{} {
+                       switch v := v.(*RollbackAppResponse); i {
+                       case 0:
+                               return &v.state
+                       case 1:
+                               return &v.sizeCache
+                       case 2:
+                               return &v.unknownFields
+                       default:
+                               return nil
+                       }
+               }
+       }
+       type x struct{}
+       out := protoimpl.TypeBuilder{
+               File: protoimpl.DescBuilder{
+                       GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
+                       RawDescriptor: file_updateapp_proto_rawDesc,
+                       NumEnums:      0,
+                       NumMessages:   4,
+                       NumExtensions: 0,
+                       NumServices:   1,
+               },
+               GoTypes:           file_updateapp_proto_goTypes,
+               DependencyIndexes: file_updateapp_proto_depIdxs,
+               MessageInfos:      file_updateapp_proto_msgTypes,
+       }.Build()
+       File_updateapp_proto = out.File
+       file_updateapp_proto_rawDesc = nil
+       file_updateapp_proto_goTypes = nil
+       file_updateapp_proto_depIdxs = nil
+}
+
+// Reference imports to suppress errors if they are not otherwise used.
+var _ context.Context
+var _ grpc.ClientConnInterface
+
+// This is a compile-time assertion to ensure that this generated file
+// is compatible with the grpc package it is being compiled against.
+const _ = grpc.SupportPackageIsVersion6
+
+// UpdateappClient is the client API for Updateapp service.
+//
+// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://godoc.org/google.golang.org/grpc#ClientConn.NewStream.
+type UpdateappClient interface {
+       // Sync
+       UpdateApp(ctx context.Context, in *UpdateAppRequest, opts ...grpc.CallOption) (*UpdateAppResponse, error)
+       RollbackApp(ctx context.Context, in *RollbackAppRequest, opts ...grpc.CallOption) (*RollbackAppResponse, error)
+}
+
+type updateappClient struct {
+       cc grpc.ClientConnInterface
+}
+
+func NewUpdateappClient(cc grpc.ClientConnInterface) UpdateappClient {
+       return &updateappClient{cc}
+}
+
+func (c *updateappClient) UpdateApp(ctx context.Context, in *UpdateAppRequest, opts ...grpc.CallOption) (*UpdateAppResponse, error) {
+       out := new(UpdateAppResponse)
+       err := c.cc.Invoke(ctx, "/updateapp/UpdateApp", in, out, opts...)
+       if err != nil {
+               return nil, err
+       }
+       return out, nil
+}
+
+func (c *updateappClient) RollbackApp(ctx context.Context, in *RollbackAppRequest, opts ...grpc.CallOption) (*RollbackAppResponse, error) {
+       out := new(RollbackAppResponse)
+       err := c.cc.Invoke(ctx, "/updateapp/RollbackApp", in, out, opts...)
+       if err != nil {
+               return nil, err
+       }
+       return out, nil
+}
+
+// UpdateappServer is the server API for Updateapp service.
+type UpdateappServer interface {
+       // Sync
+       UpdateApp(context.Context, *UpdateAppRequest) (*UpdateAppResponse, error)
+       RollbackApp(context.Context, *RollbackAppRequest) (*RollbackAppResponse, error)
+}
+
+// UnimplementedUpdateappServer can be embedded to have forward compatible implementations.
+type UnimplementedUpdateappServer struct {
+}
+
+func (*UnimplementedUpdateappServer) UpdateApp(context.Context, *UpdateAppRequest) (*UpdateAppResponse, error) {
+       return nil, status.Errorf(codes.Unimplemented, "method UpdateApp not implemented")
+}
+func (*UnimplementedUpdateappServer) RollbackApp(context.Context, *RollbackAppRequest) (*RollbackAppResponse, error) {
+       return nil, status.Errorf(codes.Unimplemented, "method RollbackApp not implemented")
+}
+
+func RegisterUpdateappServer(s *grpc.Server, srv UpdateappServer) {
+       s.RegisterService(&_Updateapp_serviceDesc, srv)
+}
+
+func _Updateapp_UpdateApp_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
+       in := new(UpdateAppRequest)
+       if err := dec(in); err != nil {
+               return nil, err
+       }
+       if interceptor == nil {
+               return srv.(UpdateappServer).UpdateApp(ctx, in)
+       }
+       info := &grpc.UnaryServerInfo{
+               Server:     srv,
+               FullMethod: "/updateapp/UpdateApp",
+       }
+       handler := func(ctx context.Context, req interface{}) (interface{}, error) {
+               return srv.(UpdateappServer).UpdateApp(ctx, req.(*UpdateAppRequest))
+       }
+       return interceptor(ctx, in, info, handler)
+}
+
+func _Updateapp_RollbackApp_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
+       in := new(RollbackAppRequest)
+       if err := dec(in); err != nil {
+               return nil, err
+       }
+       if interceptor == nil {
+               return srv.(UpdateappServer).RollbackApp(ctx, in)
+       }
+       info := &grpc.UnaryServerInfo{
+               Server:     srv,
+               FullMethod: "/updateapp/RollbackApp",
+       }
+       handler := func(ctx context.Context, req interface{}) (interface{}, error) {
+               return srv.(UpdateappServer).RollbackApp(ctx, req.(*RollbackAppRequest))
+       }
+       return interceptor(ctx, in, info, handler)
+}
+
+var _Updateapp_serviceDesc = grpc.ServiceDesc{
+       ServiceName: "updateapp",
+       HandlerType: (*UpdateappServer)(nil),
+       Methods: []grpc.MethodDesc{
+               {
+                       MethodName: "UpdateApp",
+                       Handler:    _Updateapp_UpdateApp_Handler,
+               },
+               {
+                       MethodName: "RollbackApp",
+                       Handler:    _Updateapp_RollbackApp_Handler,
+               },
+       },
+       Streams:  []grpc.StreamDesc{},
+       Metadata: "updateapp.proto",
+}
diff --git a/central-controller/src/rsync/pkg/grpc/updateapp/updateapp.proto b/central-controller/src/rsync/pkg/grpc/updateapp/updateapp.proto
new file mode 100644 (file)
index 0000000..bbe3f93
--- /dev/null
@@ -0,0 +1,34 @@
+// SPDX-License-Identifier: Apache-2.0
+// Copyright (c) 2020 Intel Corporation
+
+syntax = "proto3";
+
+service updateapp {
+    // Sync
+    rpc UpdateApp(UpdateAppRequest) returns (UpdateAppResponse) {
+    }
+
+    rpc RollbackApp(RollbackAppRequest) returns (RollbackAppResponse) {
+    }
+
+}
+
+message UpdateAppRequest {
+    string update_from_appContext = 1;
+    string update_to_appContext = 2;
+}
+
+message UpdateAppResponse {
+    bool app_context_updated = 1;
+    string app_context_update_message = 2;
+}
+
+message RollbackAppRequest {
+    string rollback_from_appContext = 1;
+    string rollback_to_appContext = 2;
+}
+
+message RollbackAppResponse {
+    bool app_context_rolledback = 1;
+    string app_context_rollback_message = 2;
+}
\ No newline at end of file
diff --git a/central-controller/src/rsync/pkg/grpc/updateappserver/updateappserver.go b/central-controller/src/rsync/pkg/grpc/updateappserver/updateappserver.go
new file mode 100644 (file)
index 0000000..a9477cb
--- /dev/null
@@ -0,0 +1,51 @@
+// SPDX-License-Identifier: Apache-2.0
+// Copyright (c) 2021 Intel Corporation
+
+package updateappserver
+
+import (
+       "context"
+       "encoding/json"
+       "log"
+
+       con "gitlab.com/project-emco/core/emco-base/src/rsync/pkg/context"
+       "gitlab.com/project-emco/core/emco-base/src/rsync/pkg/grpc/updateapp"
+)
+
+type updateappServer struct {
+       updateapp.UnimplementedUpdateappServer
+}
+
+func (cs *updateappServer) UpdateApp(ctx context.Context, req *updateapp.UpdateAppRequest) (*updateapp.UpdateAppResponse, error) {
+       updateAppReq, _ := json.Marshal(req)
+       log.Println("GRPC Server received UpdateAppRequest: ", string(updateAppReq))
+
+       // Try updating the comp app
+       instca := con.CompositeAppContext{}
+       err := instca.UpdateComApp(req.GetUpdateFromAppContext(), req.GetUpdateToAppContext())
+       if err != nil {
+               log.Println("Updating the compApp failed: " + err.Error())
+               return &updateapp.UpdateAppResponse{AppContextUpdated: false}, err
+       }
+       return &updateapp.UpdateAppResponse{AppContextUpdated: true}, nil
+}
+
+func (cs *updateappServer) RollbackApp(ctx context.Context, req *updateapp.RollbackAppRequest) (*updateapp.RollbackAppResponse, error) {
+       updateAppReq, _ := json.Marshal(req)
+       log.Println("GRPC Server received UpdateAppRequest: ", string(updateAppReq))
+
+       // Try rollback for the comp app
+       instca := con.CompositeAppContext{}
+       err := instca.UpdateComApp(req.GetRollbackFromAppContext(), req.GetRollbackToAppContext())
+       if err != nil {
+               log.Println("Rollback for compApp failed: " + err.Error())
+               return &updateapp.RollbackAppResponse{AppContextRolledback: false}, err
+       }
+       return &updateapp.RollbackAppResponse{AppContextRolledback: true}, nil
+}
+
+// NewInstallAppServer exported
+func NewUpdateAppServer() *updateappServer {
+       s := &updateappServer{}
+       return s
+}
diff --git a/central-controller/src/rsync/pkg/internal/utils.go b/central-controller/src/rsync/pkg/internal/utils.go
deleted file mode 100644 (file)
index 0317c7e..0000000
+++ /dev/null
@@ -1,102 +0,0 @@
-// SPDX-License-Identifier: Apache-2.0
-// Copyright (c) 2020 Intel Corporation
-
-package utils
-
-import (
-       "io/ioutil"
-       "log"
-       "os"
-       "path"
-
-       corev1 "k8s.io/api/core/v1"
-
-       pkgerrors "github.com/pkg/errors"
-       "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
-       "k8s.io/apimachinery/pkg/runtime"
-       "k8s.io/client-go/kubernetes/scheme"
-)
-
-// DecodeYAMLFile reads a YAMl file to extract the Kubernetes object definition
-func DecodeYAMLFile(path string, into runtime.Object) (runtime.Object, error) {
-       if _, err := os.Stat(path); err != nil {
-               if os.IsNotExist(err) {
-                       return nil, pkgerrors.New("File " + path + " not found")
-               } else {
-                       return nil, pkgerrors.Wrap(err, "Stat file error")
-               }
-       }
-
-       rawBytes, err := ioutil.ReadFile(path)
-       if err != nil {
-               return nil, pkgerrors.Wrap(err, "Read YAML file error")
-       }
-
-       decode := scheme.Codecs.UniversalDeserializer().Decode
-       obj, _, err := decode(rawBytes, nil, into)
-       if err != nil {
-               return nil, pkgerrors.Wrap(err, "Deserialize YAML error")
-       }
-
-       return obj, nil
-}
-
-// DecodeYAMLData reads a string to extract the Kubernetes object definition
-func DecodeYAMLData(data string, into runtime.Object) (runtime.Object, error) {
-       decode := scheme.Codecs.UniversalDeserializer().Decode
-       obj, _, err := decode([]byte(data), nil, into)
-       if err != nil {
-               return nil, pkgerrors.Wrap(err, "Deserialize YAML error")
-       }
-
-       return obj, nil
-}
-
-//EnsureDirectory makes sure that the directories specified in the path exist
-//If not, it will create them, if possible.
-func EnsureDirectory(f string) error {
-       base := path.Dir(f)
-       _, err := os.Stat(base)
-       if err != nil && !os.IsNotExist(err) {
-               return err
-       }
-       return os.MkdirAll(base, 0700)
-}
-
-// TagPodsIfPresent finds the PodTemplateSpec from any workload
-// object that contains it and changes the spec to include the tag label
-func TagPodsIfPresent(unstruct *unstructured.Unstructured, tag string) {
-
-       spec, ok := unstruct.Object["spec"].(map[string]interface{})
-       if !ok {
-               log.Println("Error converting spec to map")
-               return
-       }
-
-       template, ok := spec["template"].(map[string]interface{})
-       if !ok {
-               //log.Println("Error converting template to map")
-               return
-       }
-       log.Println("Apply label in template")
-       //Attempt to convert the template to a podtemplatespec.
-       //This is to check if we have any pods being created.
-       podTemplateSpec := &corev1.PodTemplateSpec{}
-       err := runtime.DefaultUnstructuredConverter.FromUnstructured(template, podTemplateSpec)
-       if err != nil {
-               log.Println("Did not find a podTemplateSpec: " + err.Error())
-               return
-       }
-
-       labels := podTemplateSpec.GetLabels()
-       if labels == nil {
-               labels = map[string]string{}
-       }
-       labels["emco/deployment-id"] = tag
-       podTemplateSpec.SetLabels(labels)
-
-       updatedTemplate, err := runtime.DefaultUnstructuredConverter.ToUnstructured(podTemplateSpec)
-
-       //Set the label
-       spec["template"] = updatedTemplate
-}
diff --git a/central-controller/src/rsync/pkg/internal/utils/acutils.go b/central-controller/src/rsync/pkg/internal/utils/acutils.go
new file mode 100644 (file)
index 0000000..ae3175e
--- /dev/null
@@ -0,0 +1,437 @@
+// SPDX-License-Identifier: Apache-2.0
+// Copyright (c) 2020 Intel Corporation
+
+package utils
+
+import (
+       "encoding/json"
+       "fmt"
+       "strings"
+
+       pkgerrors "github.com/pkg/errors"
+       "gitlab.com/project-emco/core/emco-base/src/orchestrator/pkg/appcontext"
+       log "gitlab.com/project-emco/core/emco-base/src/orchestrator/pkg/infra/logutils"
+       "gitlab.com/project-emco/core/emco-base/src/orchestrator/pkg/resourcestatus"
+)
+
+type AppContextReference struct {
+       acID string
+       ac   appcontext.AppContext
+}
+
+func NewAppContextReference(acID string) (AppContextReference, error) {
+       ac := appcontext.AppContext{}
+       if len(acID) == 0 {
+               log.Error("Error loading AppContext - appContexID is nil", log.Fields{})
+               return AppContextReference{}, pkgerrors.Errorf("appContexID is nil")
+       }
+       _, err := ac.LoadAppContext(acID)
+       if err != nil {
+               log.Error("Error loading AppContext", log.Fields{"err": err, "acID": acID})
+               return AppContextReference{}, err
+       }
+       return AppContextReference{ac: ac, acID: acID}, nil
+}
+func (a *AppContextReference) GetAppContextHandle() appcontext.AppContext {
+       return a.ac
+}
+
+//GetAppContextFlag gets the stop flag
+func (a *AppContextReference) GetAppContextFlag(key string) (bool, error) {
+       h, err := a.ac.GetCompositeAppHandle()
+       if err != nil {
+               // Treat an error as stop
+               return true, err
+       }
+       sh, err := a.ac.GetLevelHandle(h, key)
+       if sh != nil {
+               if v, err := a.ac.GetValue(sh); err == nil {
+                       return v.(bool), nil
+               }
+       }
+       return true, err
+}
+
+//UpdateAppContextFlag to update flags
+func (a *AppContextReference) UpdateAppContextFlag(key string, b bool) error {
+       h, err := a.ac.GetCompositeAppHandle()
+       if err != nil {
+               log.Error("Error UpdateAppContextFlag", log.Fields{"err": err})
+               return err
+       }
+       sh, err := a.ac.GetLevelHandle(h, key)
+       if sh == nil {
+               _, err = a.ac.AddLevelValue(h, key, b)
+       } else {
+               err = a.ac.UpdateValue(sh, b)
+       }
+       if err != nil {
+               log.Error("Error UpdateAppContextFlag", log.Fields{"err": err})
+       }
+       return err
+
+}
+
+//UpdateAppContextStatus updates a field in AppContext
+func (a *AppContextReference) UpdateAppContextStatus(key string, status interface{}) error {
+       //var acStatus appcontext.AppContextStatus = appcontext.AppContextStatus{}
+       hc, err := a.ac.GetCompositeAppHandle()
+       if err != nil {
+               log.Error("Error UpdateAppContextStatus", log.Fields{"err": err})
+               return err
+       }
+       dsh, err := a.ac.GetLevelHandle(hc, key)
+       if dsh == nil {
+               _, err = a.ac.AddLevelValue(hc, key, status)
+       } else {
+               err = a.ac.UpdateValue(dsh, status)
+       }
+       if err != nil {
+               log.Error("Error UpdateAppContextStatus", log.Fields{"err": err})
+       }
+       return err
+
+}
+
+//GetAppContextStatus gets the status
+func (a *AppContextReference) GetAppContextStatus(key string) (appcontext.AppContextStatus, error) {
+       var acStatus appcontext.AppContextStatus = appcontext.AppContextStatus{}
+
+       hc, err := a.ac.GetCompositeAppHandle()
+       if err != nil {
+               log.Error("Error GetAppContextStatus", log.Fields{"err": err})
+               return acStatus, err
+       }
+       dsh, err := a.ac.GetLevelHandle(hc, key)
+       if dsh != nil {
+               v, err := a.ac.GetValue(dsh)
+               if err != nil {
+                       log.Error("Error GetAppContextStatus", log.Fields{"err": err})
+                       return acStatus, err
+               }
+               //s := fmt.Sprintf("%v", v)
+               //acStatus.Status = appcontext.StatusValue(s)
+               acStatus = appcontext.AppContextStatus{}
+               js, err := json.Marshal(v)
+               if err != nil {
+                       log.Error("Error GetAppContextStatus", log.Fields{"err": err})
+                       return acStatus, err
+               }
+               err = json.Unmarshal(js, &acStatus)
+               if err != nil {
+                       log.Error("Error GetAppContextStatus", log.Fields{"err": err})
+                       return acStatus, err
+               }
+       }
+       return acStatus, err
+}
+
+// SetClusterAvailableStatus sets the cluster available status
+func (a *AppContextReference) SetClusterAvailableStatus(app, cluster string, status appcontext.StatusValue) {
+       ch, err := a.ac.GetClusterHandle(app, cluster)
+       if err != nil {
+               return
+       }
+       rsh, _ := a.ac.GetLevelHandle(ch, "readystatus")
+       // If readystatus handle was not found, then create it
+       if rsh == nil {
+               a.ac.AddLevelValue(ch, "readystatus", status)
+       } else {
+               a.ac.UpdateStatusValue(rsh, status)
+       }
+}
+
+// GetClusterAvailableStatus sets the cluster ready status
+// does not return an error, just a status of Unknown if the cluster readystatus key does
+// not exist or any other error occurs.
+func (a *AppContextReference) GetClusterAvailableStatus(app, cluster string) appcontext.StatusValue {
+       ch, err := a.ac.GetClusterHandle(app, cluster)
+       if err != nil {
+               return appcontext.ClusterReadyStatusEnum.Unknown
+       }
+       rsh, _ := a.ac.GetLevelHandle(ch, "readystatus")
+       if rsh != nil {
+               status, err := a.ac.GetValue(rsh)
+               if err != nil {
+                       return appcontext.ClusterReadyStatusEnum.Unknown
+               }
+               return status.(appcontext.StatusValue)
+       }
+
+       return appcontext.ClusterReadyStatusEnum.Unknown
+}
+
+// GetRes Reads resource
+func (a *AppContextReference) GetRes(name string, app string, cluster string) ([]byte, interface{}, error) {
+       var byteRes []byte
+
+       rh, err := a.ac.GetResourceHandle(app, cluster, name)
+       if err != nil {
+               log.Error("Error GetRes", log.Fields{"err": err})
+               return nil, nil, err
+       }
+       sh, err := a.ac.GetLevelHandle(rh, "status")
+       if err != nil {
+               statusPending := resourcestatus.ResourceStatus{
+                       Status: resourcestatus.RsyncStatusEnum.Pending,
+               }
+               sh, err = a.ac.AddLevelValue(rh, "status", statusPending)
+               if err != nil {
+                       log.Error("Error GetRes", log.Fields{"err": err})
+                       return nil, nil, err
+               }
+       }
+       resval, err := a.ac.GetValue(rh)
+       if err != nil {
+               log.Error("Error GetRes", log.Fields{"err": err})
+               return nil, sh, err
+       }
+       if resval != "" {
+               result := strings.Split(name, "+")
+               if result[0] == "" {
+                       log.Error("Error GetRes, Resource name is nil", log.Fields{})
+                       return nil, sh, pkgerrors.Errorf("Resource name is nil %s:", name)
+               }
+               byteRes = []byte(fmt.Sprintf("%v", resval.(interface{})))
+       } else {
+               log.Error("Error GetRes, Resource name is nil", log.Fields{})
+               return nil, sh, pkgerrors.Errorf("Resource value is nil %s", name)
+       }
+       return byteRes, sh, nil
+}
+
+//GetNamespace reads namespace from metadata
+func (a *AppContextReference) GetNamespace() (string, string) {
+
+       namespace := "default"
+       level := "0"
+       appmeta, err := a.ac.GetCompositeAppMeta()
+       if err == nil {
+               namespace = appmeta.Namespace
+               level = appmeta.Level
+       }
+       log.Info("CloudConfig for this app will be looked up using level and namespace specified", log.Fields{
+               "level":     level,
+               "namespace": namespace,
+       })
+       return namespace, level
+}
+
+// PutRes copies resource into appContext
+func (a *AppContextReference) PutRes(name string, app string, cluster string, data []byte) error {
+
+       rh, err := a.ac.GetResourceHandle(app, cluster, name)
+       if err != nil {
+               log.Error("Error GetResourceHandle", log.Fields{"err": err})
+               return err
+       }
+       handle, _ := a.ac.GetLevelHandle(rh, "definition")
+       // If definition handle was not found, then create it
+       if handle == nil {
+               a.ac.AddLevelValue(rh, "definition", string(data))
+       } else {
+               a.ac.UpdateStatusValue(handle, string(data))
+       }
+       return nil
+}
+
+//GetAppContextFlag gets the statusappctxid
+func (a *AppContextReference) GetStatusAppContext(key string) (string, error) {
+       h, err := a.ac.GetCompositeAppHandle()
+       if err != nil {
+               log.Error("Error GetAppContextFlag", log.Fields{"err": err})
+               return "", err
+       }
+       sh, err := a.ac.GetLevelHandle(h, key)
+       if sh != nil {
+               if v, err := a.ac.GetValue(sh); err == nil {
+                       return v.(string), nil
+               }
+       }
+       return "", err
+}
+
+// Add resource level for a status
+// Function adds any missing levels to AppContext
+func (a *AppContextReference) AddResourceStatus(name string, app string, cluster string, status interface{}, acID string) error {
+       var rh, ch, ah interface{}
+
+       rh, err := a.ac.GetResourceHandle(app, cluster, name)
+       if err != nil {
+               // Assume the resource doesn't exist
+               h, err := a.ac.GetCompositeAppHandle()
+               if err != nil {
+                       log.Error("Composite App Handle not found", log.Fields{"err": err})
+                       return err
+               }
+               // Check if App exists if not add handle
+               ah, err = a.ac.GetAppHandle(app)
+               if err != nil {
+                       //Add App level
+                       ah, err = a.ac.AddApp(h, app)
+                       if err != nil {
+                               log.Error("Unable to add application to context for status", log.Fields{"err": err})
+                               return err
+                       }
+               }
+               ch, err = a.ac.GetClusterHandle(app, cluster)
+               if err != nil {
+                       ch, err = a.ac.AddCluster(ah, cluster)
+                       if err != nil {
+                               log.Error("Unable to add cluster to context for status", log.Fields{"err": err})
+                               return err
+                       }
+               }
+               rh, err = a.ac.AddResource(ch, name, "nil")
+               if err != nil {
+                       log.Error("Unable to add resource to context for status", log.Fields{"err": err})
+                       return err
+               }
+       }
+       sh, err := a.ac.GetLevelHandle(rh, "status")
+       if err != nil {
+               sh, err = a.ac.AddLevelValue(rh, "status", status)
+               if err != nil {
+                       log.Error("Error add status to resource", log.Fields{"err": err})
+                       return err
+               }
+       } else {
+               a.ac.UpdateStatusValue(sh, status)
+       }
+       // Create link to the original resource
+       link := acID
+       lh, err := a.ac.GetLevelHandle(rh, "reference")
+       if err != nil {
+               lh, err = a.ac.AddLevelValue(rh, "reference", link)
+               if err != nil {
+                       log.Error("Error add reference to resource for status", log.Fields{"err": err})
+                       return err
+               }
+       } else {
+               a.ac.UpdateStatusValue(lh, link)
+       }
+       // Create a link to new appContext at the cluster level also for readystatus
+       ch, err = a.ac.GetClusterHandle(app, cluster)
+       if err != nil {
+               return err
+       }
+       lch, err := a.ac.GetLevelHandle(ch, "reference")
+       if err != nil {
+               lch, err = a.ac.AddLevelValue(ch, "reference", link)
+               if err != nil {
+                       log.Error("Error add reference to resource for status", log.Fields{"err": err})
+                       return err
+               }
+       } else {
+               a.ac.UpdateStatusValue(lch, link)
+       }
+       return nil
+}
+
+// SetClusterResourceReady sets the cluster ready status
+func (a *AppContextReference) SetClusterResourcesReady(app, cluster string, value bool) error {
+
+       ch, err := a.ac.GetClusterHandle(app, cluster)
+       if err != nil {
+               return err
+       }
+       rsh, _ := a.ac.GetLevelHandle(ch, "resourcesready")
+       // If resource ready handle was not found, then create it
+       if rsh == nil {
+               a.ac.AddLevelValue(ch, "resourcesready", value)
+       } else {
+               a.ac.UpdateStatusValue(rsh, value)
+       }
+       return nil
+}
+
+// GetClusterResourceReady gets the cluster ready status
+func (a *AppContextReference) GetClusterResourcesReady(app, cluster string) bool {
+       ch, err := a.ac.GetClusterHandle(app, cluster)
+       if err != nil {
+               return false
+       }
+       rsh, _ := a.ac.GetLevelHandle(ch, "resourcesready")
+       if rsh != nil {
+               status, err := a.ac.GetValue(rsh)
+               if err != nil {
+                       return false
+               }
+               return status.(bool)
+       }
+       return false
+}
+
+// SetResourceReadyStatus sets the resource ready status
+func (a *AppContextReference) SetResourceReadyStatus(app, cluster, res string, readyType string, value bool) error {
+       rh, err := a.ac.GetResourceHandle(app, cluster, res)
+       if err != nil {
+               return err
+       }
+       rsh, _ := a.ac.GetLevelHandle(rh, string(readyType))
+       // If resource ready handle was not found, then create it
+       if rsh == nil {
+               a.ac.AddLevelValue(rh, string(readyType), value)
+       } else {
+               a.ac.UpdateStatusValue(rsh, value)
+       }
+       return nil
+}
+
+// GetClusterResourceReady gets the resources ready status
+func (a *AppContextReference) GetResourceReadyStatus(app, cluster, res string, readyType string) bool {
+       rh, err := a.ac.GetResourceHandle(app, cluster, res)
+       if err != nil {
+               return false
+       }
+       rsh, _ := a.ac.GetLevelHandle(rh, string(readyType))
+       if rsh != nil {
+               status, err := a.ac.GetValue(rsh)
+               if err != nil {
+                       return false
+               }
+               return status.(bool)
+       }
+       return false
+}
+
+// CheckAppReadyOnAllClusters checks if App is ready on all clusters
+func (a *AppContextReference) CheckAppReadyOnAllClusters(app string) bool {
+       // Check if all the clusters are ready
+       cl, err := a.ac.GetClusterNames(app)
+       if err != nil {
+               return false
+       }
+       for _, cn := range cl {
+               if !a.GetClusterResourcesReady(app, cn) {
+                       // Some cluster is not ready
+                       return false
+               }
+       }
+       return true
+}
+
+func (a *AppContextReference) GetSubResApprove(name, app, cluster string) ([]byte, interface{}, error) {
+       var byteRes []byte
+
+       rh, err := a.ac.GetResourceHandle(app, cluster, name)
+       if err != nil {
+               return nil, nil, err
+       }
+       // Check if Subresource defined
+       sh, err := a.ac.GetLevelHandle(rh, "subresource/approval")
+       if err != nil {
+               return nil, nil, err
+       }
+       resval, err := a.ac.GetValue(sh)
+       if err != nil {
+               return nil, sh, err
+       }
+       if resval != "" {
+               byteRes = []byte(fmt.Sprintf("%v", resval.(interface{})))
+       } else {
+               log.Error("Error GetSubResApprove, Resource name is nil", log.Fields{})
+               return nil, sh, pkgerrors.Errorf("SubResource value is nil %s", name)
+       }
+       return byteRes, sh, nil
+}
diff --git a/central-controller/src/rsync/pkg/internal/utils/helpers.go b/central-controller/src/rsync/pkg/internal/utils/helpers.go
new file mode 100644 (file)
index 0000000..6c05706
--- /dev/null
@@ -0,0 +1,73 @@
+// SPDX-License-Identifier: Apache-2.0
+// Copyright (c) 2020 Intel Corporation
+
+package utils
+
+import (
+       "encoding/base64"
+       pkgerrors "github.com/pkg/errors"
+       log "gitlab.com/project-emco/core/emco-base/src/orchestrator/pkg/infra/logutils"
+       mtypes "gitlab.com/project-emco/core/emco-base/src/orchestrator/pkg/module/types"
+       "gitlab.com/project-emco/core/emco-base/src/rsync/pkg/db"
+       "k8s.io/apimachinery/pkg/runtime"
+       "k8s.io/client-go/kubernetes/scheme"
+       "strings"
+       //emcoutils "gitlab.com/project-emco/core/emco-base/src/orchestrator/pkg/infra/utils"
+)
+
+// DecodeYAMLData reads a string to extract the Kubernetes object definition
+func DecodeYAMLData(data string, into runtime.Object) (runtime.Object, error) {
+       decode := scheme.Codecs.UniversalDeserializer().Decode
+       obj, _, err := decode([]byte(data), nil, into)
+       if err != nil {
+               log.Error("Error DecodeYAMLData", log.Fields{"error": err})
+               return nil, pkgerrors.Wrap(err, "Deserialize YAML error")
+       }
+
+       return obj, nil
+}
+
+// GetKubeConfig uses the connectivity client to get the kubeconfig based on the name
+// of the clustername.
+var GetKubeConfig = func(clustername string, level string, namespace string) ([]byte, error) {
+       if !strings.Contains(clustername, "+") {
+               return nil, pkgerrors.New("Not a valid cluster name")
+       }
+       strs := strings.Split(clustername, "+")
+       if len(strs) != 2 {
+               return nil, pkgerrors.New("Not a valid cluster name")
+       }
+
+       ccc := db.NewCloudConfigClient()
+
+       log.Info("Querying CloudConfig", log.Fields{"strs": strs, "level": level, "namespace": namespace})
+       cconfig, err := ccc.GetCloudConfig(strs[0], strs[1], level, namespace)
+       if err != nil {
+               return nil, pkgerrors.New("Get kubeconfig failed")
+       }
+       log.Info("Successfully looked up CloudConfig", log.Fields{".Provider": cconfig.Provider, ".Cluster": cconfig.Cluster, ".Level": cconfig.Level, ".Namespace": cconfig.Namespace})
+
+       dec, err := base64.StdEncoding.DecodeString(cconfig.Config)
+       if err != nil {
+               return nil, err
+       }
+
+       return dec, nil
+}
+
+var GetGitOpsConfig = func(clustername string, level string, namespace string) (mtypes.GitOpsSpec, error) {
+       if !strings.Contains(clustername, "+") {
+               return mtypes.GitOpsSpec{}, pkgerrors.New("Not a valid cluster name")
+       }
+       strs := strings.Split(clustername, "+")
+       if len(strs) != 2 {
+               return mtypes.GitOpsSpec{}, pkgerrors.New("Not a valid cluster name")
+       }
+       ccc := db.NewCloudConfigClient()
+
+       cfg, err := ccc.GetGitOpsConfig(strs[0], strs[1], level, namespace)
+       if err != nil {
+               return mtypes.GitOpsSpec{}, err
+       }
+       return cfg.Config, nil
+}
diff --git a/central-controller/src/rsync/pkg/plugins/azurearc/config.go b/central-controller/src/rsync/pkg/plugins/azurearc/config.go
new file mode 100644 (file)
index 0000000..4edc8ee
--- /dev/null
@@ -0,0 +1,325 @@
+// SPDX-License-Identifier: Apache-2.0
+// Copyright (c) 2022 Intel Corporation
+
+package azurearc
+
+import (
+       "bytes"
+       "context"
+       "encoding/json"
+       "io/ioutil"
+       "net/http"
+       "net/url"
+       "time"
+
+       "github.com/fluxcd/go-git-providers/gitprovider"
+       log "gitlab.com/project-emco/core/emco-base/src/orchestrator/pkg/infra/logutils"
+       emcogit "gitlab.com/project-emco/core/emco-base/src/rsync/pkg/gitops/emcogit"
+)
+
+const subscriptionURL = "https://management.azure.com/subscriptions/"
+const azureCoreURL = "https://management.core.windows.net/"
+const azureLoginURL = "https://login.microsoftonline.com/"
+
+type Token struct {
+       TokenType    string `json:"token_type"`
+       ExpiresIn    string `json:"expires_in"`
+       ExtExpiresIn string `json:"ext_expires_in"`
+       ExpiresOn    string `json:"expires_on"`
+       NotBefore    string `json:"not_before"`
+       Resource     string `json:"resource"`
+       AccessToken  string `json:"access_token"`
+}
+
+type Properties struct {
+       RepositoryUrl         string `json:"repositoryUrl"`
+       OperatorNamespace     string `json:"operatorNamespace"`
+       OperatorInstanceName  string `json:"operatorInstanceName"`
+       OperatorType          string `json:"operatorType"`
+       OperatorParams        string `json:"operatorParams"`
+       OperatorScope         string `json:"operatorScope"`
+       SshKnownHostsContents string `json:"sshKnownHostsContents"`
+}
+
+type Requestbody struct {
+       Properties Properties `json:"properties"`
+}
+
+/*
+       Function to get the access token for azure arc
+       params: clientId, ClientSecret, tenantIdValue
+       return: Token, error
+*/
+func (p *AzureArcProvider) getAccessToken(clientId string, clientSecret string, tenantIdValue string) (string, error) {
+
+       client := http.Client{}
+
+       data := url.Values{}
+       data.Set("grant_type", "client_credentials")
+       data.Add("client_id", clientId)
+       data.Add("resource", azureCoreURL)
+       data.Add("client_secret", clientSecret)
+
+       urlPost := azureLoginURL + tenantIdValue + "/oauth2/token"
+
+       //Rest api to get the access token
+       req, err := http.NewRequest("POST", urlPost, bytes.NewBufferString(data.Encode()))
+       if err != nil {
+               //Handle Error
+               log.Error("Couldn't create Azure Access Token request", log.Fields{"err": err, "req": req})
+               return "", err
+       }
+
+       req.Header.Set("Content-Type", "application/x-www-form-urlencoded; param=value")
+
+       res, err := client.Do(req)
+       if err != nil {
+               log.Error(" Azure Access Token response error", log.Fields{"err": err, "res": res})
+               return "", err
+       }
+
+       responseData, err := ioutil.ReadAll(res.Body)
+       if err != nil {
+               log.Error(" Azure Access Token response marshall error", log.Fields{"err": err, "responseData": responseData})
+               return "", err
+       }
+
+       // Unmarshall the response body into json and get token value
+       newToken := Token{}
+       json.Unmarshal(responseData, &newToken)
+
+       return newToken.AccessToken, nil
+}
+
+/*
+       Function to create a git configuration for the mentioned user repo
+       params: accessToken, repositoryUrl, gitConfiguration, operatorScopeType, subscriptionId, Arc Cluster ResourceGroup, Arc ClusterName
+                       git branch, git path
+       return: response, error
+*/
+func (p *AzureArcProvider) createGitConfiguration(accessToken string, repositoryUrl string, gitConfiguration string, operatorScopeType string, subscriptionIdValue string, arcClusterResourceGroupName string, arcClusterName string, gitbranch string, gitpath string) (string, error) {
+
+       // PUT request for creating git configuration
+       client := http.Client{}
+
+       flags := "--git-branch=" + gitbranch + " --git-poll-interval=1s --sync-garbage-collection --git-path=" + gitpath
+
+       // PUT request body
+       properties := Requestbody{
+               Properties{
+                       RepositoryUrl:         repositoryUrl,
+                       OperatorNamespace:     gitConfiguration,
+                       OperatorInstanceName:  gitConfiguration,
+                       OperatorType:          "flux",
+                       OperatorParams:        flags,
+                       OperatorScope:         operatorScopeType,
+                       SshKnownHostsContents: ""}}
+
+       dataProperties, err := json.Marshal(properties)
+       if err != nil {
+               log.Error(" Data properties marshall error", log.Fields{"err": err, "dataProperties": dataProperties})
+               return "", err
+       }
+
+       urlPut := subscriptionURL + subscriptionIdValue + "/resourceGroups/" + arcClusterResourceGroupName + "/providers/Microsoft.Kubernetes/connectedClusters/" + arcClusterName + "/providers/Microsoft.KubernetesConfiguration/sourceControlConfigurations/" + gitConfiguration + "?api-version=2021-03-01"
+
+       reqPut, err := http.NewRequest(http.MethodPut, urlPut, bytes.NewBuffer(dataProperties))
+       if err != nil {
+               //Handle Error
+               log.Error("Error in creating request for git configuration", log.Fields{"err": err})
+               return "", err
+       }
+       // Add request header
+       authorizationString := "Bearer " + accessToken
+       reqPut.Header.Set("Content-Type", "application/json; charset=UTF-8")
+       reqPut.Header.Add("Authorization", authorizationString)
+
+       resPut, err := client.Do(reqPut)
+       if err != nil {
+               //Handle Error
+               log.Error("Error in response from create git configuration", log.Fields{"err": err})
+               return "", err
+       }
+
+       responseDataPut, err := ioutil.ReadAll(resPut.Body)
+       if err != nil {
+               //Handle Error
+               log.Error("Error in parsing response from create git configuration", log.Fields{"err": err})
+               return "", err
+       }
+
+       log.Info("Response for GitConfiguration creation:", log.Fields{"ResponseData": string(responseDataPut)})
+       return string(responseDataPut), nil
+
+}
+
+/*
+       Function to add dummy file to prevent the path getting deleted
+       params : context
+       return : error
+*/
+func (p *AzureArcProvider) addDummyFile(ctx context.Context, gitBranch string) error {
+
+       c, err := emcogit.CreateClient(p.gitProvider.GitToken, p.gitProvider.GitType)
+
+       if err != nil {
+               log.Error("Error Creating emcogit client", log.Fields{"err": err})
+               return err
+       }
+       files := []gitprovider.CommitFile{}
+
+       path := "clusters/" + p.gitProvider.Cluster + "/context/" + p.gitProvider.Cid
+       files = emcogit.Add(path+"/DoNotDelete", "Dummy file", files, p.gitProvider.GitType).([]gitprovider.CommitFile)
+
+       err = emcogit.CommitFiles(ctx, c, p.gitProvider.UserName, p.gitProvider.RepoName, gitBranch, "New Commit", files, p.gitProvider.GitType)
+       if err != nil {
+               log.Error("Couldn't commit the file", log.Fields{"err": err})
+               return err
+       }
+
+       return nil
+}
+
+/*
+       Function to delete dummy file
+       params : context
+       return : error
+*/
+func (p *AzureArcProvider) deleteDummyFile(ctx context.Context, gitBranch string) error {
+
+       c, err := emcogit.CreateClient(p.gitProvider.GitToken, p.gitProvider.GitType)
+
+       if err != nil {
+               log.Error("Error Creating emcogit client", log.Fields{"err": err})
+               return err
+       }
+       files := []gitprovider.CommitFile{}
+
+       path := "clusters/" + p.gitProvider.Cluster + "/context/" + p.gitProvider.Cid
+       files = emcogit.Delete(path+"/DoNotDelete", files, p.gitProvider.GitType).([]gitprovider.CommitFile)
+
+       err = emcogit.CommitFiles(ctx, c, p.gitProvider.UserName, p.gitProvider.RepoName, gitBranch, "New Commit", files, p.gitProvider.GitType)
+       if err != nil {
+               log.Error("Couldn't commit the file", log.Fields{"err": err})
+               return err
+       }
+
+       return nil
+}
+
+/*
+       Function to Delete Git configuration
+       params : Access Token, Subscription Id, Arc Cluster ResourceName, Arc Cluster Name, Flux Configuration name
+       return : Response, error
+
+*/
+func (p *AzureArcProvider) deleteGitConfiguration(accessToken string, subscriptionIdValue string, arcClusterResourceGroupName string, arcClusterName string, gitConfiguration string) (string, error) {
+
+       // Create client
+       client := &http.Client{}
+       // Create request
+       urlDelete := subscriptionURL + subscriptionIdValue + "/resourceGroups/" + arcClusterResourceGroupName + "/providers/Microsoft.Kubernetes/connectedClusters/" + arcClusterName + "/providers/Microsoft.KubernetesConfiguration/sourceControlConfigurations/" + gitConfiguration + "?api-version=2021-03-01"
+
+       reqDelete, err := http.NewRequest("DELETE", urlDelete, nil)
+       if err != nil {
+               //Handle Error
+               log.Error("Error in request of delete configuration", log.Fields{"Response": reqDelete, "err": err})
+               return "", err
+       }
+       // Add request header
+       authorizationString := "Bearer " + accessToken
+       reqDelete.Header.Set("Content-Type", "application/json; charset=UTF-8")
+       reqDelete.Header.Add("Authorization", authorizationString)
+
+       resPut, err := client.Do(reqDelete)
+       if err != nil {
+               //Handle Error
+               log.Error("Error in response of delete configuration", log.Fields{"Response": resPut, "err": err})
+               return "", err
+       }
+       responseDataPut, err := ioutil.ReadAll(resPut.Body)
+       if err != nil {
+               log.Error("Error in parsing response of delete configuration", log.Fields{"Response": responseDataPut, "err": err})
+               return "", err
+       }
+
+       return string(responseDataPut), nil
+}
+
+/*
+       Function to create gitconfiguration of fluxv1 type in azure
+       params : ctx context.Context, config interface{}
+       return : error
+*/
+func (p *AzureArcProvider) ApplyConfig(ctx context.Context, config interface{}) error {
+
+       //Add dummy file to git
+       resp := p.addDummyFile(ctx, p.gitProvider.Branch)
+       if resp != nil {
+               log.Error("Couldn't add dummy file", log.Fields{"err": resp})
+               return resp
+       }
+
+       //get accesstoken for azure
+       accessToken, err := p.getAccessToken(p.clientID, p.clientSecret, p.tenantID)
+
+       log.Info("Obtained AccessToken: ", log.Fields{"accessToken": accessToken})
+
+       if err != nil {
+               log.Error("Couldn't obtain access token", log.Fields{"err": err, "accessToken": accessToken})
+               return err
+       }
+
+       gitConfiguration := "config-" + p.gitProvider.Cid
+       operatorScope := "cluster"
+       gitPath := "clusters/" + p.gitProvider.Cluster + "/context/" + p.gitProvider.Cid
+       gitBranch := p.gitProvider.Branch
+
+       _, err = p.createGitConfiguration(accessToken, p.gitProvider.Url, gitConfiguration, operatorScope, p.subscriptionID,
+               p.arcResourceGroup, p.arcCluster, gitBranch, gitPath)
+
+       if err != nil {
+               log.Error("Error in creating git configuration", log.Fields{"err": err})
+               return err
+       }
+
+       return nil
+
+}
+
+/*
+       Function to delete the git configuration
+       params : ctx context.Context, config interface{}
+       return : error
+*/
+func (p *AzureArcProvider) DeleteConfig(ctx context.Context, config interface{}) error {
+
+       //get accesstoken for azure
+       accessToken, err := p.getAccessToken(p.clientID, p.clientSecret, p.tenantID)
+
+       if err != nil {
+               log.Error("Couldn't obtain access token", log.Fields{"err": err, "accessToken": accessToken})
+               return err
+       }
+
+       gitConfiguration := "config-" + p.gitProvider.Cid
+
+       // to allow enough time for the flux to delete deployments from azure arc
+       time.Sleep(time.Duration(p.configDeleteDelay) * time.Second)
+
+       _, err = p.deleteGitConfiguration(accessToken, p.subscriptionID, p.arcResourceGroup, p.arcCluster, gitConfiguration)
+
+       if err != nil {
+               log.Error("Error in deleting git configuration", log.Fields{"err": err})
+               return err
+       }
+
+       //Delete dummy file to git
+       resp := p.deleteDummyFile(ctx, p.gitProvider.Branch)
+       if resp != nil {
+               log.Error("Couldn't delete dummy file", log.Fields{"err": resp})
+               return resp
+       }
+
+       return nil
+}
diff --git a/central-controller/src/rsync/pkg/plugins/azurearc/k8s.go b/central-controller/src/rsync/pkg/plugins/azurearc/k8s.go
new file mode 100644 (file)
index 0000000..cc1af77
--- /dev/null
@@ -0,0 +1,130 @@
+// SPDX-License-Identifier: Apache-2.0
+// Copyright (c) 2022 Intel Corporation
+
+package azurearc
+
+import (
+       "fmt"
+       "strings"
+
+       pkgerrors "github.com/pkg/errors"
+       log "gitlab.com/project-emco/core/emco-base/src/orchestrator/pkg/infra/logutils"
+
+       "gitlab.com/project-emco/core/emco-base/src/rsync/pkg/db"
+       gitsupport "gitlab.com/project-emco/core/emco-base/src/rsync/pkg/gitops/gitsupport"
+       "gitlab.com/project-emco/core/emco-base/src/rsync/pkg/internal/utils"
+)
+
+type AzureArcProvider struct {
+       gitProvider       gitsupport.GitProvider
+       clientID          string
+       tenantID          string
+       clientSecret      string
+       subscriptionID    string
+       arcCluster        string
+       arcResourceGroup  string
+       configDeleteDelay int
+}
+
+func NewAzureArcProvider(cid, app, cluster, level, namespace string) (*AzureArcProvider, error) {
+
+       result := strings.SplitN(cluster, "+", 2)
+
+       c, err := utils.GetGitOpsConfig(cluster, level, namespace)
+
+       if err != nil {
+               return nil, err
+       }
+       if c.Props.GitOpsType != "azureArc" {
+               log.Error("Invalid GitOps type:", log.Fields{})
+               return nil, pkgerrors.Errorf("Invalid GitOps type: " + c.Props.GitOpsType)
+       }
+
+       // Read from database
+       ccc := db.NewCloudConfigClient()
+
+       gitProvider, err := gitsupport.NewGitProvider(cid, app, cluster, level, namespace)
+       if err != nil {
+               log.Error("Error creating git provider", log.Fields{"err": err, "gitProvider": gitProvider})
+               return nil, err
+       }
+
+       resObject, err := ccc.GetClusterSyncObjects(result[0], c.Props.GitOpsResourceObject)
+       if err != nil {
+               log.Error("Invalid resObject :", log.Fields{"resObj": c.Props.GitOpsResourceObject})
+               return nil, pkgerrors.Errorf("Invalid resObject: " + c.Props.GitOpsResourceObject)
+       }
+
+       kvRes := resObject.Spec.Kv
+
+       var clientID, tenantID, clientSecret, subscriptionID, arcCluster, arcResourceGroup, configDeleteDelayStr string
+
+       for _, kvpair := range kvRes {
+               log.Info("kvpair", log.Fields{"kvpair": kvpair})
+               v, ok := kvpair["clientID"]
+               if ok {
+                       clientID = fmt.Sprintf("%v", v)
+                       continue
+               }
+               v, ok = kvpair["tenantID"]
+               if ok {
+                       tenantID = fmt.Sprintf("%v", v)
+                       continue
+               }
+               v, ok = kvpair["clientSecret"]
+               if ok {
+                       clientSecret = fmt.Sprintf("%v", v)
+                       continue
+               }
+               v, ok = kvpair["subscriptionID"]
+               if ok {
+                       subscriptionID = fmt.Sprintf("%v", v)
+                       continue
+               }
+               v, ok = kvpair["arcCluster"]
+               if ok {
+                       arcCluster = fmt.Sprintf("%v", v)
+                       continue
+               }
+               v, ok = kvpair["arcResourceGroup"]
+               if ok {
+                       arcResourceGroup = fmt.Sprintf("%v", v)
+                       continue
+               }
+               v, ok = kvpair["configDeleteDelay"]
+               if ok {
+                       configDeleteDelayStr = fmt.Sprintf("%v", v)
+                       continue
+               }
+       }
+       if len(clientID) <= 0 || len(tenantID) <= 0 || len(clientSecret) <= 0 || len(subscriptionID) <= 0 || len(arcCluster) <= 0 || len(arcResourceGroup) <= 0 || len(configDeleteDelayStr) <= 0 {
+               log.Error("Missing information for Azure Arc", log.Fields{"clientID": clientID, "tenantID": tenantID, "clientSecret": clientSecret, "subscriptionID": subscriptionID,
+                       "arcCluster": arcCluster, "arcResourceGroup": arcResourceGroup, "configDeleteDelay": configDeleteDelayStr})
+               return nil, pkgerrors.Errorf("Missing Information for Azure Arc")
+       }
+
+       var configDeleteDelay int
+       _, err = fmt.Sscan(configDeleteDelayStr, &configDeleteDelay)
+
+       if err != nil {
+               log.Error("Invalid config delete delay", log.Fields{"configDeleteDelayStr": configDeleteDelayStr, "err": err})
+               return nil, err
+       }
+
+       p := AzureArcProvider{
+
+               gitProvider:       *gitProvider,
+               clientID:          clientID,
+               tenantID:          tenantID,
+               clientSecret:      clientSecret,
+               subscriptionID:    subscriptionID,
+               arcCluster:        arcCluster,
+               arcResourceGroup:  arcResourceGroup,
+               configDeleteDelay: configDeleteDelay,
+       }
+       return &p, nil
+}
+
+func (p *AzureArcProvider) CleanClientProvider() error {
+       return nil
+}
diff --git a/central-controller/src/rsync/pkg/plugins/azurearc/resources.go b/central-controller/src/rsync/pkg/plugins/azurearc/resources.go
new file mode 100644 (file)
index 0000000..c1ceb47
--- /dev/null
@@ -0,0 +1,59 @@
+// SPDX-License-Identifier: Apache-2.0
+// Copyright (c) 2022 Intel Corporation
+
+package azurearc
+
+import (
+       "context"
+
+       log "gitlab.com/project-emco/core/emco-base/src/orchestrator/pkg/infra/logutils"
+       "gitlab.com/project-emco/core/emco-base/src/rsync/pkg/status"
+)
+
+// Creates a new resource if the not already existing
+func (p *AzureArcProvider) Create(name string, ref interface{}, content []byte) (interface{}, error) {
+
+       res, err := p.gitProvider.Create(name, ref, content)
+       return res, err
+}
+
+// Apply resource to the cluster
+func (p *AzureArcProvider) Apply(name string, ref interface{}, content []byte) (interface{}, error) {
+
+       res, err := p.gitProvider.Apply(name, ref, content)
+       return res, err
+}
+
+// Delete resource from the cluster
+func (p *AzureArcProvider) Delete(name string, ref interface{}, content []byte) (interface{}, error) {
+
+       res, err := p.gitProvider.Delete(name, ref, content)
+       return res, err
+}
+
+// Get resource from the cluster
+func (p *AzureArcProvider) Get(name string, gvkRes []byte) ([]byte, error) {
+
+       return []byte{}, nil
+}
+
+// Commit resources to the cluster
+func (p *AzureArcProvider) Commit(ctx context.Context, ref interface{}) error {
+
+       err := p.gitProvider.Commit(ctx, ref)
+       return err
+}
+
+// IsReachable cluster reachablity test
+func (p *AzureArcProvider) IsReachable() error {
+       return nil
+}
+
+func (p *AzureArcProvider) TagResource(res []byte, label string) ([]byte, error) {
+       b, err := status.TagResource(res, label)
+       if err != nil {
+               log.Error("Error Tag Resoruce with label:", log.Fields{"err": err, "label": label, "resource": res})
+               return nil, err
+       }
+       return b, nil
+}
diff --git a/central-controller/src/rsync/pkg/plugins/azurearc/status.go b/central-controller/src/rsync/pkg/plugins/azurearc/status.go
new file mode 100644 (file)
index 0000000..37cd2ed
--- /dev/null
@@ -0,0 +1,23 @@
+// SPDX-License-Identifier: Apache-2.0
+// Copyright (c) 2022 Intel Corporation
+
+package azurearc
+
+// StartClusterWatcher watches for CR
+// Same as K8s
+func (c *AzureArcProvider) StartClusterWatcher() error {
+       return nil
+}
+
+// ApplyStatusCR applies status CR
+func (p *AzureArcProvider) ApplyStatusCR(name string, content []byte) error {
+
+       return nil
+
+}
+
+// DeleteStatusCR deletes status CR
+func (p *AzureArcProvider) DeleteStatusCR(name string, content []byte) error {
+
+       return nil
+}
diff --git a/central-controller/src/rsync/pkg/plugins/fluxv2/config.go b/central-controller/src/rsync/pkg/plugins/fluxv2/config.go
new file mode 100644 (file)
index 0000000..eae720d
--- /dev/null
@@ -0,0 +1,93 @@
+// SPDX-License-Identifier: Apache-2.0
+// Copyright (c) 2022 Intel Corporation
+
+package fluxv2
+
+import (
+       "context"
+       "time"
+
+       "github.com/fluxcd/go-git-providers/gitprovider"
+       kustomize "github.com/fluxcd/kustomize-controller/api/v1beta2"
+       fluxsc "github.com/fluxcd/source-controller/api/v1beta1"
+       yaml "github.com/ghodss/yaml"
+       log "gitlab.com/project-emco/core/emco-base/src/orchestrator/pkg/infra/logutils"
+       emcogit "gitlab.com/project-emco/core/emco-base/src/rsync/pkg/gitops/emcogit"
+       metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
+)
+
+// Create GitRepository and Kustomization CR's for Flux
+func (p *Fluxv2Provider) ApplyConfig(ctx context.Context, config interface{}) error {
+
+       // Create Source CR and Kcustomize CR
+       gr := fluxsc.GitRepository{
+               TypeMeta: metav1.TypeMeta{
+                       APIVersion: "source.toolkit.fluxcd.io/v1beta1",
+                       Kind:       "GitRepository",
+               },
+               ObjectMeta: metav1.ObjectMeta{
+                       Name:      p.gitProvider.Cid,
+                       Namespace: p.gitProvider.Namespace,
+               },
+               Spec: fluxsc.GitRepositorySpec{
+                       URL:       p.gitProvider.Url,
+                       Interval:  metav1.Duration{Duration: time.Second * 30},
+                       Reference: &fluxsc.GitRepositoryRef{Branch: p.gitProvider.Branch},
+               },
+       }
+       x, err := yaml.Marshal(&gr)
+       if err != nil {
+               log.Error("ApplyConfig:: Marshal err", log.Fields{"err": err, "gr": gr})
+               return err
+       }
+       path := "clusters/" + p.gitProvider.Cluster + "/" + gr.Name + ".yaml"
+       // Add to the commit
+       gp := emcogit.Add(path, string(x), []gitprovider.CommitFile{}, p.gitProvider.GitType)
+
+       kc := kustomize.Kustomization{
+               TypeMeta: metav1.TypeMeta{
+                       APIVersion: "kustomize.toolkit.fluxcd.io/v1beta2",
+                       Kind:       "Kustomization",
+               },
+               ObjectMeta: metav1.ObjectMeta{
+                       Name:      "kcust" + p.gitProvider.Cid,
+                       Namespace: p.gitProvider.Namespace,
+               },
+               Spec: kustomize.KustomizationSpec{
+                       Interval: metav1.Duration{Duration: time.Second * 300},
+                       Path:     "clusters/" + p.gitProvider.Cluster + "/context/" + p.gitProvider.Cid,
+                       Prune:    true,
+                       SourceRef: kustomize.CrossNamespaceSourceReference{
+                               Kind: "GitRepository",
+                               Name: gr.Name,
+                       },
+                       TargetNamespace: p.gitProvider.Namespace,
+               },
+       }
+       y, err := yaml.Marshal(&kc)
+       if err != nil {
+               log.Error("ApplyConfig:: Marshal err", log.Fields{"err": err, "kc": kc})
+               return err
+       }
+       path = "clusters/" + p.gitProvider.Cluster + "/" + kc.Name + ".yaml"
+       gp = emcogit.Add(path, string(y), gp, p.gitProvider.GitType)
+       // Commit
+       err = emcogit.CommitFiles(ctx, p.gitProvider.Client, p.gitProvider.UserName, p.gitProvider.RepoName, p.gitProvider.Branch, "Commit for "+p.gitProvider.GetPath("context"), gp, p.gitProvider.GitType)
+       if err != nil {
+               log.Error("ApplyConfig:: Commit files err", log.Fields{"err": err, "gp": gp})
+       }
+       return err
+}
+
+// Delete GitRepository and Kustomization CR's for Flux
+func (p *Fluxv2Provider) DeleteConfig(ctx context.Context, config interface{}) error {
+       path := "clusters/" + p.gitProvider.Cluster + "/" + p.gitProvider.Cid + ".yaml"
+       gp := emcogit.Delete(path, []gitprovider.CommitFile{}, p.gitProvider.GitType)
+       path = "clusters/" + p.gitProvider.Cluster + "/" + "kcust" + p.gitProvider.Cid + ".yaml"
+       gp = emcogit.Delete(path, gp, p.gitProvider.GitType)
+       err := emcogit.CommitFiles(ctx, p.gitProvider.Client, p.gitProvider.UserName, p.gitProvider.RepoName, p.gitProvider.Branch, "Commit for "+p.gitProvider.GetPath("context"), gp, p.gitProvider.GitType)
+       if err != nil {
+               log.Error("ApplyConfig:: Commit files err", log.Fields{"err": err, "gp": gp})
+       }
+       return err
+}
diff --git a/central-controller/src/rsync/pkg/plugins/fluxv2/k8s.go b/central-controller/src/rsync/pkg/plugins/fluxv2/k8s.go
new file mode 100644 (file)
index 0000000..fc4dc5e
--- /dev/null
@@ -0,0 +1,42 @@
+// SPDX-License-Identifier: Apache-2.0
+// Copyright (c) 2022 Intel Corporation
+
+package fluxv2
+
+import (
+       pkgerrors "github.com/pkg/errors"
+       log "gitlab.com/project-emco/core/emco-base/src/orchestrator/pkg/infra/logutils"
+
+       gitsupport "gitlab.com/project-emco/core/emco-base/src/rsync/pkg/gitops/gitsupport"
+       "gitlab.com/project-emco/core/emco-base/src/rsync/pkg/internal/utils"
+)
+
+// Connection is for a cluster
+type Fluxv2Provider struct {
+       gitProvider gitsupport.GitProvider
+}
+
+func NewFluxv2Provider(cid, app, cluster, level, namespace string) (*Fluxv2Provider, error) {
+
+       c, err := utils.GetGitOpsConfig(cluster, level, namespace)
+       if err != nil {
+               return nil, err
+       }
+       if c.Props.GitOpsType != "fluxcd" {
+               log.Error("Invalid GitOps type:", log.Fields{})
+               return nil, pkgerrors.Errorf("Invalid GitOps type: " + c.Props.GitOpsType)
+       }
+
+       gitProvider, err := gitsupport.NewGitProvider(cid, app, cluster, level, namespace)
+       if err != nil {
+               return nil, err
+       }
+       p := Fluxv2Provider{
+               gitProvider: *gitProvider,
+       }
+       return &p, nil
+}
+
+func (p *Fluxv2Provider) CleanClientProvider() error {
+       return nil
+}
diff --git a/central-controller/src/rsync/pkg/plugins/fluxv2/resources.go b/central-controller/src/rsync/pkg/plugins/fluxv2/resources.go
new file mode 100644 (file)
index 0000000..e653991
--- /dev/null
@@ -0,0 +1,76 @@
+// SPDX-License-Identifier: Apache-2.0
+// Copyright (c) 2022 Intel Corporation
+
+package fluxv2
+
+import (
+       "context"
+
+       log "gitlab.com/project-emco/core/emco-base/src/orchestrator/pkg/infra/logutils"
+       "gitlab.com/project-emco/core/emco-base/src/rsync/pkg/internal/utils"
+       "gitlab.com/project-emco/core/emco-base/src/rsync/pkg/status"
+       "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
+)
+
+// Creates a new resource if the not already existing
+func (p *Fluxv2Provider) Create(name string, ref interface{}, content []byte) (interface{}, error) {
+
+       res, err := p.gitProvider.Create(name, ref, content)
+       return res, err
+}
+
+// Apply resource to the cluster
+func (p *Fluxv2Provider) Apply(name string, ref interface{}, content []byte) (interface{}, error) {
+
+       //Decode the yaml to create a runtime.Object
+       unstruct := &unstructured.Unstructured{}
+       //Ignore the returned obj as we expect the data in unstruct
+       _, err := utils.DecodeYAMLData(string(content), unstruct)
+       if err != nil {
+               return nil, err
+       }
+       // Set Namespace
+       unstruct.SetNamespace(p.gitProvider.Namespace)
+       b, err := unstruct.MarshalJSON()
+       if err != nil {
+               return nil, err
+       }
+       res, err := p.gitProvider.Apply(name, ref, b)
+       return res, err
+
+}
+
+// Delete resource from the cluster
+func (p *Fluxv2Provider) Delete(name string, ref interface{}, content []byte) (interface{}, error) {
+
+       res, err := p.gitProvider.Delete(name, ref, content)
+       return res, err
+
+}
+
+// Get resource from the cluster
+func (p *Fluxv2Provider) Get(name string, gvkRes []byte) ([]byte, error) {
+
+       return []byte{}, nil
+}
+
+// Commit resources to the cluster
+func (p *Fluxv2Provider) Commit(ctx context.Context, ref interface{}) error {
+
+       err := p.gitProvider.Commit(ctx, ref)
+       return err
+}
+
+// IsReachable cluster reachablity test
+func (p *Fluxv2Provider) IsReachable() error {
+       return nil
+}
+
+func (m *Fluxv2Provider) TagResource(res []byte, label string) ([]byte, error) {
+       b, err := status.TagResource(res, label)
+       if err != nil {
+               log.Error("Error Tag Resoruce with label:", log.Fields{"err": err, "label": label, "resource": res})
+               return nil, err
+       }
+       return b, nil
+}
diff --git a/central-controller/src/rsync/pkg/plugins/fluxv2/status.go b/central-controller/src/rsync/pkg/plugins/fluxv2/status.go
new file mode 100644 (file)
index 0000000..a2f06d4
--- /dev/null
@@ -0,0 +1,53 @@
+// SPDX-License-Identifier: Apache-2.0
+// Copyright (c) 2022 Intel Corporation
+
+package fluxv2
+
+import (
+       "context"
+       "gitlab.com/project-emco/core/emco-base/src/rsync/pkg/internal/utils"
+       "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
+)
+
+// StartClusterWatcher watches for CR changes in git location
+func (p *Fluxv2Provider) StartClusterWatcher() error {
+       p.gitProvider.StartClusterWatcher()
+       return nil
+}
+
+// ApplyStatusCR applies status CR
+func (p *Fluxv2Provider) ApplyStatusCR(name string, content []byte) error {
+
+       // Add namespace to the status resource, needed by
+       // Flux
+       //Decode the yaml to create a runtime.Object
+       unstruct := &unstructured.Unstructured{}
+       //Ignore the returned obj as we expect the data in unstruct
+       _, err := utils.DecodeYAMLData(string(content), unstruct)
+       if err != nil {
+               return err
+       }
+       // Set Namespace
+       unstruct.SetNamespace(p.gitProvider.Namespace)
+       b, err := unstruct.MarshalJSON()
+       if err != nil {
+               return err
+       }
+       ref, err := p.gitProvider.Apply(name, nil, b)
+       if err != nil {
+               return err
+       }
+       p.gitProvider.Commit(context.Background(), ref)
+       return err
+
+}
+
+// DeleteStatusCR deletes status CR
+func (p *Fluxv2Provider) DeleteStatusCR(name string, content []byte) error {
+       ref, err := p.gitProvider.Delete(name, nil, content)
+       if err != nil {
+               return err
+       }
+       p.gitProvider.Commit(context.Background(), ref)
+       return err
+}
diff --git a/central-controller/src/rsync/pkg/plugins/k8s/config.go b/central-controller/src/rsync/pkg/plugins/k8s/config.go
new file mode 100644 (file)
index 0000000..e3f1c7f
--- /dev/null
@@ -0,0 +1,16 @@
+// SPDX-License-Identifier: Apache-2.0
+// Copyright (c) 2020 Intel Corporation
+
+package k8s
+
+import (
+       "context"
+)
+
+// For K8s this function is not required to do any operation at this time
+func (p *K8sProvider) ApplyConfig(ctx context.Context, config interface{}) error {
+       return nil
+}
+func (p *K8sProvider) DeleteConfig(ctx context.Context, config interface{}) error {
+       return nil
+}
diff --git a/central-controller/src/rsync/pkg/plugins/k8s/k8s.go b/central-controller/src/rsync/pkg/plugins/k8s/k8s.go
new file mode 100644 (file)
index 0000000..3a4ccf4
--- /dev/null
@@ -0,0 +1,71 @@
+// SPDX-License-Identifier: Apache-2.0
+// Copyright (c) 2020 Intel Corporation
+
+package k8s
+
+import (
+       //"fmt"
+       "io/ioutil"
+       "os"
+
+       pkgerrors "github.com/pkg/errors"
+       log "gitlab.com/project-emco/core/emco-base/src/orchestrator/pkg/infra/logutils"
+       kubeclient "gitlab.com/project-emco/core/emco-base/src/rsync/pkg/client"
+       "gitlab.com/project-emco/core/emco-base/src/rsync/pkg/internal/utils"
+)
+
+// Connection is for a cluster
+type K8sProvider struct {
+       cid       string
+       cluster   string
+       app       string
+       namespace string
+       level     string
+       fileName  string
+       client    *kubeclient.Client
+}
+
+func NewK8sProvider(cid, app, cluster, level, namespace string) (*K8sProvider, error) {
+       p := K8sProvider{
+               cid:       cid,
+               app:       app,
+               cluster:   cluster,
+               level:     level,
+               namespace: namespace,
+       }
+       // Get file from DB
+       dec, err := utils.GetKubeConfig(cluster, level, namespace)
+       if err != nil {
+               return nil, err
+       }
+       //
+       f, err := ioutil.TempFile("/tmp", "rsync-config-"+cluster+"-")
+       if err != nil {
+               log.Error("Unable to create temp file in tmp directory", log.Fields{"err": err})
+               return nil, err
+       }
+       fileName := f.Name()
+       log.Info("Temp file for Kubeconfig", log.Fields{"fileName": fileName})
+       _, err = f.Write(dec)
+       if err != nil {
+               log.Error("Unable to write tmp directory", log.Fields{"err": err, "filename": fileName})
+               return nil, err
+       }
+
+       client := kubeclient.New("", fileName, namespace)
+       if client == nil {
+               return nil, pkgerrors.New("failed to connect with the cluster")
+       }
+       p.fileName = fileName
+       p.client = client
+       return &p, nil
+}
+
+// If file exists delete it
+func (p *K8sProvider) CleanClientProvider() error {
+       if _, err := os.Stat(p.fileName); err == nil {
+               os.Remove(p.fileName)
+       }
+       return nil
+
+}
diff --git a/central-controller/src/rsync/pkg/plugins/k8s/resources.go b/central-controller/src/rsync/pkg/plugins/k8s/resources.go
new file mode 100644 (file)
index 0000000..ac7ec3e
--- /dev/null
@@ -0,0 +1,94 @@
+// SPDX-License-Identifier: Apache-2.0
+// Copyright (c) 2020 Intel Corporation
+
+package k8s
+
+import (
+       "context"
+       pkgerrors "github.com/pkg/errors"
+       log "gitlab.com/project-emco/core/emco-base/src/orchestrator/pkg/infra/logutils"
+       "gitlab.com/project-emco/core/emco-base/src/rsync/pkg/internal/utils"
+       "gitlab.com/project-emco/core/emco-base/src/rsync/pkg/status"
+       apierrors "k8s.io/apimachinery/pkg/api/errors"
+       "strings"
+)
+
+// Creates a new resource if the not already existing
+func (p *K8sProvider) Create(name string, ref interface{}, content []byte) (interface{}, error) {
+
+       if err := p.client.Create(content); err != nil {
+               if apierrors.IsAlreadyExists(err) {
+                       log.Warn("Resource is already present, Skipping", log.Fields{"error": err, "resource": name})
+                       return nil, nil
+               } else {
+                       log.Error("Failed to create res", log.Fields{"error": err, "resource": name})
+               }
+               return nil, err
+       }
+       return nil, nil
+}
+
+// Apply resource to the cluster
+func (p *K8sProvider) Apply(name string, ref interface{}, content []byte) (interface{}, error) {
+
+       if err := p.client.Apply(content); err != nil {
+               log.Error("Failed to apply res", log.Fields{"error": err, "resource": name})
+               return nil, err
+       }
+       acUtils, err := utils.NewAppContextReference(p.cid)
+       if err != nil {
+               return nil, nil
+       }
+       // Currently only subresource supported is approval
+       subres, _, err := acUtils.GetSubResApprove(name, p.app, p.cluster)
+       if err == nil {
+               result := strings.Split(name, "+")
+               if result[0] == "" {
+                       return nil, pkgerrors.Errorf("Resource name is nil %s:", name)
+               }
+               log.Info("Approval Subresource::", log.Fields{"cluster": p.cluster, "resource": result[0], "approval": string(subres)})
+               err = p.client.Approve(result[0], subres)
+               return nil, err
+       }
+
+       return nil, nil
+}
+
+// Delete resource from the cluster
+func (p *K8sProvider) Delete(name string, ref interface{}, content []byte) (interface{}, error) {
+       if err := p.client.Delete(content); err != nil {
+               log.Error("Failed to delete res", log.Fields{"error": err, "resource": name})
+               return nil, err
+       }
+       return nil, nil
+}
+
+// Get resource from the cluster
+func (p *K8sProvider) Get(name string, gvkRes []byte) ([]byte, error) {
+       b, err := p.client.Get(gvkRes, p.namespace)
+       if err != nil {
+               log.Error("Failed to get res", log.Fields{"error": err, "resource": name})
+               return nil, err
+       }
+       return b, nil
+}
+
+// Commit resources to the cluster
+// Not required in K8s case
+func (p *K8sProvider) Commit(ctx context.Context, ref interface{}) error {
+       return nil
+}
+
+// IsReachable cluster reachablity test
+func (p *K8sProvider) IsReachable() error {
+       return p.client.IsReachable()
+}
+
+func (m *K8sProvider) TagResource(res []byte, label string) ([]byte, error) {
+       b, err := status.TagResource(res, label)
+       if err != nil {
+               log.Error("Error Tag Resoruce with label:", log.Fields{"err": err, "label": label, "resource": res})
+               return nil, err
+       }
+       return b, nil
+}
diff --git a/central-controller/src/rsync/pkg/plugins/k8s/status.go b/central-controller/src/rsync/pkg/plugins/k8s/status.go
new file mode 100644 (file)
index 0000000..34de1ab
--- /dev/null
@@ -0,0 +1,172 @@
+// SPDX-License-Identifier: Apache-2.0
+// Copyright (c) 2020 Intel Corporation
+
+package k8s
+
+import (
+       "strings"
+       "sync"
+
+       pkgerrors "github.com/pkg/errors"
+       log "gitlab.com/project-emco/core/emco-base/src/orchestrator/pkg/infra/logutils"
+
+       v1alpha1 "gitlab.com/project-emco/core/emco-base/src/monitor/pkg/apis/k8splugin/v1alpha1"
+       clientset "gitlab.com/project-emco/core/emco-base/src/monitor/pkg/client/clientset/versioned"
+       informers "gitlab.com/project-emco/core/emco-base/src/monitor/pkg/client/informers/externalversions"
+       "gitlab.com/project-emco/core/emco-base/src/rsync/pkg/internal/utils"
+       "gitlab.com/project-emco/core/emco-base/src/rsync/pkg/status"
+       "k8s.io/client-go/tools/cache"
+       "k8s.io/client-go/tools/clientcmd"
+)
+
+type channelManager struct {
+       channels map[string]chan struct{}
+       sync.Mutex
+}
+
+var channelData channelManager
+
+const monitorLabel = "emco/deployment-id"
+
+// HandleStatusUpdate for an application in a cluster
+func HandleStatusUpdate(clusterId string, id string, v *v1alpha1.ResourceBundleState) {
+       log.Info("K8s HandleStatusUpdate", log.Fields{"id": id, "cluster": clusterId})
+       // Get the contextId from the label (id)
+       result := strings.SplitN(id, "-", 2)
+       log.Info("::HandleStatusUpdate::", log.Fields{"id": id, "cluster": clusterId})
+       if result[0] == "" {
+               log.Error("::label is missing an appcontext identifier::", log.Fields{"id": id, "cluster": clusterId})
+               return
+       }
+       if len(result) != 2 {
+               log.Error("::invalid label format::", log.Fields{"id": id, "cluster": clusterId})
+               return
+       }
+       // Get the app from the label (id)
+       if result[1] == "" {
+               log.Error("::label is missing an app identifier::", log.Fields{"id": id, "cluster": clusterId})
+               return
+       }
+       log.Info("K8s HandleStatusUpdate", log.Fields{"id": id, "cluster": clusterId, "app": result[1]})
+       // Notify Resource tracking
+       status.HandleResourcesStatus(result[0], result[1], clusterId, v)
+}
+
+// StartClusterWatcher watches for CR
+// configBytes - Kubectl file data
+func (c *K8sProvider) StartClusterWatcher() error {
+
+       // a cluster watcher always watches the cluster as a whole, so rsync's CloudConfig level
+       // is 0 and namespace doesn't need to be specified because the result is non-ambiguous
+       log.Info("Starting cluster watcher with L0 cloudconfig", log.Fields{})
+
+       //key := provider + "+" + name
+       // Get the lock
+       channelData.Lock()
+       defer channelData.Unlock()
+       // For first time
+       if channelData.channels == nil {
+               channelData.channels = make(map[string]chan struct{})
+       }
+       _, ok := channelData.channels[c.cluster]
+       if !ok {
+               // Create Channel
+               channelData.channels[c.cluster] = make(chan struct{})
+               // Read config
+               configBytes, err := utils.GetKubeConfig(c.cluster, "0", "")
+               if err != nil {
+                       return err
+               }
+               // Create config
+               config, err := clientcmd.RESTConfigFromKubeConfig(configBytes)
+               if err != nil {
+                       log.Error("RESTConfigFromKubeConfig error:", log.Fields{"err": err})
+                       return pkgerrors.Wrap(err, "RESTConfigFromKubeConfig error")
+               }
+               k8sClient, err := clientset.NewForConfig(config)
+               if err != nil {
+                       return pkgerrors.Wrap(err, "Clientset NewForConfig error")
+               }
+               // Create Informer
+               mInformerFactory := informers.NewSharedInformerFactory(k8sClient, 0)
+               mInformer := mInformerFactory.K8splugin().V1alpha1().ResourceBundleStates().Informer()
+               go scheduleStatus(c.cluster, channelData.channels[c.cluster], mInformer)
+       }
+       return nil
+}
+
+// StopClusterWatcher stop watching a cluster
+func StopClusterWatcher(clusterId string) {
+       //key := provider + "+" + name
+       if channelData.channels != nil {
+               c, ok := channelData.channels[clusterId]
+               if ok {
+                       close(c)
+               }
+       }
+}
+
+// CloseAllClusterWatchers close all channels
+func CloseAllClusterWatchers() {
+       if channelData.channels == nil {
+               return
+       }
+       // Close all Channels to stop all watchers
+       for _, e := range channelData.channels {
+               close(e)
+       }
+}
+
+// Per Cluster Go routine to watch CR
+func scheduleStatus(clusterId string, c <-chan struct{}, s cache.SharedIndexInformer) {
+       handlers := cache.ResourceEventHandlerFuncs{
+               AddFunc: func(obj interface{}) {
+                       v, ok := obj.(*v1alpha1.ResourceBundleState)
+                       if ok {
+                               labels := v.GetLabels()
+                               l, ok := labels[monitorLabel]
+                               if ok {
+                                       HandleStatusUpdate(clusterId, l, v)
+                               }
+                       }
+               },
+               UpdateFunc: func(oldObj, obj interface{}) {
+                       v, ok := obj.(*v1alpha1.ResourceBundleState)
+                       if ok {
+                               labels := v.GetLabels()
+                               l, ok := labels[monitorLabel]
+                               if ok {
+                                       HandleStatusUpdate(clusterId, l, v)
+                               }
+                       }
+               },
+               DeleteFunc: func(obj interface{}) {
+                       // Ignore it
+               },
+       }
+       s.AddEventHandler(handlers)
+       s.Run(c)
+}
+
+// ApplyStatusCR applies status CR
+func (p *K8sProvider) ApplyStatusCR(name string, content []byte) error {
+       if err := p.client.Apply(content); err != nil {
+               log.Error("Failed to apply Status CR", log.Fields{
+                       "error": err,
+               })
+               return err
+       }
+       return nil
+
+}
+
+// DeleteStatusCR deletes status CR
+func (p *K8sProvider) DeleteStatusCR(name string, content []byte) error {
+       if err := p.client.Delete(content); err != nil {
+               log.Error("Failed to delete Status CR", log.Fields{
+                       "error": err,
+               })
+               return err
+       }
+       return nil
+}
diff --git a/central-controller/src/rsync/pkg/plugins/k8sexp/configexp.go b/central-controller/src/rsync/pkg/plugins/k8sexp/configexp.go
new file mode 100644 (file)
index 0000000..ec26854
--- /dev/null
@@ -0,0 +1,16 @@
+// SPDX-License-Identifier: Apache-2.0
+// Copyright (c) 2020 Intel Corporation
+
+package k8sexp
+
+import (
+       "context"
+)
+
+// For K8s this function is not required to do any operation at this time
+func (p *K8sProviderExp) ApplyConfig(ctx context.Context, config interface{}) error {
+       return nil
+}
+func (p *K8sProviderExp) DeleteConfig(ctx context.Context, config interface{}) error {
+       return nil
+}
diff --git a/central-controller/src/rsync/pkg/plugins/k8sexp/k8sexp.go b/central-controller/src/rsync/pkg/plugins/k8sexp/k8sexp.go
new file mode 100644 (file)
index 0000000..c01f697
--- /dev/null
@@ -0,0 +1,71 @@
+// SPDX-License-Identifier: Apache-2.0
+// Copyright (c) 2020 Intel Corporation
+
+package k8sexp
+
+import (
+       "io/ioutil"
+       "os"
+
+       pkgerrors "github.com/pkg/errors"
+       log "gitlab.com/project-emco/core/emco-base/src/orchestrator/pkg/infra/logutils"
+
+       kubeclient "gitlab.com/project-emco/core/emco-base/src/rsync/pkg/client"
+       "gitlab.com/project-emco/core/emco-base/src/rsync/pkg/internal/utils"
+)
+
+// Connection is for a cluster
+type K8sProviderExp struct {
+       cid       string
+       cluster   string
+       app       string
+       namespace string
+       level     string
+       fileName  string
+       client    *kubeclient.Client
+}
+
+func NewK8sProvider(cid, app, cluster, level, namespace string) (*K8sProviderExp, error) {
+       p := K8sProviderExp{
+               cid:       cid,
+               app:       app,
+               cluster:   cluster,
+               level:     level,
+               namespace: namespace,
+       }
+       // Get file from DB
+       dec, err := utils.GetKubeConfig(cluster, level, namespace)
+       if err != nil {
+               return nil, err
+       }
+       //
+       f, err := ioutil.TempFile("/tmp", "rsync-config-"+cluster+"-")
+       if err != nil {
+               log.Error("Unable to create temp file in tmp directory", log.Fields{"err": err})
+               return nil, err
+       }
+       fileName := f.Name()
+       log.Info("Temp file for Kubeconfig", log.Fields{"fileName": fileName})
+       _, err = f.Write(dec)
+       if err != nil {
+               log.Error("Unable to write tmp directory", log.Fields{"err": err, "filename": fileName})
+               return nil, err
+       }
+
+       client := kubeclient.New("", fileName, namespace)
+       if client == nil {
+               return nil, pkgerrors.New("failed to connect with the cluster")
+       }
+       p.fileName = fileName
+       p.client = client
+       return &p, nil
+}
+
+// If file exists delete it
+func (p *K8sProviderExp) CleanClientProvider() error {
+       log.Info("CleanClientProvider::", log.Fields{"filename": p.fileName})
+       if _, err := os.Stat(p.fileName); err == nil {
+               os.Remove(p.fileName)
+       }
+       return nil
+}
diff --git a/central-controller/src/rsync/pkg/plugins/k8sexp/resourcesexp.go b/central-controller/src/rsync/pkg/plugins/k8sexp/resourcesexp.go
new file mode 100644 (file)
index 0000000..6890c32
--- /dev/null
@@ -0,0 +1,204 @@
+// SPDX-License-Identifier: Apache-2.0
+// Copyright (c) 2020 Intel Corporation
+
+package k8sexp
+
+import (
+       "context"
+       "io/ioutil"
+       "os"
+
+       pkgerrors "github.com/pkg/errors"
+       log "gitlab.com/project-emco/core/emco-base/src/orchestrator/pkg/infra/logutils"
+       "gitlab.com/project-emco/core/emco-base/src/rsync/pkg/internal/utils"
+       "gitlab.com/project-emco/core/emco-base/src/rsync/pkg/status"
+       . "gitlab.com/project-emco/core/emco-base/src/rsync/pkg/types"
+       apierrors "k8s.io/apimachinery/pkg/api/errors"
+       "strings"
+)
+
+type approval struct {
+       name string
+       res  []byte
+}
+type reference struct {
+       op          RsyncOperation
+       filepath    string
+       approveList []approval
+}
+
+func appendRef(ref interface{}, b []byte, op RsyncOperation, apv ...approval) interface{} {
+
+       var exists bool
+       switch ref.(type) {
+       case *reference:
+               exists = true
+       default:
+               exists = false
+
+       }
+       var rf *reference
+       // Create rf is doesn't exist
+       if !exists {
+               f, err := ioutil.TempFile("/tmp", "k8sexp"+"-")
+               if err != nil {
+                       log.Error("Unable to create temp file in tmp directory", log.Fields{"err": err})
+                       return nil
+               }
+               rf = &reference{
+                       op:       op,
+                       filepath: f.Name(),
+               }
+       } else {
+               rf = ref.(*reference)
+       }
+       // If the file doesn't exist, create it, or append to the file
+       f, err := os.OpenFile(rf.filepath, os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0644)
+       if err != nil {
+               log.Error("Error opening file", log.Fields{"err": err, "filepath": rf.filepath})
+               return rf
+       }
+       defer f.Close()
+       // Write seperator
+       if _, err := f.Write([]byte("\n---\n")); err != nil {
+               log.Error("Error appending file", log.Fields{"err": err, "filepath": rf.filepath})
+               return rf
+       }
+       if _, err := f.Write(b); err != nil {
+               log.Error("Error appending file", log.Fields{"err": err, "filepath": rf.filepath})
+       }
+       rf.approveList = append(rf.approveList, apv...)
+       return rf
+}
+
+// Creates a new resource if the not already existing
+func (p *K8sProviderExp) Create(name string, ref interface{}, content []byte) (interface{}, error) {
+       // Add the label based on the Status Appcontext ID
+       label := p.cid + "-" + p.app
+       b, err := status.TagResource(content, label)
+       if err != nil {
+               log.Error("Error Tag Resoruce with label:", log.Fields{"err": err, "label": label, "resource": name})
+               return nil, err
+       }
+       ref = appendRef(ref, b, OpCreate)
+       return ref, nil
+}
+
+// Apply resource to the cluster
+func (p *K8sProviderExp) Apply(name string, ref interface{}, content []byte) (interface{}, error) {
+       var apv approval
+       // Add the label based on the Status Appcontext ID
+       label := p.cid + "-" + p.app
+       b, err := status.TagResource(content, label)
+       if err != nil {
+               log.Error("Error Tag Resoruce with label:", log.Fields{"err": err, "label": label, "resource": name})
+               return nil, err
+       }
+       // Check if subresource
+       acUtils, err := utils.NewAppContextReference(p.cid)
+       if err != nil {
+               return ref, err
+       }
+       // Currently only subresource supported is approval
+       subres, _, err := acUtils.GetSubResApprove(name, p.app, p.cluster)
+       if err == nil {
+               result := strings.Split(name, "+")
+               if result[0] == "" {
+                       return nil, pkgerrors.Errorf("Resource name is nil %s:", name)
+               }
+               log.Info("Approval Subresource::", log.Fields{"cluster": p.cluster, "resource": result[0], "approval": string(subres)})
+               apv = approval{name: result[0], res: subres}
+               ref = appendRef(ref, b, OpApply, apv)
+       } else {
+               ref = appendRef(ref, b, OpApply)
+       }
+       return ref, nil
+}
+
+// Delete resource from the cluster
+func (p *K8sProviderExp) Delete(name string, ref interface{}, content []byte) (interface{}, error) {
+       ref = appendRef(ref, content, OpDelete)
+       return ref, nil
+
+}
+
+// Get resource from the cluster
+func (p *K8sProviderExp) Get(name string, gvkRes []byte) ([]byte, error) {
+       b, err := p.client.Get(gvkRes, p.namespace)
+       if err != nil {
+               log.Error("Failed to get res", log.Fields{"error": err, "resource": name})
+               return nil, err
+       }
+       return b, nil
+}
+
+// Commit resources to the cluster
+func (p *K8sProviderExp) Commit(ctx context.Context, ref interface{}) error {
+       var exists bool
+       switch ref.(type) {
+       case *reference:
+               exists = true
+       default:
+               exists = false
+
+       }
+       // Check for rf
+       if !exists {
+               log.Error("Commit: No ref found", log.Fields{})
+               return nil
+       }
+       rf := ref.(*reference)
+       log.Info("Commit:: Ref found", log.Fields{"filename": rf.filepath, "op": rf.op})
+       defer os.Remove(rf.filepath)
+       content, err := ioutil.ReadFile(rf.filepath)
+       if err != nil {
+               log.Error("File read failed", log.Fields{"Error": err})
+               return err
+       }
+       switch rf.op {
+       case OpDelete:
+               if err := p.client.Delete(content); err != nil {
+                       log.Error("Failed to delete resources", log.Fields{"error": err})
+                       return err
+               }
+       case OpApply:
+               if err := p.client.Apply(content); err != nil {
+                       log.Error("Failed to apply resources", log.Fields{"error": err})
+                       return err
+               }
+               //Check if approval list is not 0
+               if len(rf.approveList) > 0 {
+                       for _, apv := range rf.approveList {
+                               if err := p.client.Approve(apv.name, apv.res); err != nil {
+                                       log.Error("Failed to approve resources", log.Fields{"error": err})
+                                       return err
+                               }
+                       }
+               }
+       case OpCreate:
+               if err := p.client.Create(content); err != nil {
+                       if apierrors.IsAlreadyExists(err) {
+                               log.Warn("Resources is already present, Skipping", log.Fields{"error": err})
+                               return nil
+                       } else {
+                               log.Error("Failed to create resources", log.Fields{"error": err})
+                               return err
+                       }
+               }
+       }
+       return nil
+}
+
+// IsReachable cluster reachablity test
+func (p *K8sProviderExp) IsReachable() error {
+       return p.client.IsReachable()
+}
+
+func (m *K8sProviderExp) TagResource(res []byte, label string) ([]byte, error) {
+       b, err := status.TagResource(res, label)
+       if err != nil {
+               log.Error("Error Tag Resoruce with label:", log.Fields{"err": err, "label": label, "resource": res})
+               return nil, err
+       }
+       return b, nil
+}
diff --git a/central-controller/src/rsync/pkg/plugins/k8sexp/statusexp.go b/central-controller/src/rsync/pkg/plugins/k8sexp/statusexp.go
new file mode 100644 (file)
index 0000000..4c1103c
--- /dev/null
@@ -0,0 +1,43 @@
+// SPDX-License-Identifier: Apache-2.0
+// Copyright (c) 2020 Intel Corporation
+
+package k8sexp
+
+import (
+       log "gitlab.com/project-emco/core/emco-base/src/orchestrator/pkg/infra/logutils"
+       "gitlab.com/project-emco/core/emco-base/src/rsync/pkg/plugins/k8s"
+)
+
+// StartClusterWatcher watches for CR
+// Same as K8s
+func (c *K8sProviderExp) StartClusterWatcher() error {
+       cl, err := k8s.NewK8sProvider(c.cid, c.app, c.cluster, c.level, c.namespace)
+       defer cl.CleanClientProvider()
+       if err != nil {
+               return err
+       }
+       return cl.StartClusterWatcher()
+}
+
+// ApplyStatusCR applies status CR
+func (p *K8sProviderExp) ApplyStatusCR(name string, content []byte) error {
+       if err := p.client.Apply(content); err != nil {
+               log.Error("Failed to apply Status CR", log.Fields{
+                       "error": err,
+               })
+               return err
+       }
+       return nil
+
+}
+
+// DeleteStatusCR deletes status CR
+func (p *K8sProviderExp) DeleteStatusCR(name string, content []byte) error {
+       if err := p.client.Delete(content); err != nil {
+               log.Error("Failed to delete Status CR", log.Fields{
+                       "error": err,
+               })
+               return err
+       }
+       return nil
+}
diff --git a/central-controller/src/rsync/pkg/status/deploymentutil.go b/central-controller/src/rsync/pkg/status/deploymentutil.go
new file mode 100644 (file)
index 0000000..6109518
--- /dev/null
@@ -0,0 +1,178 @@
+/*
+Copyright 2016 The Kubernetes Authors.
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+package status
+
+import (
+       "context"
+       "sort"
+
+       apps "k8s.io/api/apps/v1"
+       v1 "k8s.io/api/core/v1"
+       apiequality "k8s.io/apimachinery/pkg/api/equality"
+       metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
+       intstrutil "k8s.io/apimachinery/pkg/util/intstr"
+       appsclient "k8s.io/client-go/kubernetes/typed/apps/v1"
+)
+
+// deploymentutil contains a copy of a few functions from Kubernetes controller code to avoid a dependency on k8s.io/kubernetes.
+// This code is copied from https://github.com/kubernetes/kubernetes/blob/e856613dd5bb00bcfaca6974431151b5c06cbed5/pkg/controller/deployment/util/deployment_util.go
+// No changes to the code were made other than removing some unused functions
+
+// RsListFunc returns the ReplicaSet from the ReplicaSet namespace and the List metav1.ListOptions.
+type RsListFunc func(string, metav1.ListOptions) ([]*apps.ReplicaSet, error)
+
+// ListReplicaSets returns a slice of RSes the given deployment targets.
+// Note that this does NOT attempt to reconcile ControllerRef (adopt/orphan),
+// because only the controller itself should do that.
+// However, it does filter out anything whose ControllerRef doesn't match.
+func ListReplicaSets(deployment *apps.Deployment, getRSList RsListFunc) ([]*apps.ReplicaSet, error) {
+       // TODO: Right now we list replica sets by their labels. We should list them by selector, i.e. the replica set's selector
+       //       should be a superset of the deployment's selector, see https://github.com/kubernetes/kubernetes/issues/19830.
+       namespace := deployment.Namespace
+       selector, err := metav1.LabelSelectorAsSelector(deployment.Spec.Selector)
+       if err != nil {
+               return nil, err
+       }
+       options := metav1.ListOptions{LabelSelector: selector.String()}
+       all, err := getRSList(namespace, options)
+       if err != nil {
+               return nil, err
+       }
+       // Only include those whose ControllerRef matches the Deployment.
+       owned := make([]*apps.ReplicaSet, 0, len(all))
+       for _, rs := range all {
+               if metav1.IsControlledBy(rs, deployment) {
+                       owned = append(owned, rs)
+               }
+       }
+       return owned, nil
+}
+
+// ReplicaSetsByCreationTimestamp sorts a list of ReplicaSet by creation timestamp, using their names as a tie breaker.
+type ReplicaSetsByCreationTimestamp []*apps.ReplicaSet
+
+func (o ReplicaSetsByCreationTimestamp) Len() int      { return len(o) }
+func (o ReplicaSetsByCreationTimestamp) Swap(i, j int) { o[i], o[j] = o[j], o[i] }
+func (o ReplicaSetsByCreationTimestamp) Less(i, j int) bool {
+       if o[i].CreationTimestamp.Equal(&o[j].CreationTimestamp) {
+               return o[i].Name < o[j].Name
+       }
+       return o[i].CreationTimestamp.Before(&o[j].CreationTimestamp)
+}
+
+// FindNewReplicaSet returns the new RS this given deployment targets (the one with the same pod template).
+func FindNewReplicaSet(deployment *apps.Deployment, rsList []*apps.ReplicaSet) *apps.ReplicaSet {
+       sort.Sort(ReplicaSetsByCreationTimestamp(rsList))
+       for i := range rsList {
+               if EqualIgnoreHash(&rsList[i].Spec.Template, &deployment.Spec.Template) {
+                       // In rare cases, such as after cluster upgrades, Deployment may end up with
+                       // having more than one new ReplicaSets that have the same template as its template,
+                       // see https://github.com/kubernetes/kubernetes/issues/40415
+                       // We deterministically choose the oldest new ReplicaSet.
+                       return rsList[i]
+               }
+       }
+       // new ReplicaSet does not exist.
+       return nil
+}
+
+// EqualIgnoreHash returns true if two given podTemplateSpec are equal, ignoring the diff in value of Labels[pod-template-hash]
+// We ignore pod-template-hash because:
+// 1. The hash result would be different upon podTemplateSpec API changes
+//    (e.g. the addition of a new field will cause the hash code to change)
+// 2. The deployment template won't have hash labels
+func EqualIgnoreHash(template1, template2 *v1.PodTemplateSpec) bool {
+       t1Copy := template1.DeepCopy()
+       t2Copy := template2.DeepCopy()
+       // Remove hash labels from template.Labels before comparing
+       delete(t1Copy.Labels, apps.DefaultDeploymentUniqueLabelKey)
+       delete(t2Copy.Labels, apps.DefaultDeploymentUniqueLabelKey)
+       return apiequality.Semantic.DeepEqual(t1Copy, t2Copy)
+}
+
+// GetNewReplicaSet returns a replica set that matches the intent of the given deployment; get ReplicaSetList from client interface.
+// Returns nil if the new replica set doesn't exist yet.
+func GetNewReplicaSet(deployment *apps.Deployment, c appsclient.AppsV1Interface) (*apps.ReplicaSet, error) {
+       rsList, err := ListReplicaSets(deployment, RsListFromClient(c))
+       if err != nil {
+               return nil, err
+       }
+       return FindNewReplicaSet(deployment, rsList), nil
+}
+
+// RsListFromClient returns an rsListFunc that wraps the given client.
+func RsListFromClient(c appsclient.AppsV1Interface) RsListFunc {
+       return func(namespace string, options metav1.ListOptions) ([]*apps.ReplicaSet, error) {
+               rsList, err := c.ReplicaSets(namespace).List(context.Background(), options)
+               if err != nil {
+                       return nil, err
+               }
+               var ret []*apps.ReplicaSet
+               for i := range rsList.Items {
+                       ret = append(ret, &rsList.Items[i])
+               }
+               return ret, err
+       }
+}
+
+// IsRollingUpdate returns true if the strategy type is a rolling update.
+func IsRollingUpdate(deployment *apps.Deployment) bool {
+       return deployment.Spec.Strategy.Type == apps.RollingUpdateDeploymentStrategyType
+}
+
+// MaxUnavailable returns the maximum unavailable pods a rolling deployment can take.
+func MaxUnavailable(deployment apps.Deployment) int32 {
+       if !IsRollingUpdate(&deployment) || *(deployment.Spec.Replicas) == 0 {
+               return int32(0)
+       }
+       // Error caught by validation
+       _, maxUnavailable, _ := ResolveFenceposts(deployment.Spec.Strategy.RollingUpdate.MaxSurge, deployment.Spec.Strategy.RollingUpdate.MaxUnavailable, *(deployment.Spec.Replicas))
+       if maxUnavailable > *deployment.Spec.Replicas {
+               return *deployment.Spec.Replicas
+       }
+       return maxUnavailable
+}
+
+// ResolveFenceposts resolves both maxSurge and maxUnavailable. This needs to happen in one
+// step. For example:
+//
+// 2 desired, max unavailable 1%, surge 0% - should scale old(-1), then new(+1), then old(-1), then new(+1)
+// 1 desired, max unavailable 1%, surge 0% - should scale old(-1), then new(+1)
+// 2 desired, max unavailable 25%, surge 1% - should scale new(+1), then old(-1), then new(+1), then old(-1)
+// 1 desired, max unavailable 25%, surge 1% - should scale new(+1), then old(-1)
+// 2 desired, max unavailable 0%, surge 1% - should scale new(+1), then old(-1), then new(+1), then old(-1)
+// 1 desired, max unavailable 0%, surge 1% - should scale new(+1), then old(-1)
+func ResolveFenceposts(maxSurge, maxUnavailable *intstrutil.IntOrString, desired int32) (int32, int32, error) {
+       surge, err := intstrutil.GetValueFromIntOrPercent(intstrutil.ValueOrDefault(maxSurge, intstrutil.FromInt(0)), int(desired), true)
+       if err != nil {
+               return 0, 0, err
+       }
+       unavailable, err := intstrutil.GetValueFromIntOrPercent(intstrutil.ValueOrDefault(maxUnavailable, intstrutil.FromInt(0)), int(desired), false)
+       if err != nil {
+               return 0, 0, err
+       }
+
+       if surge == 0 && unavailable == 0 {
+               // Validation should never allow the user to explicitly use zero values for both maxSurge
+               // maxUnavailable. Due to rounding down maxUnavailable though, it may resolve to zero.
+               // If both fenceposts resolve to zero, then we should set maxUnavailable to 1 on the
+               // theory that surge might not work due to quota.
+               unavailable = 1
+       }
+
+       return int32(surge), int32(unavailable), nil
+}
diff --git a/central-controller/src/rsync/pkg/status/ready.go b/central-controller/src/rsync/pkg/status/ready.go
new file mode 100644 (file)
index 0000000..f81a58f
--- /dev/null
@@ -0,0 +1,246 @@
+/*
+Copyright The Helm Authors.
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+package status
+
+import (
+       "gitlab.com/project-emco/core/emco-base/src/orchestrator/pkg/infra/logutils"
+       appsv1 "k8s.io/api/apps/v1"
+       batchv1 "k8s.io/api/batch/v1"
+       corev1 "k8s.io/api/core/v1"
+       "k8s.io/apimachinery/pkg/util/intstr"
+       "log"
+)
+
+// ReadyCheckerOption is a function that configures a ReadyChecker.
+type ReadyCheckerOption func(*ReadyChecker)
+
+// PausedAsReady returns a ReadyCheckerOption that configures a ReadyChecker
+// to consider paused resources to be ready. For example a Deployment
+// with spec.paused equal to true would be considered ready.
+func PausedAsReady(pausedAsReady bool) ReadyCheckerOption {
+       return func(c *ReadyChecker) {
+               c.pausedAsReady = pausedAsReady
+       }
+}
+
+// CheckJobs returns a ReadyCheckerOption that configures a ReadyChecker
+// to consider readiness of Job resources.
+func CheckJobs(checkJobs bool) ReadyCheckerOption {
+       return func(c *ReadyChecker) {
+               c.checkJobs = checkJobs
+       }
+}
+
+// NewReadyChecker creates a new checker. Passed ReadyCheckerOptions can
+// be used to override defaults.
+func NewReadyChecker(opts ...ReadyCheckerOption) ReadyChecker {
+       c := ReadyChecker{}
+
+       for _, opt := range opts {
+               opt(&c)
+       }
+
+       return c
+}
+
+// ReadyChecker is a type that can check core Kubernetes types for readiness.
+type ReadyChecker struct {
+       checkJobs     bool
+       pausedAsReady bool
+}
+
+// PodReady returns true if a pod is ready; false otherwise.
+func (c *ReadyChecker) PodReady(pod *corev1.Pod) bool {
+       for _, cn := range pod.Status.Conditions {
+               if cn.Type == corev1.PodReady && cn.Status == corev1.ConditionTrue {
+                       return true
+               }
+       }
+       log.Printf("Pod is not ready: %s/%s", pod.GetNamespace(), pod.GetName())
+       return false
+}
+
+func (c *ReadyChecker) JobReady(job *batchv1.Job) bool {
+       if c.checkJobs {
+               if job.Status.Failed > *job.Spec.BackoffLimit {
+                       log.Printf("Job is failed: %s/%s", job.GetNamespace(), job.GetName())
+                       return false
+               }
+               if job.Status.Succeeded < *job.Spec.Completions {
+                       log.Printf("Job is not completed: %s/%s", job.GetNamespace(), job.GetName())
+                       return false
+               }
+               return true
+       }
+       return false
+}
+
+func (c *ReadyChecker) ServiceReady(s *corev1.Service) bool {
+       // ExternalName Services are external to cluster so helm shouldn't be checking to see if they're 'ready' (i.e. have an IP Set)
+       if s.Spec.Type == corev1.ServiceTypeExternalName {
+               return true
+       }
+
+       // Ensure that the service cluster IP is not empty
+       if s.Spec.ClusterIP == "" {
+               log.Printf("Service does not have cluster IP address: %s/%s", s.GetNamespace(), s.GetName())
+               return false
+       }
+
+       // This checks if the service has a LoadBalancer and that balancer has an Ingress defined
+       if s.Spec.Type == corev1.ServiceTypeLoadBalancer {
+               // do not wait when at least 1 external IP is set
+               if len(s.Spec.ExternalIPs) > 0 {
+                       log.Printf("Service %s/%s has external IP addresses (%v), marking as ready", s.GetNamespace(), s.GetName(), s.Spec.ExternalIPs)
+                       return true
+               }
+
+               if s.Status.LoadBalancer.Ingress == nil {
+                       log.Printf("Service does not have load balancer ingress IP address: %s/%s", s.GetNamespace(), s.GetName())
+                       return false
+               }
+       }
+
+       return true
+}
+
+func (c *ReadyChecker) VolumeReady(v *corev1.PersistentVolumeClaim) bool {
+       if v.Status.Phase != corev1.ClaimBound {
+               log.Printf("PersistentVolumeClaim is not bound: %s/%s", v.GetNamespace(), v.GetName())
+               return false
+       }
+       return true
+}
+
+func (c *ReadyChecker) DeploymentReady(dep *appsv1.Deployment) bool {
+       // If paused deployment will never be ready
+       if dep.Spec.Paused {
+               return c.pausedAsReady
+       }
+       expectedReady := *dep.Spec.Replicas - MaxUnavailable(*dep)
+       if !(dep.Status.ReadyReplicas >= expectedReady) {
+               log.Printf("Deployment is not ready: %s/%s. %d out of %d expected pods are ready", dep.Namespace, dep.Name, dep.Status.ReadyReplicas, expectedReady)
+               return false
+       }
+       return true
+}
+
+func (c *ReadyChecker) DaemonSetReady(ds *appsv1.DaemonSet) bool {
+       // If the update strategy is not a rolling update, there will be nothing to wait for
+       if ds.Spec.UpdateStrategy.Type != appsv1.RollingUpdateDaemonSetStrategyType {
+               return true
+       }
+
+       // Make sure all the updated pods have been scheduled
+       if ds.Status.UpdatedNumberScheduled != ds.Status.DesiredNumberScheduled {
+               log.Printf("DaemonSet is not ready: %s/%s. %d out of %d expected pods have been scheduled", ds.Namespace, ds.Name, ds.Status.UpdatedNumberScheduled, ds.Status.DesiredNumberScheduled)
+               return false
+       }
+       maxUnavailable, err := intstr.GetValueFromIntOrPercent(ds.Spec.UpdateStrategy.RollingUpdate.MaxUnavailable, int(ds.Status.DesiredNumberScheduled), true)
+       if err != nil {
+               // If for some reason the value is invalid, set max unavailable to the
+               // number of desired replicas. This is the same behavior as the
+               // `MaxUnavailable` function in deploymentutil
+               maxUnavailable = int(ds.Status.DesiredNumberScheduled)
+       }
+
+       expectedReady := int(ds.Status.DesiredNumberScheduled) - maxUnavailable
+       if !(int(ds.Status.NumberReady) >= expectedReady) {
+               log.Printf("DaemonSet is not ready: %s/%s. %d out of %d expected pods are ready", ds.Namespace, ds.Name, ds.Status.NumberReady, expectedReady)
+               return false
+       }
+       return true
+}
+
+func (c *ReadyChecker) StatefulSetReady(sts *appsv1.StatefulSet) bool {
+       // If the update strategy is not a rolling update, there will be nothing to wait for
+       if sts.Spec.UpdateStrategy.Type != appsv1.RollingUpdateStatefulSetStrategyType {
+               return true
+       }
+
+       // Dereference all the pointers because StatefulSets like them
+       var partition int
+       // 1 is the default for replicas if not set
+       var replicas = 1
+       // For some reason, even if the update strategy is a rolling update, the
+       // actual rollingUpdate field can be nil. If it is, we can safely assume
+       // there is no partition value
+       if sts.Spec.UpdateStrategy.RollingUpdate != nil && sts.Spec.UpdateStrategy.RollingUpdate.Partition != nil {
+               partition = int(*sts.Spec.UpdateStrategy.RollingUpdate.Partition)
+       }
+       if sts.Spec.Replicas != nil {
+               replicas = int(*sts.Spec.Replicas)
+       }
+
+       // Because an update strategy can use partitioning, we need to calculate the
+       // number of updated replicas we should have. For example, if the replicas
+       // is set to 3 and the partition is 2, we'd expect only one pod to be
+       // updated
+       expectedReplicas := replicas - partition
+
+       // Make sure all the updated pods have been scheduled
+       if int(sts.Status.UpdatedReplicas) != expectedReplicas {
+               log.Printf("StatefulSet is not ready: %s/%s. %d out of %d expected pods have been scheduled", sts.Namespace, sts.Name, sts.Status.UpdatedReplicas, expectedReplicas)
+               return false
+       }
+
+       if int(sts.Status.ReadyReplicas) != replicas {
+               log.Printf("StatefulSet is not ready: %s/%s. %d out of %d expected pods are ready", sts.Namespace, sts.Name, sts.Status.ReadyReplicas, replicas)
+               return false
+       }
+       return true
+}
+
+// These methods are mainly for hook implementations.
+//
+// For most kinds, the checks to see if the resource is marked as Added or Modified
+// by the Kubernetes event stream is enough. For some kinds, more is required:
+//
+// - Jobs: A job is marked "Ready" when it has successfully completed. This is
+//   ascertained by watching the Status fields in a job's output.
+// - Pods: A pod is marked "Ready" when it has successfully completed. This is
+//   ascertained by watching the status.phase field in a pod's output.
+//
+func (c *ReadyChecker) PodSuccess(pod *corev1.Pod) bool {
+
+       switch pod.Status.Phase {
+       case corev1.PodSucceeded:
+               logutils.Info("Pod succeeded::", logutils.Fields{"Pod Name": pod.Name})
+               return true
+       case corev1.PodFailed:
+               return true
+       case corev1.PodPending:
+               logutils.Info("Pod running::", logutils.Fields{"Pod Name": pod.Name})
+       case corev1.PodRunning:
+               logutils.Info("Pod is Running::", logutils.Fields{"Pod Name": pod.Name})
+       }
+
+       return false
+}
+
+func (c *ReadyChecker) JobSuccess(job *batchv1.Job) bool {
+
+       for _, c := range job.Status.Conditions {
+               if c.Type == batchv1.JobComplete && c.Status == "True" {
+                       return true
+               } else if c.Type == batchv1.JobFailed && c.Status == "True" {
+                       return true
+               }
+       }
+       logutils.Info("Job Status:", logutils.Fields{"Jobs active": job.Status.Active, "Jobs failed": job.Status.Failed, "Jobs Succeded": job.Status.Succeeded})
+       return false
+}
diff --git a/central-controller/src/rsync/pkg/status/res_status.go b/central-controller/src/rsync/pkg/status/res_status.go
new file mode 100644 (file)
index 0000000..57f0ea7
--- /dev/null
@@ -0,0 +1,290 @@
+// SPDX-License-Identifier: Apache-2.0
+// Copyright (c) 2020 Intel Corporation
+
+package status
+
+import (
+       "encoding/json"
+
+       yaml "github.com/ghodss/yaml"
+       rb "gitlab.com/project-emco/core/emco-base/src/monitor/pkg/apis/k8splugin/v1alpha1"
+       "gitlab.com/project-emco/core/emco-base/src/orchestrator/pkg/appcontext"
+       log "gitlab.com/project-emco/core/emco-base/src/orchestrator/pkg/infra/logutils"
+       "gitlab.com/project-emco/core/emco-base/src/rsync/pkg/depend"
+       "gitlab.com/project-emco/core/emco-base/src/rsync/pkg/grpc/readynotifyserver"
+       metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
+       "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
+
+       "gitlab.com/project-emco/core/emco-base/src/rsync/pkg/internal/utils"
+       "gitlab.com/project-emco/core/emco-base/src/rsync/pkg/types"
+)
+
+var PreInstallHookLabel string = "emco/preinstallHook"
+
+// Update status for the App ready on a cluster and check if app ready on all clusters
+func HandleResourcesStatus(acID, app, cluster string, rbData *rb.ResourceBundleState) {
+
+       // Look up the contextId
+       var ac appcontext.AppContext
+       _, err := ac.LoadAppContext(acID)
+       if err != nil {
+               log.Error("::App context not found::", log.Fields{"acID": acID, "app": app, "cluster": cluster, "err": err})
+               return
+       }
+       // Produce yaml representation of the status
+       vjson, err := json.Marshal(rbData.Status)
+       if err != nil {
+               log.Error("::Error marshalling status information::", log.Fields{"acID": acID, "app": app, "cluster": cluster, "err": err})
+               return
+       }
+       chandle, err := ac.GetClusterHandle(app, cluster)
+       if err != nil {
+               log.Error("::Error getting cluster handle::", log.Fields{"acID": acID, "app": app, "cluster": cluster, "err": err})
+               return
+       }
+       // Get the handle for the context/app/cluster status object
+       handle, _ := ac.GetLevelHandle(chandle, "status")
+
+       // If status handle was not found, then create the status object in the appcontext
+       if handle == nil {
+               ac.AddLevelValue(chandle, "status", string(vjson))
+       } else {
+               ac.UpdateStatusValue(handle, string(vjson))
+       }
+
+       UpdateAppReadyStatus(acID, app, cluster, rbData)
+
+       // Inform Rsync dependency management of the update
+       go depend.ResourcesReady(acID, app, cluster)
+
+       // Send notification to the subscribers
+       err = readynotifyserver.SendAppContextNotification(acID)
+       if err != nil {
+               log.Error("::Error sending ReadyNotify to subscribers::", log.Fields{"acID": acID, "app": app, "cluster": cluster, "err": err})
+       }
+}
+
+func updateResourcesStatus(acID, app, cluster string, rbData *rb.ResourceBundleState) bool {
+       var Ready bool = true
+       // Default is ready status
+       // In case of Hook resoureces if Pod and Job it is success status
+       var statusType types.ResourceStatusType = types.ReadyStatus
+       acUtils, err := utils.NewAppContextReference(acID)
+       if err != nil {
+               return false
+       }
+       readyChecker := NewReadyChecker(PausedAsReady(true), CheckJobs(true))
+       var avail bool = false
+       for _, s := range rbData.Status.ServiceStatuses {
+               name := s.Name + "+" + "Service"
+               b := readyChecker.ServiceReady(&s)
+               avail = true
+               // If not ready set flag to false
+               if !b {
+                       Ready = false
+               }
+               acUtils.SetResourceReadyStatus(app, cluster, name, string(types.ReadyStatus), b)
+       }
+       for _, d := range rbData.Status.DeploymentStatuses {
+               avail = true
+               name := d.Name + "+" + "Deployment"
+               b := readyChecker.DeploymentReady(&d)
+               // If not ready set flag to false
+               if !b {
+                       Ready = false
+               }
+               acUtils.SetResourceReadyStatus(app, cluster, name, string(statusType), b)
+       }
+       for _, d := range rbData.Status.DaemonSetStatuses {
+               avail = true
+               name := d.Name + "+" + "Daemon"
+               b := readyChecker.DaemonSetReady(&d)
+               // If not ready set flag to false
+               if !b {
+                       Ready = false
+               }
+               acUtils.SetResourceReadyStatus(app, cluster, name, string(statusType), b)
+       }
+       for _, s := range rbData.Status.StatefulSetStatuses {
+               avail = true
+               name := s.Name + "+" + "StatefulSet"
+               b := readyChecker.StatefulSetReady(&s)
+               // If not ready set flag to false
+               if !b {
+                       Ready = false
+               }
+               acUtils.SetResourceReadyStatus(app, cluster, name, string(types.ReadyStatus), b)
+       }
+       for _, j := range rbData.Status.JobStatuses {
+               name := j.Name + "+" + "Job"
+               // Check if the Job is a Hook
+               annoMap := j.GetAnnotations()
+               _, ok := annoMap["helm.sh/hook"]
+               if ok {
+                       // Hooks are checked for Success Status
+                       acUtils.SetResourceReadyStatus(app, cluster, name, string(types.SuccessStatus), readyChecker.JobSuccess(&j))
+                       // No need to consider hook resources for ready status
+                       continue
+               }
+               avail = true
+               b := readyChecker.JobReady(&j)
+               // If not ready set flag to false
+               if !b {
+                       Ready = false
+               }
+               acUtils.SetResourceReadyStatus(app, cluster, name, string(types.ReadyStatus), b)
+       }
+
+       for _, p := range rbData.Status.PodStatuses {
+               name := p.Name + "+" + "Pod"
+
+               // Check if the Pod is a Hook
+               annoMap := p.GetAnnotations()
+               _, ok := annoMap["helm.sh/hook"]
+               if ok {
+                       // Hooks are checked for Success Status
+                       acUtils.SetResourceReadyStatus(app, cluster, name, string(types.SuccessStatus), readyChecker.PodSuccess(&p))
+                       // No need to consider hook resources for ready status
+                       continue
+               }
+               // Check if Pod is associated with a Job, if so skip that Pod
+               // That Pod will never go in ready state
+               labels := p.GetLabels()
+               _, job := labels["job-name"]
+               if job {
+                       acUtils.SetResourceReadyStatus(app, cluster, name, string(types.SuccessStatus), readyChecker.PodSuccess(&p))
+                       continue
+               }
+               avail = true
+               // If not ready set flag to false
+               b := readyChecker.PodReady(&p)
+               if !b {
+                       Ready = false
+               }
+               acUtils.SetResourceReadyStatus(app, cluster, name, string(statusType), b)
+       }
+       if !avail {
+               return false
+       }
+
+       return Ready
+
+}
+func UpdateAppReadyStatus(acID, app string, cluster string, rbData *rb.ResourceBundleState) bool {
+
+       // Check if hook label is present
+       labels := rbData.GetLabels()
+       // Status tracking is also used for per install hooks
+       // At the time of preinstall hook installation cluster
+       // ready status should not be updated
+       _, hookCR := labels[PreInstallHookLabel]
+       acUtils, err := utils.NewAppContextReference(acID)
+       if err != nil {
+               return false
+       }
+       if hookCR {
+               // If hookCR label, no need to update the ready status
+               // Main resources not installed yet
+               return updateResourcesStatus(acID, app, cluster, rbData)
+       }
+       //  Update AppContext to flase
+       // If the application is not ready stop processing
+       if !updateResourcesStatus(acID, app, cluster, rbData) {
+               acUtils.SetClusterResourcesReady(app, cluster, false)
+               return false
+       }
+       // If Application is ready on the cluster, Update AppContext
+       acUtils.SetClusterResourcesReady(app, cluster, true)
+       log.Info(" UpdateAppReadyStatus:: App is ready on cluster", log.Fields{"acID": acID, "app": app, "cluster": cluster})
+       return true
+}
+
+// GetStatusCR returns a status monitoring customer resource
+func GetStatusCR(label string, extraLabel string) ([]byte, error) {
+
+       var statusCr rb.ResourceBundleState
+
+       statusCr.TypeMeta.APIVersion = "k8splugin.io/v1alpha1"
+       statusCr.TypeMeta.Kind = "ResourceBundleState"
+       statusCr.SetName(label)
+
+       labels := make(map[string]string)
+       labels["emco/deployment-id"] = label
+       if len(extraLabel) > 0 {
+               labels[extraLabel] = "true"
+       }
+       statusCr.SetLabels(labels)
+
+       labelSelector, err := metav1.ParseToLabelSelector("emco/deployment-id = " + label)
+       if err != nil {
+               return nil, err
+       }
+       statusCr.Spec.Selector = labelSelector
+
+       // Marshaling to json then convert to yaml works better than marshaling to yaml
+       // The 'apiVersion' attribute was marshaling to 'apiversion'
+       j, err := json.Marshal(&statusCr)
+       if err != nil {
+               return nil, err
+       }
+       y, err := yaml.JSONToYAML(j)
+       if err != nil {
+               return nil, err
+       }
+
+       return y, nil
+}
+
+//TagResource with label
+func TagResource(res []byte, label string) ([]byte, error) {
+
+       //Decode the yaml to create a runtime.Object
+       unstruct := &unstructured.Unstructured{}
+       //Ignore the returned obj as we expect the data in unstruct
+       _, err := utils.DecodeYAMLData(string(res), unstruct)
+       if err != nil {
+               return nil, err
+       }
+       //Add the tracking label to all resources created here
+       labels := unstruct.GetLabels()
+       //Check if labels exist for this object
+       if labels == nil {
+               labels = map[string]string{}
+       }
+       //labels[config.GetConfiguration().KubernetesLabelName] = client.GetInstanceID()
+       labels["emco/deployment-id"] = label
+       unstruct.SetLabels(labels)
+
+       // This checks if the resource we are creating has a podSpec in it
+       // Eg: Deployment, StatefulSet, Job etc..
+       // If a PodSpec is found, the label will be added to it too.
+       //connector.TagPodsIfPresent(unstruct, client.GetInstanceID())
+       TagPodsIfPresent(unstruct, label)
+       b, err := unstruct.MarshalJSON()
+       if err != nil {
+               return nil, err
+       }
+       return b, nil
+}
+
+// TagPodsIfPresent finds the TemplateSpec from any workload
+// object that contains it and changes the spec to include the tag label
+func TagPodsIfPresent(unstruct *unstructured.Unstructured, tag string) {
+       _, found, err := unstructured.NestedMap(unstruct.Object, "spec", "template")
+       if err != nil || !found {
+               return
+       }
+       // extract spec template labels
+       labels, found, err := unstructured.NestedMap(unstruct.Object, "spec", "template", "metadata", "labels")
+       if err != nil {
+               log.Error("TagPodsIfPresent: Error reading the NestMap for template", log.Fields{"unstruct": unstruct, "err": err})
+               return
+       }
+       if labels == nil || !found {
+               labels = make(map[string]interface{})
+       }
+       labels["emco/deployment-id"] = tag
+       if err := unstructured.SetNestedMap(unstruct.Object, labels, "spec", "template", "metadata", "labels"); err != nil {
+               log.Error("Error tagging template with emco label", log.Fields{"err": err})
+       }
+}
diff --git a/central-controller/src/rsync/pkg/status/status.go b/central-controller/src/rsync/pkg/status/status.go
deleted file mode 100644 (file)
index c4779bc..0000000
+++ /dev/null
@@ -1,220 +0,0 @@
-// SPDX-License-Identifier: Apache-2.0
-// Copyright (c) 2020 Intel Corporation
-
-package status
-
-import (
-       "encoding/json"
-       "fmt"
-       "strings"
-       "sync"
-
-       yaml "github.com/ghodss/yaml"
-       pkgerrors "github.com/pkg/errors"
-       "github.com/sirupsen/logrus"
-
-       v1alpha1 "github.com/open-ness/EMCO/src/monitor/pkg/apis/k8splugin/v1alpha1"
-       clientset "github.com/open-ness/EMCO/src/monitor/pkg/generated/clientset/versioned"
-       informers "github.com/open-ness/EMCO/src/monitor/pkg/generated/informers/externalversions"
-       appcontext "github.com/open-ness/EMCO/src/orchestrator/pkg/appcontext"
-       "github.com/open-ness/EMCO/src/rsync/pkg/connector"
-       "github.com/open-ness/EMCO/src/rsync/pkg/grpc/readynotifyserver"
-       metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
-       "k8s.io/client-go/tools/cache"
-       "k8s.io/client-go/tools/clientcmd"
-)
-
-type channelManager struct {
-       channels map[string]chan struct{}
-       sync.Mutex
-}
-
-var channelData channelManager
-
-const monitorLabel = "emco/deployment-id"
-
-// HandleStatusUpdate for an application in a cluster
-func HandleStatusUpdate(clusterId string, id string, v *v1alpha1.ResourceBundleState) {
-       // Get the contextId from the label (id)
-       result := strings.SplitN(id, "-", 2)
-       logrus.Info("::HandleStatusUpdate id::", id)
-       logrus.Info("::HandleStatusUpdate result::", result)
-       if result[0] == "" {
-               logrus.Info(clusterId, "::label is missing an appcontext identifier::", id)
-               return
-       }
-
-       if len(result) != 2 {
-               logrus.Info(clusterId, "::invalid label format::", id)
-               return
-       }
-
-       // Get the app from the label (id)
-       if result[1] == "" {
-               logrus.Info(clusterId, "::label is missing an app identifier::", id)
-               return
-       }
-
-       // Look up the contextId
-       var ac appcontext.AppContext
-       _, err := ac.LoadAppContext(result[0])
-       if err != nil {
-               logrus.Info(clusterId, "::App context not found::", result[0], "::Error::", err)
-               return
-       }
-
-       // Produce yaml representation of the status
-       vjson, err := json.Marshal(v.Status)
-       if err != nil {
-               logrus.Info(clusterId, "::Error marshalling status information::", err)
-               return
-       }
-
-       chandle, err := ac.GetClusterHandle(result[1], clusterId)
-       if err != nil {
-               logrus.Info(clusterId, "::Error getting cluster handle::", err)
-               return
-       }
-       // Get the handle for the context/app/cluster status object
-       handle, _ := ac.GetLevelHandle(chandle, "status")
-
-       // If status handle was not found, then create the status object in the appcontext
-       if handle == nil {
-               ac.AddLevelValue(chandle, "status", string(vjson))
-       } else {
-               ac.UpdateStatusValue(handle, string(vjson))
-       }
-
-       // Send notification to the subscribers
-       err = readynotifyserver.SendAppContextNotification(result[0])
-       if err != nil {
-               logrus.Error(clusterId, "::Error sending ReadyNotify to subscribers::", err)
-       }
-}
-
-// StartClusterWatcher watches for CR
-// configBytes - Kubectl file data
-func StartClusterWatcher(clusterId string) error {
-
-       // a cluster watcher always watches the cluster as a whole, so rsync's CloudConfig level
-       // is 0 and namespace doesn't need to be specified because the result is non-ambiguous
-       configBytes, err := connector.GetKubeConfig(clusterId, "0", "")
-       if err != nil {
-               return err
-       }
-
-       //key := provider + "+" + name
-       // Get the lock
-       channelData.Lock()
-       defer channelData.Unlock()
-       // For first time
-       if channelData.channels == nil {
-               channelData.channels = make(map[string]chan struct{})
-       }
-       _, ok := channelData.channels[clusterId]
-       if !ok {
-               // Create Channel
-               channelData.channels[clusterId] = make(chan struct{})
-               // Create config
-               config, err := clientcmd.RESTConfigFromKubeConfig(configBytes)
-               if err != nil {
-                       logrus.Info(fmt.Sprintf("RESTConfigFromKubeConfig error: %s", err.Error()))
-                       return pkgerrors.Wrap(err, "RESTConfigFromKubeConfig error")
-               }
-               k8sClient, err := clientset.NewForConfig(config)
-               if err != nil {
-                       return pkgerrors.Wrap(err, "Clientset NewForConfig error")
-               }
-               // Create Informer
-               mInformerFactory := informers.NewSharedInformerFactory(k8sClient, 0)
-               mInformer := mInformerFactory.K8splugin().V1alpha1().ResourceBundleStates().Informer()
-               go scheduleStatus(clusterId, channelData.channels[clusterId], mInformer)
-       }
-       return nil
-}
-
-// StopClusterWatcher stop watching a cluster
-func StopClusterWatcher(clusterId string) {
-       //key := provider + "+" + name
-       if channelData.channels != nil {
-               c, ok := channelData.channels[clusterId]
-               if ok {
-                       close(c)
-               }
-       }
-}
-
-// CloseAllClusterWatchers close all channels
-func CloseAllClusterWatchers() {
-       if channelData.channels == nil {
-               return
-       }
-       // Close all Channels to stop all watchers
-       for _, e := range channelData.channels {
-               close(e)
-       }
-}
-
-// Per Cluster Go routine to watch CR
-func scheduleStatus(clusterId string, c <-chan struct{}, s cache.SharedIndexInformer) {
-       handlers := cache.ResourceEventHandlerFuncs{
-               AddFunc: func(obj interface{}) {
-                       v, ok := obj.(*v1alpha1.ResourceBundleState)
-                       if ok {
-                               labels := v.GetLabels()
-                               l, ok := labels[monitorLabel]
-                               if ok {
-                                       HandleStatusUpdate(clusterId, l, v)
-                               }
-                       }
-               },
-               UpdateFunc: func(oldObj, obj interface{}) {
-                       v, ok := obj.(*v1alpha1.ResourceBundleState)
-                       if ok {
-                               labels := v.GetLabels()
-                               l, ok := labels[monitorLabel]
-                               if ok {
-                                       HandleStatusUpdate(clusterId, l, v)
-                               }
-                       }
-               },
-               DeleteFunc: func(obj interface{}) {
-                       // Ignore it
-               },
-       }
-       s.AddEventHandler(handlers)
-       s.Run(c)
-}
-
-// GetStatusCR returns a status monitoring customer resource
-func GetStatusCR(label string) ([]byte, error) {
-
-       var statusCr v1alpha1.ResourceBundleState
-
-       statusCr.TypeMeta.APIVersion = "k8splugin.io/v1alpha1"
-       statusCr.TypeMeta.Kind = "ResourceBundleState"
-       statusCr.SetName(label)
-
-       labels := make(map[string]string)
-       labels["emco/deployment-id"] = label
-       statusCr.SetLabels(labels)
-
-       labelSelector, err := metav1.ParseToLabelSelector("emco/deployment-id = " + label)
-       if err != nil {
-               return nil, err
-       }
-       statusCr.Spec.Selector = labelSelector
-
-       // Marshaling to json then convert to yaml works better than marshaling to yaml
-       // The 'apiVersion' attribute was marshaling to 'apiversion'
-       j, err := json.Marshal(&statusCr)
-       if err != nil {
-               return nil, err
-       }
-       y, err := yaml.JSONToYAML(j)
-       if err != nil {
-               return nil, err
-       }
-
-       return y, nil
-}
diff --git a/central-controller/src/rsync/pkg/status/status_test.go b/central-controller/src/rsync/pkg/status/status_test.go
new file mode 100644 (file)
index 0000000..7daf5d8
--- /dev/null
@@ -0,0 +1,87 @@
+package status_test
+
+import (
+       "io/ioutil"
+       "testing"
+
+       rb "gitlab.com/project-emco/core/emco-base/src/monitor/pkg/apis/k8splugin/v1alpha1"
+       "gitlab.com/project-emco/core/emco-base/src/orchestrator/pkg/appcontext"
+       "gitlab.com/project-emco/core/emco-base/src/orchestrator/pkg/infra/contextdb"
+       "gitlab.com/project-emco/core/emco-base/src/rsync/pkg/context"
+       "gitlab.com/project-emco/core/emco-base/src/rsync/pkg/internal/utils"
+       "gitlab.com/project-emco/core/emco-base/src/rsync/pkg/status"
+       . "gitlab.com/project-emco/core/emco-base/src/rsync/pkg/types"
+
+       "k8s.io/api/core/v1"
+)
+
+func init() {
+       edb := new(contextdb.MockConDb)
+       edb.Err = nil
+       contextdb.Db = edb
+}
+
+var rbfile, _ = ioutil.ReadFile("test/test.yaml")
+
+var TestCA CompositeApp = CompositeApp{
+       CompMetadata: appcontext.CompositeAppMeta{Project: "proj1", CompositeApp: "ca1", Version: "v1", Release: "r1",
+               DeploymentIntentGroup: "dig1", Namespace: "default", Level: "0"},
+       AppOrder: []string{"collectd"},
+       Apps: map[string]*App{"collectd": {
+               Name: "collectd",
+               Clusters: map[string]*Cluster{"provider1+cluster1": {
+                       Name: "provider1+cluster1",
+                       Resources: map[string]*AppResource{"r1": {Name: "r1", Data: "a1c1r1"},
+                               "r2": {Name: "r2", Data: "a1c1r2"},
+                       },
+                       ResOrder: []string{"r1", "r2"}}},
+       },
+       },
+}
+
+func TestAppReadyOnAllClusters(t *testing.T) {
+       // Read in test data
+
+       data := &rb.ResourceBundleState{}
+       _, err := utils.DecodeYAMLData(string(rbfile), data)
+       if err != nil {
+               return
+       }
+       cid, _ := context.CreateCompApp(TestCA)
+
+       testCases := []struct {
+               label                  string
+               expectedValue          bool
+               podReady               v1.ConditionStatus
+               updatedNumberScheduled int32
+       }{
+               {
+                       label:                  "AppReadyOnAllClusters Success Case",
+                       expectedValue:          true,
+                       updatedNumberScheduled: 1,
+                       podReady:               v1.ConditionTrue,
+               },
+               {
+                       label:                  "AppReadyOnAllClusters Daemonset not ready",
+                       expectedValue:          false,
+                       updatedNumberScheduled: 0,
+                       podReady:               v1.ConditionTrue,
+               },
+               {
+                       label:                  "AppReadyOnAllClusters Pod not ready",
+                       expectedValue:          false,
+                       updatedNumberScheduled: 1,
+                       podReady:               v1.ConditionFalse,
+               },
+       }
+       for _, testCase := range testCases {
+               t.Run(testCase.label, func(t *testing.T) {
+                       data.Status.DaemonSetStatuses[0].Status.UpdatedNumberScheduled = testCase.updatedNumberScheduled
+                       data.Status.PodStatuses[0].Status.Conditions[1].Status = testCase.podReady
+                       val := status.UpdateAppReadyStatus(cid, "collectd", "provider1+cluster1", data)
+                       if val != testCase.expectedValue {
+                               t.Fatalf("TestAppReadyOnAllClusters Failed")
+                       }
+               })
+       }
+}
diff --git a/central-controller/src/rsync/pkg/status/test/test.yaml b/central-controller/src/rsync/pkg/status/test/test.yaml
new file mode 100644 (file)
index 0000000..287c007
--- /dev/null
@@ -0,0 +1,276 @@
+apiVersion: k8splugin.io/v1alpha1
+kind: ResourceBundleState
+metadata:
+  name: 5738075950853499756-collectd
+  namespace: default
+  resourceVersion: "10638140"
+  selfLink: /apis/k8splugin.io/v1alpha1/namespaces/default/resourcebundlestates/5738075950853499756-collectd
+  uid: 9beed5a4-7148-4ee2-bb3a-3713562c02dd
+spec:
+  selector:
+    matchLabels:
+      emco/deployment-id: 5738075950853499756-collectd
+status:
+  configMapStatuses:
+  - apiVersion: v1
+    kind: ConfigMap
+    metadata:
+      creationTimestamp: "2021-11-22T20:27:12Z"
+      labels:
+        emco/deployment-id: 5738075950853499756-collectd
+      name: info-cm
+      namespace: default
+      resourceVersion: "10638104"
+      selfLink: /api/v1/namespaces/default/configmaps/info-cm
+      uid: d388f37c-a094-4fad-bfd8-1ab07fdf84ed
+  - apiVersion: v1
+    kind: ConfigMap
+    metadata:
+      creationTimestamp: "2021-11-22T20:27:10Z"
+      labels:
+        app: collectd
+        chart: collectd-0.2.0
+        emco/deployment-id: 5738075950853499756-collectd
+        release: r6
+      name: r6-collectd-config
+      namespace: default
+      resourceVersion: "10638087"
+      selfLink: /api/v1/namespaces/default/configmaps/r6-collectd-config
+      uid: dd2986f4-3f1f-41fe-856b-ab78ab86e9c9
+  csrStatuses: []
+  daemonSetStatuses:
+  - apiVersion: apps/v1
+    kind: DaemonSet
+    metadata:
+      annotations:
+        checksum/config: 0952c8535863755990ab5103e45c26fddc33a59b00be9fb949b40368314e877c
+        deprecated.daemonset.template.generation: "1"
+      creationTimestamp: "2021-11-22T20:27:10Z"
+      generation: 1
+      labels:
+        app: collectd
+        chart: collectd-0.2.0
+        emco/deployment-id: 5738075950853499756-collectd
+        release: r6
+      name: r6-collectd
+      namespace: default
+      resourceVersion: "10638101"
+      selfLink: /apis/apps/v1/namespaces/default/daemonsets/r6-collectd
+      uid: 21eca93d-b006-4e09-af47-afcd6f8a4d56
+    spec:
+      revisionHistoryLimit: 10
+      selector:
+        matchLabels:
+          app: collectd
+          collector: collectd
+          release: r6
+      template:
+        metadata:
+          creationTimestamp: null
+          labels:
+            app: collectd
+            collector: collectd
+            emco/deployment-id: 5738075950853499756-collectd
+            release: r6
+        spec:
+          containers:
+          - image: opnfv/barometer-collectd:latest
+            imagePullPolicy: IfNotPresent
+            name: collectd
+            resources: {}
+            securityContext:
+              allowPrivilegeEscalation: true
+              privileged: true
+            terminationMessagePath: /dev/termination-log
+            terminationMessagePolicy: File
+            volumeMounts:
+            - mountPath: /opt/collectd/etc
+              name: r6-collectd-config
+            - mountPath: /mnt/proc
+              name: proc
+              readOnly: true
+            - mountPath: /hostfs
+              name: root
+              readOnly: true
+            - mountPath: /mnt/etc
+              name: etc
+              readOnly: true
+            - mountPath: /var/run/docker.sock
+              name: run
+          dnsPolicy: ClusterFirst
+          hostNetwork: true
+          restartPolicy: Always
+          schedulerName: default-scheduler
+          securityContext: {}
+          terminationGracePeriodSeconds: 30
+          volumes:
+          - configMap:
+              defaultMode: 484
+              name: r6-collectd-config
+            name: r6-collectd-config
+          - hostPath:
+              path: /proc
+              type: ""
+            name: proc
+          - hostPath:
+              path: /
+              type: ""
+            name: root
+          - hostPath:
+              path: /etc
+              type: ""
+            name: etc
+          - hostPath:
+              path: /var/run/docker.sock
+              type: ""
+            name: run
+      updateStrategy:
+        rollingUpdate:
+          maxUnavailable: 1
+        type: RollingUpdate
+    status:
+      currentNumberScheduled: 1
+      desiredNumberScheduled: 1
+      numberAvailable: 1
+      numberMisscheduled: 0
+      numberReady: 1
+      observedGeneration: 1
+      updatedNumberScheduled: 1
+  deploymentStatuses: []
+  ingressStatuses: []
+  jobStatuses: []
+  podStatuses:
+  - apiVersion: v1
+    kind: Pod
+    metadata:
+      annotations:
+        container.apparmor.security.beta.kubernetes.io/collectd: runtime/default
+        kubernetes.io/psp: restricted
+        seccomp.security.alpha.kubernetes.io/pod: runtime/default
+      creationTimestamp: "2021-11-22T20:27:11Z"
+      generateName: r6-collectd-
+      labels:
+        app: collectd
+        collector: collectd
+        controller-revision-hash: 7d78fdd5d8
+        emco/deployment-id: 5738075950853499756-collectd
+        pod-template-generation: "1"
+        release: r6
+      name: r6-collectd-p9n45
+      namespace: default
+      ownerReferences:
+      - apiVersion: apps/v1
+        blockOwnerDeletion: true
+        controller: true
+        kind: DaemonSet
+        name: r6-collectd
+        uid: 21eca93d-b006-4e09-af47-afcd6f8a4d56
+      resourceVersion: "10638105"
+      selfLink: /api/v1/namespaces/default/pods/r6-collectd-p9n45
+      uid: a5a88727-5a3a-4295-9cb2-6edf2a794185
+    spec:
+      affinity:
+        nodeAffinity:
+          requiredDuringSchedulingIgnoredDuringExecution:
+            nodeSelectorTerms:
+            - matchFields:
+              - key: metadata.name
+                operator: In
+                values:
+                - localhost
+      containers:
+      - image: opnfv/barometer-collectd:latest
+        imagePullPolicy: IfNotPresent
+        name: collectd
+        resources: {}
+        securityContext:
+          allowPrivilegeEscalation: true
+          capabilities:
+            drop:
+            - NET_RAW
+          privileged: true
+        terminationMessagePath: /dev/termination-log
+        terminationMessagePolicy: File
+      dnsPolicy: ClusterFirst
+      enableServiceLinks: true
+      hostNetwork: true
+      nodeName: localhost
+      priority: 0
+      restartPolicy: Always
+      schedulerName: default-scheduler
+      securityContext: {}
+      serviceAccount: default
+      serviceAccountName: default
+      terminationGracePeriodSeconds: 30
+    status:
+      conditions:
+      - lastProbeTime: null
+        lastTransitionTime: "2021-11-22T20:27:11Z"
+        status: "True"
+        type: Initialized
+      - lastProbeTime: null
+        lastTransitionTime: "2021-11-22T20:27:19Z"
+        status: "True"
+        type: Ready
+      - lastProbeTime: null
+        lastTransitionTime: "2021-11-22T20:27:19Z"
+        status: "True"
+        type: ContainersReady
+      - lastProbeTime: null
+        lastTransitionTime: "2021-11-22T20:27:11Z"
+        status: "True"
+        type: PodScheduled
+      containerStatuses:
+      - containerID: docker://7d2fc26b1489ab0304526276ab3f721587b5d059e7a9ed4a962a80b692f8031f
+        image: opnfv/barometer-collectd:latest
+        imageID: docker-pullable://opnfv/barometer-collectd@sha256:5424d11948e4d2ef265800d7ab19bd087da600d76e681a5e18d8847f159c6785
+        lastState: {}
+        name: collectd
+        ready: true
+        restartCount: 0
+        started: true
+        state:
+          running:
+            startedAt: "2021-11-22T20:27:19Z"
+      hostIP: 192.168.121.109
+      phase: Running
+      podIP: 192.168.121.109
+      podIPs:
+      - ip: 192.168.121.109
+      qosClass: BestEffort
+      startTime: "2021-11-22T20:27:11Z"
+  ready: false
+  resourceCount: 0
+  secretStatuses: []
+  serviceStatuses:
+  - apiVersion: v1
+    kind: Service
+    metadata:
+      annotations:
+        kubectl.kubernetes.io/last-applied-configuration: |
+          {"apiVersion":"v1","kind":"Service","metadata":{"annotations":{},"labels":{"app":"collectd","emco/deployment-id":"5738075950853499756-collectd","release":"r6"},"name":"collectd","namespace":"default"},"spec":{"ports":[{"name":"collectd-prometheus","port":9104,"protocol":"TCP","targetPort":9103}],"selector":{"app":"collectd","collector":"collectd"},"type":"ClusterIP"}}
+      creationTimestamp: "2021-11-22T20:27:10Z"
+      labels:
+        app: collectd
+        emco/deployment-id: 5738075950853499756-collectd
+        release: r6
+      name: collectd
+      namespace: default
+      resourceVersion: "10638089"
+      selfLink: /api/v1/namespaces/default/services/collectd
+      uid: d2129cff-6d9a-4d39-83c8-13b3aaecf940
+    spec:
+      clusterIP: 10.244.17.224
+      ports:
+      - name: collectd-prometheus
+        port: 9104
+        protocol: TCP
+        targetPort: 9103
+      selector:
+        app: collectd
+        collector: collectd
+      sessionAffinity: None
+      type: ClusterIP
+    status:
+      loadBalancer: {}
+  statefulSetStatuses: []
diff --git a/central-controller/src/rsync/pkg/types/types.go b/central-controller/src/rsync/pkg/types/types.go
new file mode 100644 (file)
index 0000000..0adb584
--- /dev/null
@@ -0,0 +1,257 @@
+// SPDX-License-Identifier: Apache-2.0
+// Copyright (c) 2020 Intel Corporation
+
+package types
+
+import (
+       "context"
+       "k8s.io/apimachinery/pkg/runtime/schema"
+
+       "gitlab.com/project-emco/core/emco-base/src/orchestrator/pkg/appcontext"
+)
+
+const (
+       CurrentStateKey         string = "rsync/state/CurrentState"
+       DesiredStateKey         string = "rsync/state/DesiredState"
+       PendingTerminateFlagKey string = "rsync/state/PendingTerminateFlag"
+       AppContextEventQueueKey string = "rsync/AppContextEventQueue"
+       StatusKey               string = "status"
+       StopFlagKey             string = "stopflag"
+       StatusAppContextIDKey   string = "statusappctxid"
+)
+
+// RsyncEvent is event Rsync handles
+type RsyncEvent string
+
+// Rsync Event types
+const (
+       InstantiateEvent     RsyncEvent = "Instantiate"
+       TerminateEvent       RsyncEvent = "Terminate"
+       ReadEvent            RsyncEvent = "Read"
+       AddChildContextEvent RsyncEvent = "AddChildContext"
+       UpdateEvent          RsyncEvent = "Update"
+       // This is an internal event
+       UpdateDeleteEvent RsyncEvent = "UpdateDelete"
+)
+
+// RsyncOperation is operation Rsync handles
+type RsyncOperation int
+
+// Rsync Operations
+const (
+       OpApply RsyncOperation = iota
+       OpDelete
+       OpRead
+       OpCreate
+)
+
+// ResourceStatusType defines types of resource statuses
+type ResourceStatusType string
+
+// ResourceStatusType
+const (
+       ReadyStatus   ResourceStatusType = "resready"
+       SuccessStatus ResourceStatusType = "ressuccess"
+)
+
+func (d RsyncOperation) String() string {
+       return [...]string{"Apply", "Delete", "Read"}[d]
+}
+
+// StateChange represents a state change rsync handles
+type StateChange struct {
+       // Name of the event
+       Event RsyncEvent
+       // List of states that can handle this event
+       SState []appcontext.StatusValue
+       // Dst state if the state transition was successful
+       DState appcontext.StatusValue
+       // Current state if the state transition was successful
+       CState appcontext.StatusValue
+       // Error state if the state transition was unsuccessful
+       ErrState appcontext.StatusValue
+}
+
+// StateChanges represent State Machine for the AppContext
+var StateChanges = map[RsyncEvent]StateChange{
+
+       InstantiateEvent: StateChange{
+               SState: []appcontext.StatusValue{
+                       appcontext.AppContextStatusEnum.Created,
+                       appcontext.AppContextStatusEnum.Instantiated,
+                       appcontext.AppContextStatusEnum.InstantiateFailed,
+                       appcontext.AppContextStatusEnum.Instantiating},
+               DState:   appcontext.AppContextStatusEnum.Instantiated,
+               CState:   appcontext.AppContextStatusEnum.Instantiating,
+               ErrState: appcontext.AppContextStatusEnum.InstantiateFailed,
+       },
+       TerminateEvent: StateChange{
+               SState: []appcontext.StatusValue{
+                       appcontext.AppContextStatusEnum.InstantiateFailed,
+                       appcontext.AppContextStatusEnum.Instantiating,
+                       appcontext.AppContextStatusEnum.Instantiated,
+                       appcontext.AppContextStatusEnum.TerminateFailed,
+                       appcontext.AppContextStatusEnum.Terminating,
+                       appcontext.AppContextStatusEnum.Updated,
+                       appcontext.AppContextStatusEnum.UpdateFailed,
+                       appcontext.AppContextStatusEnum.Updating,
+               },
+               DState:   appcontext.AppContextStatusEnum.Terminated,
+               CState:   appcontext.AppContextStatusEnum.Terminating,
+               ErrState: appcontext.AppContextStatusEnum.TerminateFailed,
+       },
+       UpdateEvent: StateChange{
+               SState: []appcontext.StatusValue{
+                       appcontext.AppContextStatusEnum.Created,
+                       appcontext.AppContextStatusEnum.Updated},
+               DState:   appcontext.AppContextStatusEnum.Instantiated,
+               CState:   appcontext.AppContextStatusEnum.Instantiating,
+               ErrState: appcontext.AppContextStatusEnum.InstantiateFailed,
+       },
+       UpdateDeleteEvent: StateChange{
+               SState: []appcontext.StatusValue{
+                       appcontext.AppContextStatusEnum.Instantiated},
+               DState:   appcontext.AppContextStatusEnum.Updated,
+               CState:   appcontext.AppContextStatusEnum.Updating,
+               ErrState: appcontext.AppContextStatusEnum.UpdateFailed,
+       },
+       ReadEvent: StateChange{
+               SState: []appcontext.StatusValue{
+                       appcontext.AppContextStatusEnum.Created,
+                       appcontext.AppContextStatusEnum.Instantiated,
+                       appcontext.AppContextStatusEnum.InstantiateFailed,
+                       appcontext.AppContextStatusEnum.Instantiating},
+               DState:   appcontext.AppContextStatusEnum.Instantiated,
+               CState:   appcontext.AppContextStatusEnum.Instantiating,
+               ErrState: appcontext.AppContextStatusEnum.InstantiateFailed,
+       },
+}
+
+// Resource Dependency Structures
+// RsyncEvent is event Rsync handles
+type OpStatus string
+
+// OpStatus types
+const (
+       OpStatusDeployed OpStatus = "Deployed"
+       OpStatusReady    OpStatus = "Ready"
+       OpStatusDeleted  OpStatus = "Deleted"
+)
+
+type Resource struct {
+       App string                  `json:"app,omitempty"`
+       Res string                  `json:"name,omitempty"`
+       GVK schema.GroupVersionKind `json:"gvk,omitempty"`
+}
+
+// Criteria for Resource dependency
+type Criteria struct {
+       // Ready or deployed
+       OpStatus OpStatus `json:"opstatus,omitempty"`
+       // Wait time in seconds
+       Wait int `json:"wait,omitempty"`
+}
+
+type AppCriteria struct {
+       App string `json:"app"`
+       // Ready or deployed
+       OpStatus OpStatus `json:"opstatus,omitempty"`
+       // Wait time in seconds
+       Wait int `json:"wait,omitempty"`
+}
+
+// Dependency Structures
+type Dependency struct {
+       Resource Resource `json:"resource,omitempty"`
+       Criteria Criteria `json:"criteria,omitempty"`
+}
+
+// ResourceDependency structure
+type ResourceDependency struct {
+       Resource Resource     `json:"resource,omitempty"`
+       Dep      []Dependency `json:"dependency,omitempty"`
+}
+
+// CompositeApp Structures
+type CompositeApp struct {
+       Name         string                      `json:"name,omitempty"`
+       CompMetadata appcontext.CompositeAppMeta `json:"compmetadat,omitempty"`
+       AppOrder     []string                    `json:"appOrder,omitempty"`
+       Apps         map[string]*App             `json:"apps,omitempty"`
+}
+
+// AppResource represents a resource
+type AppResource struct {
+       Name string      `json:"name,omitempty"`
+       Data interface{} `json:"data,omitempty"`
+       // Needed to suport updates
+       Skip bool `json:"bool,omitempty"`
+}
+
+// Cluster is a cluster within an App
+type Cluster struct {
+       Name       string                  `json:"name,omitempty"`
+       ResOrder   []string                `json:"reorder,omitempty"`
+       Resources  map[string]*AppResource `json:"resources,omitempty"`
+       Dependency map[string][]string     `json:"resdependency,omitempty"`
+       // Needed to suport updates
+       Skip bool `json:"bool,omitempty"`
+}
+
+// App is an app within a composite app
+type App struct {
+       Name       string               `json:"name,omitempty"`
+       Clusters   map[string]*Cluster  `json:"clusters,omitempty"`
+       Dependency map[string]*Criteria `json:"dependency,omitempty"`
+       // Needed to suport updates
+       Skip bool `json:"bool,omitempty"`
+}
+
+// ResourceProvider is interface for working with the resources
+type ResourceProvider interface {
+       Create(name string, ref interface{}, content []byte) (interface{}, error)
+       Apply(name string, ref interface{}, content []byte) (interface{}, error)
+       Delete(name string, ref interface{}, content []byte) (interface{}, error)
+       Get(name string, gvkRes []byte) ([]byte, error)
+       Commit(ctx context.Context, ref interface{}) error
+       IsReachable() error
+       TagResource([]byte, string) ([]byte, error)
+}
+
+type StatusProvider interface {
+       StartClusterWatcher() error
+       ApplyStatusCR(name string, content []byte) error
+       DeleteStatusCR(name string, content []byte) error
+}
+
+type ReferenceProvider interface {
+       ApplyConfig(ctx context.Context, config interface{}) error
+       DeleteConfig(ctx context.Context, config interface{}) error
+}
+
+// Client Provider provides functionality to interface with the cluster
+type ClientProvider interface {
+       ResourceProvider
+       StatusProvider
+       ReferenceProvider
+       CleanClientProvider() error
+}
+
+// Connection is interface for connection
+type Connector interface {
+       GetClientProviders(app, cluster, level, namespace string) (ClientProvider, error)
+}
+
+// AppContextQueueElement element in per AppContext Queue
+type AppContextQueueElement struct {
+       Event RsyncEvent `json:"event"`
+       // Only valid in case of update events
+       UCID string `json:"uCID,omitempty"`
+       // Status - Pending, Done, Error, skip
+       Status string `json:"status"`
+}
+
+// AppContextQueue per AppContext queue
+type AppContextQueue struct {
+       AcQueue []AppContextQueueElement
+}
diff --git a/central-controller/src/rsync/ref-schemas/v1.yaml b/central-controller/src/rsync/ref-schemas/v1.yaml
new file mode 100644 (file)
index 0000000..a79697f
--- /dev/null
@@ -0,0 +1,129 @@
+name: emco-base
+resources:
+#emco-clm
+  - name: clusterProvider
+  - name: cluster
+    parent: clusterProvider
+  - name: clusterLabel
+    parent: cluster
+  - name: clusterKv
+    parent: cluster
+  - name: clusterSyncObject
+    parent: clusterProvider
+#emco-dcm
+  - name: logicalCloud
+    parent: project
+  - name: clusterReference
+    parent: logicalCloud
+    references:
+      - name: cluster
+  - name: clusterQuota
+    parent: logicalCloud
+  - name: logicalCloudKv
+    parent: logicalCloud
+  - name: userPermission
+    parent: logicalCloud
+#emco-dtc
+  - name: trafficGroupIntent
+    parent: deploymentIntentGroup
+  - name: inboundServerIntent
+    parent: trafficGroupIntent
+    references:
+      - name: app
+  - name: inboundClientsIntent
+    parent: inboundServerIntent
+    references:
+      - name: app
+#emco-gac
+  - name: genericK8sIntent
+    parent: deploymentIntentGroup
+  - name: genericResource
+    parent: genericK8sIntent
+    references:
+      - name: app
+  - name: customization
+    parent: genericResource
+    references:
+      - name: cluster
+#emco-hpa-plc
+  - name: hpaIntent
+    parent: deploymentIntentGroup
+    references:
+      - name: app
+  - name: hpaConsumer
+    parent: hpaIntent
+  - name: hpaResource
+    parent: hpaConsumer
+#emco-ncm
+  - name: providerNetwork
+    parent: cluster
+  - name: network
+    parent: cluster
+#emco-orchestrator
+  - name: controllerGroup.controller
+  - name: project
+  - name: compositeApp.compositeAppVersion
+    parent: project
+  - name: app
+    parent: compositeAppVersion
+  - name: compositeProfile
+    parent: compositeAppVersion
+  - name: appProfile
+    parent: compositeProfile
+    references:
+      - name: app
+  - name: deploymentIntentGroup
+    parent: compositeAppVersion
+    references:
+      - name: logicalCloud
+      - name: compositeProfile
+  - name: groupIntent
+    parent: deploymentIntentGroup
+    references:
+      - name: controller
+        type: map
+        map: intent
+        fixedKv:
+          controllerGroup: orchestrator
+        filterKeys:
+          - genericPlacementIntent
+  - name: genericPlacementIntent
+    parent: deploymentIntentGroup
+  - name: genericAppPlacementIntent
+    parent: genericPlacementIntent
+    references:
+      - name: app
+      - name: cluster
+        type: many
+  - name: appDependency
+    parent: app
+#emco-ovnaction
+  - name: netControllerIntent
+    parent: deploymentIntentGroup
+  - name: workloadIntent
+    parent: netControllerIntent
+    references:
+      - name: app
+  - name: interfaceIntent
+    parent: workloadIntent
+#emco-sfc
+  - name: sfcIntent
+    parent: deploymentIntentGroup
+  - name: sfcLink
+    parent: sfcIntent
+    references:
+      - name: app
+  - name: sfcClientSelector
+    parent: sfcIntent
+  - name: sfcProviderNetwork
+    parent: sfcIntent
+#emco-sfc-client
+  - name: sfcClientIntent
+    parent: deploymentIntentGroup
+    references:
+      - name: sfcIntent
+      - name: app
+        commonKey: compositeAppVersion
+#emco-workflowmgr
+  - name: workflowIntent
+    parent: deploymentIntentGroup
diff --git a/central-controller/src/rsync/scripts/Dockerfile b/central-controller/src/rsync/scripts/Dockerfile
deleted file mode 100644 (file)
index a4f4696..0000000
+++ /dev/null
@@ -1,24 +0,0 @@
-# SPDX-License-Identifier: Apache-2.0
-# Copyright (c) 2020 Intel Corporation
-
-FROM ubuntu:18.04
-
-ARG HTTP_PROXY=${HTTP_PROXY}
-ARG HTTPS_PROXY=${HTTPS_PROXY}
-
-ENV http_proxy $HTTP_PROXY
-ENV https_proxy $HTTPS_PROXY
-ENV no_proxy $NO_PROXY
-
-EXPOSE 9016
-
-RUN groupadd -r onap && useradd -r -g onap onap
-
-WORKDIR /opt/multicloud/k8s/rsync
-RUN chown onap:onap /opt/multicloud/k8s/rsync -R
-
-ADD --chown=onap ./rsync ./
-
-USER onap
-
-CMD ["./rsync"]
index b7be3e8..ce5592d 100644 (file)
@@ -70,7 +70,9 @@ func NewRouter(
        deviceCNFObjectClient manager.ControllerObjectManager,
        ipRangeObjectClient manager.ControllerObjectManager,
        providerIpRangeObjectClient manager.ControllerObjectManager,
-       certificateObjectClient manager.ControllerObjectManager) *mux.Router {
+       certificateObjectClient manager.ControllerObjectManager,
+       deviceSiteObjectClient manager.ControllerObjectManager,
+       clusterSyncObjectClient manager.ControllerObjectManager) *mux.Router {
 
        router := mux.NewRouter()
        ver := "v1"
@@ -146,6 +148,13 @@ func NewRouter(
        mgrset.DeviceCNF = deviceCNFObjectClient.(*manager.CNFObjectManager)
        createHandlerMapping(deviceCNFObjectClient, devRouter, manager.CNFCollection, manager.CNFResource)
 
+       // device-site API
+       if deviceSiteObjectClient == nil {
+               deviceSiteObjectClient = manager.NewDeviceSiteObjectManager()
+       }
+       mgrset.DeviceSite = deviceSiteObjectClient.(*manager.DeviceSiteObjectManager)
+       createHandlerMapping(deviceSiteObjectClient, devRouter, manager.SiteCollection, manager.SiteResource)
+
        // provider iprange API
        if providerIpRangeObjectClient == nil {
                providerIpRangeObjectClient = manager.NewIPRangeObjectManager(true)
@@ -167,6 +176,13 @@ func NewRouter(
        mgrset.Cert = certificateObjectClient.(*manager.CertificateObjectManager)
        createHandlerMapping(certificateObjectClient, olRouter, manager.CertCollection, manager.CertResource)
 
+       // cluster-sync-objects API
+       if clusterSyncObjectClient == nil {
+               clusterSyncObjectClient = manager.NewClusterSyncObjectManager()
+       }
+       mgrset.ClusterSync = clusterSyncObjectClient.(*manager.ClusterSyncObjectManager)
+       createHandlerMapping(clusterSyncObjectClient, olRouter, manager.ClusterSyncCollection, manager.ClusterSyncResource)
+
        // create resource object manager
        mgrset.Resource = manager.NewResourceObjectManager()
 
@@ -176,6 +192,7 @@ func NewRouter(
        overlayObjectClient.AddOwnResManager(deviceObjectClient)
        overlayObjectClient.AddOwnResManager(ipRangeObjectClient)
        overlayObjectClient.AddOwnResManager(certificateObjectClient)
+       overlayObjectClient.AddOwnResManager(clusterSyncObjectClient)
        hubObjectClient.AddOwnResManager(hubDeviceObjectClient)
        deviceObjectClient.AddOwnResManager(hubDeviceObjectClient)
 
@@ -184,11 +201,13 @@ func NewRouter(
        deviceObjectClient.AddDepResManager(overlayObjectClient)
        ipRangeObjectClient.AddDepResManager(overlayObjectClient)
        certificateObjectClient.AddDepResManager(overlayObjectClient)
+       clusterSyncObjectClient.AddDepResManager(overlayObjectClient)
        hubDeviceObjectClient.AddDepResManager(hubObjectClient)
        hubConnObjectClient.AddDepResManager(hubObjectClient)
        deviceConnObjectClient.AddDepResManager(deviceObjectClient)
        hubCNFObjectClient.AddDepResManager(hubObjectClient)
        deviceCNFObjectClient.AddDepResManager(deviceObjectClient)
+       deviceSiteObjectClient.AddDepResManager(deviceObjectClient)
 
        return router
 }
index 0f4ca22..3834e1c 100644 (file)
@@ -26,13 +26,13 @@ import (
        "github.com/akraino-edge-stack/icn-sdwan/central-controller/src/scc/api"
        "github.com/akraino-edge-stack/icn-sdwan/central-controller/src/scc/pkg/manager"
        "github.com/gorilla/handlers"
-       "github.com/open-ness/EMCO/src/orchestrator/pkg/infra/auth"
-       "github.com/open-ness/EMCO/src/orchestrator/pkg/infra/config"
-       contextDb "github.com/open-ness/EMCO/src/orchestrator/pkg/infra/contextdb"
-       "github.com/open-ness/EMCO/src/orchestrator/pkg/infra/db"
-       logs "github.com/open-ness/EMCO/src/orchestrator/pkg/infra/logutils"
-       controller "github.com/open-ness/EMCO/src/orchestrator/pkg/module/controller"
-       mtypes "github.com/open-ness/EMCO/src/orchestrator/pkg/module/types"
+       "gitlab.com/project-emco/core/emco-base/src/orchestrator/pkg/infra/auth"
+       "gitlab.com/project-emco/core/emco-base/src/orchestrator/pkg/infra/config"
+       contextDb "gitlab.com/project-emco/core/emco-base/src/orchestrator/pkg/infra/contextdb"
+       "gitlab.com/project-emco/core/emco-base/src/orchestrator/pkg/infra/db"
+       logs "gitlab.com/project-emco/core/emco-base/src/orchestrator/pkg/infra/logutils"
+       controller "gitlab.com/project-emco/core/emco-base/src/orchestrator/pkg/module/controller"
+       mtypes "gitlab.com/project-emco/core/emco-base/src/orchestrator/pkg/module/types"
 
        rconfig "github.com/akraino-edge-stack/icn-sdwan/central-controller/src/scc/pkg/infra/config"
 )
@@ -97,7 +97,7 @@ func main() {
                })
        }
 
-       client := controller.NewControllerClient()
+       client := controller.NewControllerClient("resources", "data", "orchestrator")
 
        // Create or update the controller entry
        rsync_port, _ := strconv.Atoi(rconfig.GetConfiguration().RsyncPort)
@@ -121,7 +121,7 @@ func main() {
        }
 
        // create http server
-       httpRouter := api.NewRouter(nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil)
+       httpRouter := api.NewRouter(nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil)
        loggedRouter := handlers.LoggingHandler(os.Stdout, httpRouter)
        log.Println("Starting SDEWAN Central Controller API")
 
index dde2cb2..a330a56 100644 (file)
@@ -2,70 +2,78 @@ module github.com/akraino-edge-stack/icn-sdwan/central-controller/src/scc
 
 require (
        github.com/go-playground/validator/v10 v10.4.1
-       github.com/gorilla/handlers v0.0.0-20150720190736-60c7bfde3e33
+       github.com/gorilla/handlers v1.3.0
        github.com/gorilla/mux v1.7.2
        github.com/jetstack/cert-manager v1.2.0
        github.com/matryer/runner v0.0.0-20190427160343-b472a46105b1
-       github.com/open-ness/EMCO/src/orchestrator v0.0.0-00010101000000-000000000000
-       github.com/open-ness/EMCO/src/rsync v0.0.0-00010101000000-000000000000
        github.com/pkg/errors v0.9.1
-       k8s.io/api v0.20.2
-       k8s.io/apimachinery v0.20.2
+       gitlab.com/project-emco/core/emco-base/src/orchestrator v0.0.0-00010101000000-000000000000
+       gitlab.com/project-emco/core/emco-base/src/rsync v0.0.0-00010101000000-000000000000
+       k8s.io/api v0.23.3
+       k8s.io/apimachinery v0.23.3
        k8s.io/client-go v12.0.0+incompatible
-       sigs.k8s.io/yaml v1.2.0
+       sigs.k8s.io/yaml v1.3.0
 )
 
 require (
        github.com/cheekybits/is v0.0.0-20150225183255-68e9c0620927 // indirect
        github.com/coreos/etcd v3.3.13+incompatible // indirect
        github.com/davecgh/go-spew v1.1.1 // indirect
-       github.com/go-logr/logr v0.2.1 // indirect
+       github.com/go-logr/logr v1.2.2 // indirect
        github.com/go-playground/locales v0.13.0 // indirect
        github.com/go-playground/universal-translator v0.17.0 // indirect
        github.com/go-stack/stack v1.8.0 // indirect
-       github.com/gogo/protobuf v1.3.1 // indirect
-       github.com/golang/protobuf v1.4.2 // indirect
+       github.com/gogo/protobuf v1.3.2 // indirect
+       github.com/golang/protobuf v1.5.2 // indirect
        github.com/golang/snappy v0.0.1 // indirect
        github.com/google/gofuzz v1.2.0 // indirect
-       github.com/googleapis/gnostic v0.4.1 // indirect
-       github.com/imdario/mergo v0.3.11 // indirect
-       github.com/json-iterator/go v1.1.10 // indirect
+       github.com/googleapis/gnostic v0.5.5 // indirect
+       github.com/imdario/mergo v0.3.12 // indirect
+       github.com/json-iterator/go v1.1.12 // indirect
+       github.com/klauspost/compress v1.13.6 // indirect
        github.com/leodido/go-urn v1.2.0 // indirect
        github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
-       github.com/modern-go/reflect2 v1.0.1 // indirect
-       github.com/sirupsen/logrus v1.7.0 // indirect
+       github.com/modern-go/reflect2 v1.0.2 // indirect
+       github.com/sirupsen/logrus v1.8.1 // indirect
        github.com/spf13/pflag v1.0.5 // indirect
-       github.com/xdg/scram v0.0.0-20180814205039-7eeb5667e42c // indirect
-       github.com/xdg/stringprep v1.0.0 // indirect
+       github.com/tidwall/gjson v1.14.0 // indirect
+       github.com/tidwall/match v1.1.1 // indirect
+       github.com/tidwall/pretty v1.2.0 // indirect
+       github.com/xdg-go/pbkdf2 v1.0.0 // indirect
+       github.com/xdg-go/scram v1.0.2 // indirect
+       github.com/xdg-go/stringprep v1.0.2 // indirect
        github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f // indirect
        github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415 // indirect
-       github.com/xeipuuv/gojsonschema v1.1.0 // indirect
+       github.com/xeipuuv/gojsonschema v1.2.0 // indirect
+       github.com/youmark/pkcs8 v0.0.0-20181117223130-1be2e3e5546d // indirect
        go.etcd.io/etcd v3.3.12+incompatible // indirect
-       go.mongodb.org/mongo-driver v1.1.2 // indirect
-       golang.org/x/crypto v0.0.0-20201221181555-eec23a3978ad // indirect
-       golang.org/x/net v0.0.0-20200822124328-c89045814202 // indirect
-       golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d // indirect
-       golang.org/x/sync v0.0.0-20201207232520-09787c993a3a // indirect
-       golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c // indirect
-       golang.org/x/term v0.0.0-20201117132131-f5c789dd3221 // indirect
-       golang.org/x/text v0.3.3 // indirect
-       golang.org/x/time v0.0.0-20200630173020-3af7569d3a1e // indirect
-       google.golang.org/appengine v1.6.5 // indirect
-       google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013 // indirect
-       google.golang.org/grpc v1.28.0 // indirect
-       google.golang.org/protobuf v1.24.0 // indirect
+       go.mongodb.org/mongo-driver v1.8.4 // indirect
+       golang.org/x/crypto v0.0.0-20211215153901-e495a2d5b3d3 // indirect
+       golang.org/x/net v0.0.0-20220127200216-cd36cc0744dd // indirect
+       golang.org/x/oauth2 v0.0.0-20210819190943-2bc19b11175f // indirect
+       golang.org/x/sync v0.0.0-20210220032951-036812b2e83c // indirect
+       golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e // indirect
+       golang.org/x/term v0.0.0-20210927222741-03fcf44c2211 // indirect
+       golang.org/x/text v0.3.7 // indirect
+       golang.org/x/time v0.0.0-20210723032227-1f47c861a9ac // indirect
+       google.golang.org/appengine v1.6.7 // indirect
+       google.golang.org/genproto v0.0.0-20210831024726-fe130286e0e2 // indirect
+       google.golang.org/grpc v1.43.0 // indirect
+       google.golang.org/protobuf v1.27.1 // indirect
        gopkg.in/inf.v0 v0.9.1 // indirect
-       gopkg.in/yaml.v2 v2.3.0 // indirect
-       k8s.io/apiextensions-apiserver v0.20.2 // indirect
-       k8s.io/klog/v2 v2.4.0 // indirect
-       k8s.io/utils v0.0.0-20200729134348-d5654de09c73 // indirect
-       sigs.k8s.io/structured-merge-diff/v4 v4.0.2 // indirect
+       gopkg.in/yaml.v2 v2.4.0 // indirect
+       gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b // indirect
+       k8s.io/apiextensions-apiserver v0.23.3 // indirect
+       k8s.io/klog/v2 v2.30.0 // indirect
+       k8s.io/utils v0.0.0-20211208161948-7d6a63dca704 // indirect
+       sigs.k8s.io/structured-merge-diff/v4 v4.2.1 // indirect
 )
 
 replace (
-       github.com/open-ness/EMCO/src/monitor => ../monitor
-       github.com/open-ness/EMCO/src/orchestrator => ../vendor/github.com/open-ness/EMCO/src/orchestrator
-       github.com/open-ness/EMCO/src/rsync => ../rsync
+       gitlab.com/project-emco/core/emco-base/src/monitor => ../monitor
+       gitlab.com/project-emco/core/emco-base/src/orchestrator => ../vendor/gitlab.com/project-emco/core/emco-base/src/orchestrator
+       gitlab.com/project-emco/core/emco-base/src/rsync => ../rsync
+       google.golang.org/grpc => google.golang.org/grpc v1.29.0
        k8s.io/api => k8s.io/api v0.19.0
        k8s.io/apiextensions-apiserver => k8s.io/apiextensions-apiserver v0.19.0
        k8s.io/apimachinery => k8s.io/apimachinery v0.19.0
index d19576b..ac8f7f1 100644 (file)
@@ -1,40 +1,44 @@
-bazil.org/fuse v0.0.0-20160811212531-371fbbdaa898/go.mod h1:Xbm+BRKSBEpa4q4hTSxohYNQpsxXPbPry4JJWOB3LB8=
-cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
 cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
-cloud.google.com/go v0.37.4/go.mod h1:NHPJ89PdicEuT9hdPXMROBD91xc5uRDxsMtSB16k7hw=
 cloud.google.com/go v0.38.0/go.mod h1:990N+gfupTy94rShfmMCWGDn0LpTmnzTp2qbd1dvSRU=
 cloud.google.com/go v0.44.1/go.mod h1:iSa0KzasP4Uvy3f1mN/7PiObzGgflwredwwASm/v6AU=
 cloud.google.com/go v0.44.2/go.mod h1:60680Gw3Yr4ikxnPRS/oxxkBccT6SA1yMk63TGekxKY=
 cloud.google.com/go v0.45.1/go.mod h1:RpBamKRgapWJb87xiFSdk4g1CME7QZg3uwTez+TSTjc=
 cloud.google.com/go v0.46.3/go.mod h1:a6bKKbmY7er1mI7TEI4lsAkts/mkhTSZK8w33B4RAg0=
-cloud.google.com/go v0.49.0/go.mod h1:hGvAdzcWNbyuxS3nWhD7H2cIJxjRRTRLQVB0bdputVY=
+cloud.google.com/go v0.50.0/go.mod h1:r9sluTvynVuxRIOHXQEHMFffphuXHOMZMycpNR5e6To=
 cloud.google.com/go v0.51.0/go.mod h1:hWtGJ6gnXH+KgDv+V0zFGDvpi07n3z8ZNj3T1RW0Gcw=
+cloud.google.com/go v0.52.0/go.mod h1:pXajvRH/6o3+F9jDHZWQ5PbGhn+o8w9qiu/CffaVdO4=
+cloud.google.com/go v0.53.0/go.mod h1:fp/UouUEsRkN6ryDKNW/Upv/JBKnv6WDthjR6+vze6M=
+cloud.google.com/go v0.54.0/go.mod h1:1rq2OEkV3YMf6n/9ZvGWI3GWw0VoqH/1x2nd8Is/bPc=
+cloud.google.com/go v0.56.0/go.mod h1:jr7tqZxxKOVYizybht9+26Z/gUq7tiRzu+ACVAMbKVk=
+cloud.google.com/go v0.57.0/go.mod h1:oXiQ6Rzq3RAkkY7N6t3TcE6jE+CIBBbA36lwQ1JyzZs=
+cloud.google.com/go v0.62.0/go.mod h1:jmCYTdRCQuc1PHIIJ/maLInMho30T/Y0M4hTdTShOYc=
+cloud.google.com/go v0.65.0/go.mod h1:O5N8zS7uWy9vkA9vayVHs65eM1ubvY4h553ofrNHObY=
 cloud.google.com/go/bigquery v1.0.1/go.mod h1:i/xbL2UlR5RvWAURpBYZTtm/cXjCha9lbfbpx4poX+o=
 cloud.google.com/go/bigquery v1.3.0/go.mod h1:PjpwJnslEMmckchkHFfq+HTD2DmtT67aNFKH1/VBDHE=
+cloud.google.com/go/bigquery v1.4.0/go.mod h1:S8dzgnTigyfTmLBfrtrhyYhwRxG72rYxvftPBK2Dvzc=
+cloud.google.com/go/bigquery v1.5.0/go.mod h1:snEHRnqQbz117VIFhE8bmtwIDY80NLUZUMb4Nv6dBIg=
+cloud.google.com/go/bigquery v1.7.0/go.mod h1://okPTzCYNXSlb24MZs83e2Do+h+VXtc4gLoIoXIAPc=
+cloud.google.com/go/bigquery v1.8.0/go.mod h1:J5hqkt3O0uAFnINi6JXValWIb1v0goeZM77hZzJN/fQ=
 cloud.google.com/go/datastore v1.0.0/go.mod h1:LXYbyblFSglQ5pkeyhO+Qmw7ukd3C+pD7TKLgZqpHYE=
+cloud.google.com/go/datastore v1.1.0/go.mod h1:umbIZjpQpHh4hmRpGhH4tLFup+FVzqBi1b3c64qFpCk=
 cloud.google.com/go/firestore v1.1.0/go.mod h1:ulACoGHTpvq5r8rxGJ4ddJZBZqakUQqClKRT5SZwBmk=
 cloud.google.com/go/pubsub v1.0.1/go.mod h1:R0Gpsv3s54REJCy4fxDixWD93lHJMoZTyQ2kNxGRt3I=
+cloud.google.com/go/pubsub v1.1.0/go.mod h1:EwwdRX2sKPjnvnqCa270oGRyludottCI76h+R3AArQw=
+cloud.google.com/go/pubsub v1.2.0/go.mod h1:jhfEVHT8odbXTkndysNHCcx0awwzvfOlguIAii9o8iA=
+cloud.google.com/go/pubsub v1.3.1/go.mod h1:i+ucay31+CNRpDW4Lu78I4xXG+O1r/MAHgjpRVR+TSU=
 cloud.google.com/go/storage v1.0.0/go.mod h1:IhtSnM/ZTZV8YYJWCY8RULGVqBDmpoyjwiyrjsg+URw=
-cloud.google.com/go/storage v1.3.0/go.mod h1:9IAwXhoyBJ7z9LcAwkj0/7NnPzYaPeZxxVp3zm+5IqA=
-contrib.go.opencensus.io/exporter/ocagent v0.6.0/go.mod h1:zmKjrJcdo0aYcVS7bmEeSEBLPA9YJp5bjrofdU3pIXs=
+cloud.google.com/go/storage v1.5.0/go.mod h1:tpKbwo567HUNpVclU5sGELwQWBDZ8gh0ZeosJ0Rtdos=
+cloud.google.com/go/storage v1.6.0/go.mod h1:N7U0C8pVQ/+NIKOBQyamJIeKQKkZ+mxpohlUTyfDhBk=
+cloud.google.com/go/storage v1.8.0/go.mod h1:Wv1Oy7z6Yz3DshWRJFhqM/UCfaWIRTdp0RXyy7KQOVs=
+cloud.google.com/go/storage v1.10.0/go.mod h1:FLPqc6j+Ki4BU591ie1oL6qBQGu2Bl/tZ9ullr3+Kg0=
 dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU=
-github.com/Azure/azure-pipeline-go v0.2.1/go.mod h1:UGSo8XybXnIGZ3epmeBw7Jdz+HiUVpqIlpz/HKHylF4=
-github.com/Azure/azure-pipeline-go v0.2.2/go.mod h1:4rQ/NZncSvGqNkkOsNpOU1tgoNuIlp9AfUH5G1tvCHc=
-github.com/Azure/azure-sdk-for-go v16.2.1+incompatible/go.mod h1:9XXNKU+eRnpl9moKnB4QOLf1HestfXbmab5FXxiDBjc=
-github.com/Azure/azure-sdk-for-go v23.2.0+incompatible/go.mod h1:9XXNKU+eRnpl9moKnB4QOLf1HestfXbmab5FXxiDBjc=
-github.com/Azure/azure-sdk-for-go v36.1.0+incompatible/go.mod h1:9XXNKU+eRnpl9moKnB4QOLf1HestfXbmab5FXxiDBjc=
 github.com/Azure/azure-sdk-for-go v46.3.0+incompatible/go.mod h1:9XXNKU+eRnpl9moKnB4QOLf1HestfXbmab5FXxiDBjc=
-github.com/Azure/azure-storage-blob-go v0.8.0/go.mod h1:lPI3aLPpuLTeUwh1sViKXFxwl2B6teiRqI0deQUvsw0=
 github.com/Azure/go-ansiterm v0.0.0-20170929234023-d6e3b3328b78/go.mod h1:LmzpDX56iTiv29bbRTIsUNlaFfuhWRQBWjQdVyAevI8=
-github.com/Azure/go-autorest v10.8.1+incompatible/go.mod h1:r+4oMnoxhatjLLJ6zxSWATqVooLgysK6ZNox3g/xq24=
-github.com/Azure/go-autorest v11.2.8+incompatible/go.mod h1:r+4oMnoxhatjLLJ6zxSWATqVooLgysK6ZNox3g/xq24=
 github.com/Azure/go-autorest v14.2.0+incompatible/go.mod h1:r+4oMnoxhatjLLJ6zxSWATqVooLgysK6ZNox3g/xq24=
 github.com/Azure/go-autorest/autorest v0.9.0/go.mod h1:xyHB1BMZT0cuDHU7I0+g046+BFDTQ8rEZB0s4Yfa6bI=
-github.com/Azure/go-autorest/autorest v0.9.3-0.20191028180845-3492b2aff503/go.mod h1:xyHB1BMZT0cuDHU7I0+g046+BFDTQ8rEZB0s4Yfa6bI=
 github.com/Azure/go-autorest/autorest v0.9.6/go.mod h1:/FALq9T/kS7b5J5qsQ+RSTUdAmGFqi0vUdVNNx8q630=
 github.com/Azure/go-autorest/autorest v0.11.6/go.mod h1:V6p3pKZx1KKkJubbxnDWrzNhEIfOy/pTGasLqzHIPHs=
 github.com/Azure/go-autorest/autorest/adal v0.5.0/go.mod h1:8Z9fGy2MpX0PvDjB1pEgQTmVqjGhiHBW7RJJEciWzS0=
-github.com/Azure/go-autorest/autorest/adal v0.8.1-0.20191028180845-3492b2aff503/go.mod h1:Z6vX6WXXuyieHAXwMj0S6HY6e6wcHn37qQMBQlvY3lc=
 github.com/Azure/go-autorest/autorest/adal v0.8.2/go.mod h1:ZjhuQClTqx435SRJ2iMlOxPYt3d2C/T/7TiQCVZSn3Q=
 github.com/Azure/go-autorest/autorest/adal v0.9.4/go.mod h1:/3SMAM86bP6wC9Ev35peQDUeqFZBMH07vvUOmg4z/fE=
 github.com/Azure/go-autorest/autorest/date v0.1.0/go.mod h1:plvfp3oPSKwf2DNjlBjWF/7vwR+cUD/ELuzDCXwHUVA=
@@ -44,9 +48,7 @@ github.com/Azure/go-autorest/autorest/mocks v0.1.0/go.mod h1:OTyCOPRA2IgIlWxVYxB
 github.com/Azure/go-autorest/autorest/mocks v0.2.0/go.mod h1:OTyCOPRA2IgIlWxVYxBee2F5Gr4kF2zd2J5cFRaIDN0=
 github.com/Azure/go-autorest/autorest/mocks v0.3.0/go.mod h1:a8FDP3DYzQ4RYfVAxAN3SVSiiO77gL2j2ronKKP0syM=
 github.com/Azure/go-autorest/autorest/mocks v0.4.1/go.mod h1:LTp+uSrOhSkaKrUy935gNZuuIPPVsHlr9DSOxSayd+k=
-github.com/Azure/go-autorest/autorest/to v0.3.1-0.20191028180845-3492b2aff503/go.mod h1:MgwOyqaIuKdG4TL/2ywSsIWKAfJfgHDo8ObuUk3t5sA=
 github.com/Azure/go-autorest/autorest/to v0.4.0/go.mod h1:fE8iZBn7LQR7zH/9XU2NcPR4o9jEImooCeWJcYV/zLE=
-github.com/Azure/go-autorest/autorest/validation v0.2.1-0.20191028180845-3492b2aff503/go.mod h1:3EEqHnBxQGHXRYq3HT1WyXAvT7LLY3tl70hw6tQIbjI=
 github.com/Azure/go-autorest/autorest/validation v0.3.0/go.mod h1:yhLgjC0Wda5DYXl6JAsWyUe4KVNffhoDhG0zVzUMo3E=
 github.com/Azure/go-autorest/logger v0.1.0/go.mod h1:oExouG+K6PryycPJfVSxi/koC6LSNgds39diKLz7Vrc=
 github.com/Azure/go-autorest/logger v0.2.0/go.mod h1:T9E3cAhj2VqvPOtCYAvby9aBXkZmbF5NWuPV8+WeEW8=
@@ -54,83 +56,38 @@ github.com/Azure/go-autorest/tracing v0.5.0/go.mod h1:r/s2XiOKccPW3HrqB+W0TQzfbt
 github.com/Azure/go-autorest/tracing v0.6.0/go.mod h1:+vhtPC754Xsa23ID7GlGsrdKBpUA79WCAKPPZVC2DeU=
 github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
 github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo=
-github.com/DATA-DOG/go-sqlmock v1.4.1/go.mod h1:f/Ixk793poVmq4qj/V1dPUg2JEAKC73Q5eFN3EC/SaM=
-github.com/DataDog/datadog-go v3.2.0+incompatible/go.mod h1:LButxg5PwREeZtORoXG3tL4fMGNddJ+vMq1mwgfaqoQ=
 github.com/MakeNowJust/heredoc v0.0.0-20170808103936-bb23615498cd/go.mod h1:64YHyfSL2R96J44Nlwm39UHepQbyR5q10x7iYa1ks2E=
-github.com/Masterminds/goutils v1.1.0/go.mod h1:8cTjp+g8YejhMuvIA5y2vz3BpJxksy863GQaJW2MFNU=
-github.com/Masterminds/semver/v3 v3.1.0/go.mod h1:VPu/7SZ7ePZ3QOrcuXROw5FAcLl4a0cBrbBpGY/8hQs=
-github.com/Masterminds/sprig/v3 v3.1.0/go.mod h1:ONGMf7UfYGAbMXCZmQLy8x3lCDIPrEZE/rU8pmrbihA=
-github.com/Masterminds/squirrel v1.2.0/go.mod h1:yaPeOnPG5ZRwL9oKdTsO/prlkPbXWZlRVMQ/gGlzIuA=
-github.com/Masterminds/vcs v1.13.1/go.mod h1:N09YCmOQr6RLxC6UNHzuVwAdodYbbnycGHSmwVJjcKA=
-github.com/Microsoft/go-winio v0.4.11/go.mod h1:VhR8bwka0BXejwEJY73c50VrPtXAaKcyvVC4A4RozmA=
-github.com/Microsoft/go-winio v0.4.15-0.20190919025122-fc70bd9a86b5/go.mod h1:tTuCMEN+UleMWgg9dVx4Hu52b1bJo+59jBh3ajtinzw=
-github.com/Microsoft/hcsshim v0.8.7/go.mod h1:OHd7sQqRFrYd3RmSgbgji+ctCwkbq2wbEYNSzOYtcBQ=
-github.com/Microsoft/hcsshim v0.8.9/go.mod h1:5692vkUqntj1idxauYlpoINNKeqCiG6Sg38RRsjT5y8=
 github.com/NYTimes/gziphandler v0.0.0-20170623195520-56545f4a5d46/go.mod h1:3wb06e3pkSAbeQ52E9H9iFoQsEEwGN64994WTCIhntQ=
-github.com/NYTimes/gziphandler v1.1.1/go.mod h1:n/CVRwUEOgIxrgPvAQhUUr9oeUtvrhMomdKFjzJNB0c=
-github.com/Nvveen/Gotty v0.0.0-20120604004816-cd527374f1e5/go.mod h1:lmUJ/7eu/Q8D7ML55dXQrVaamCz2vxCfdQBasLZfHKk=
 github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU=
-github.com/OneOfOne/xxhash v1.2.6/go.mod h1:eZbhyaAYD41SGSSsnmcpxVoRiQ/MPUTjUdIIOT9Um7Q=
 github.com/PuerkitoBio/purell v1.0.0/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbtSwDGJws/X0=
 github.com/PuerkitoBio/purell v1.1.0/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbtSwDGJws/X0=
 github.com/PuerkitoBio/purell v1.1.1/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbtSwDGJws/X0=
 github.com/PuerkitoBio/urlesc v0.0.0-20160726150825-5bd2802263f2/go.mod h1:uGdkoq3SwY9Y+13GIhn11/XLaGBb4BfwItxLd5jeuXE=
 github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578/go.mod h1:uGdkoq3SwY9Y+13GIhn11/XLaGBb4BfwItxLd5jeuXE=
-github.com/Shopify/logrus-bugsnag v0.0.0-20171204204709-577dee27f20d/go.mod h1:HI8ITrYtUY+O+ZhtlqUnD8+KwNPOyugEhfP9fdUIaEQ=
-github.com/Shopify/sarama v1.19.0/go.mod h1:FVkBWblsNy7DGZRfXLU0O9RCGt5g3g3yEuWXgklEdEo=
-github.com/Shopify/toxiproxy v2.1.4+incompatible/go.mod h1:OXgGpZ6Cli1/URJOF1DMxUHB2q5Ap20/P/eIdh4G0pI=
 github.com/Venafi/vcert/v4 v4.11.0/go.mod h1:OE+UZ0cj8qqVUuk0u7R4GIk4ZB6JMSf/WySqnBPNwws=
 github.com/agnivade/levenshtein v1.0.1/go.mod h1:CURSv5d9Uaml+FovSIICkLbAUZ9S4RqaHDIsdSBg7lM=
 github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
 github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
 github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=
 github.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=
-github.com/alecthomas/units v0.0.0-20190924025748-f65c72e2690d/go.mod h1:rBZYJk541a8SKzHPHnH3zbiI+7dagKZ0cgpgrD7Fyho=
-github.com/aliyun/aliyun-oss-go-sdk v2.0.4+incompatible/go.mod h1:T/Aws4fEfogEE9v+HPhhw+CntffsBHJ8nXQCwKr0/g8=
 github.com/andreyvit/diff v0.0.0-20170406064948-c7f18ee00883/go.mod h1:rCTlJbsFo29Kk6CurOXKm700vrz8f0KW0JNfpkRJY/8=
-github.com/antihax/optional v0.0.0-20180407024304-ca021399b1a6/go.mod h1:V8iCPQYkqmusNa815XgQio277wI47sdRh1dUOLdyC6Q=
-github.com/apache/thrift v0.12.0/go.mod h1:cp2SuWMxlEZw2r+iP2GNCdIi4C1qmUzdZFSVb+bacwQ=
 github.com/armon/circbuf v0.0.0-20150827004946-bbbad097214e/go.mod h1:3U/XgcO3hCbHZ8TKRvWD2dDTCfh9M9ya+I9JpbB7O8o=
 github.com/armon/consul-api v0.0.0-20180202201655-eb2c6b5be1b6/go.mod h1:grANhF5doyWs3UAsr3K4I6qtAmlQcZDesFNEHPZAzj8=
 github.com/armon/go-metrics v0.0.0-20180917152333-f0300d1749da/go.mod h1:Q73ZrmVTwzkszR9V5SSuryQ31EELlFMUz1kKyl939pY=
-github.com/armon/go-metrics v0.3.0/go.mod h1:zXjbSimjXTd7vOpY8B0/2LpvNvDoXBuplAD+gJD3GYs=
 github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8=
-github.com/armon/go-radix v1.0.0/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8=
 github.com/asaskevich/govalidator v0.0.0-20180720115003-f9ffefc3facf/go.mod h1:lB+ZfQJz7igIIfQNfa7Ml4HSf2uFQQRzpGGRXenZAgY=
 github.com/asaskevich/govalidator v0.0.0-20190424111038-f61b66f89f4a/go.mod h1:lB+ZfQJz7igIIfQNfa7Ml4HSf2uFQQRzpGGRXenZAgY=
-github.com/asaskevich/govalidator v0.0.0-20200108200545-475eaeb16496/go.mod h1:oGkLhpf+kjZl6xBf758TQhh5XrAeiJv/7FRz/2spLIg=
-github.com/aws/aws-sdk-go v1.15.11/go.mod h1:mFuSZ37Z9YOHbQEwBWztmVzqXrEkub65tZoCYDt7FT0=
-github.com/aws/aws-sdk-go v1.17.7/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo=
-github.com/aws/aws-sdk-go v1.25.48/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo=
 github.com/aws/aws-sdk-go v1.34.30/go.mod h1:H7NKnBqNVzoTJpGfLrQkkD+ytBA93eiDYi/+8rV9s48=
-github.com/baiyubin/aliyun-sts-go-sdk v0.0.0-20180326062324-cfa1a18b161f/go.mod h1:AuiFmCCPBSrqvVMvuqFuk0qogytodnVFVSN5CeJB8Gc=
-github.com/beorn7/perks v0.0.0-20160804104726-4c0e84591b9a/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q=
 github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q=
 github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8=
 github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM=
 github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw=
 github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs=
-github.com/bitly/go-hostpool v0.0.0-20171023180738-a3a6125de932/go.mod h1:NOuUCSz6Q9T7+igc/hlvDOUdtWKryOrtFyIVABv/p7k=
-github.com/bitly/go-simplejson v0.5.0/go.mod h1:cXHtHw4XUPsvGaxgjIAn8PhEWG9NfngEKAMDJEczWVA=
 github.com/bketelsen/crypt v0.0.3-0.20200106085610-5cbc8cc4026c/go.mod h1:MKsuJmJgSg28kpZDP6UIiPt0e0Oz0kqKNGyRaWEPv84=
-github.com/blang/semver v3.1.0+incompatible/go.mod h1:kRBLl5iJ+tD4TcOOxsy/0fnwebNt5EWlYSAyrTnjyyk=
 github.com/blang/semver v3.5.0+incompatible/go.mod h1:kRBLl5iJ+tD4TcOOxsy/0fnwebNt5EWlYSAyrTnjyyk=
-github.com/blang/semver v3.5.1+incompatible/go.mod h1:kRBLl5iJ+tD4TcOOxsy/0fnwebNt5EWlYSAyrTnjyyk=
-github.com/bmizerany/assert v0.0.0-20160611221934-b7ed37b82869/go.mod h1:Ekp36dRnpXw/yCqJaO+ZrUyxD+3VXMFFr56k5XYrpB4=
-github.com/bradfitz/gomemcache v0.0.0-20190913173617-a41fca850d0b/go.mod h1:H0wQNHz2YrLsuXOZozoeDmnHXkNCRmMW0gwFWDfEZDA=
-github.com/brancz/gojsontoyaml v0.0.0-20191212081931-bf2969bbd742/go.mod h1:IyUJYN1gvWjtLF5ZuygmxbnsAyP3aJS6cHzIuZY50B0=
-github.com/brancz/kube-rbac-proxy v0.5.0/go.mod h1:cL2VjiIFGS90Cjh5ZZ8+It6tMcBt8rwvuw2J6Mamnl0=
-github.com/bshuster-repo/logrus-logstash-hook v0.4.1/go.mod h1:zsTqEiSzDgAa/8GZR7E1qaXrhYNDKBYy5/dWPTIflbk=
-github.com/bugsnag/bugsnag-go v0.0.0-20141110184014-b1d153021fcd/go.mod h1:2oa8nejYd4cQ/b0hMIopN0lCRxU0bueqREvZLWFrtK8=
-github.com/bugsnag/osext v0.0.0-20130617224835-0dd3f918b21b/go.mod h1:obH5gd0BsqsP2LwDJ9aOkm/6J86V6lyAXCoQWGw3K50=
-github.com/bugsnag/panicwrap v0.0.0-20151223152923-e2c28503fcd0/go.mod h1:D/8v3kj0zr8ZAKg1AQ6crr+5VwKN5eIywRkfhyM/+dE=
-github.com/campoy/embedmd v1.0.0/go.mod h1:oxyr9RCiSXg0M3VJ3ks0UGfp98BpSSGr0kpiX3MzVl8=
-github.com/cenkalti/backoff v0.0.0-20181003080854-62661b46c409/go.mod h1:90ReRw6GdpyfrHakVjL/QHaoyV4aDUVVkXQJJJ3NXXM=
 github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
-github.com/cespare/xxhash v0.0.0-20181017004759-096ff4a8a059/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc=
 github.com/cespare/xxhash v1.1.0 h1:a6HrQnmkObjyL+Gs60czilIUGqrzKutQD6XZog3p+ko=
 github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc=
-github.com/cespare/xxhash/v2 v2.1.0/go.mod h1:dgIUBU3pDso/gPgZ1osOZ0iQf77oPR28Tjxl5dIMyVM=
 github.com/cespare/xxhash/v2 v2.1.1 h1:6MnRN8NT7+YBpUIWxHtefFZOKTAPgGjpQSxqLNn0+qY=
 github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
 github.com/chai2010/gettext-go v0.0.0-20160711120539-c6fed771bfd5/go.mod h1:/iP1qXHoty45bqomnu2LM+VVyAEdWN+vtSHGlQgyxbw=
@@ -139,28 +96,9 @@ github.com/cheekybits/is v0.0.0-20150225183255-68e9c0620927/go.mod h1:h/aW8ynjgk
 github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI=
 github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI=
 github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU=
-github.com/circonus-labs/circonus-gometrics v2.3.1+incompatible/go.mod h1:nmEj6Dob7S7YxXgwXpfOuvO54S+tGdZdw9fuRZt25Ag=
-github.com/circonus-labs/circonusllhist v0.1.3/go.mod h1:kMXHVDlOchFAehlya5ePtbp5jckzBHf4XRpQvBOLI+I=
-github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
 github.com/cloudflare/cloudflare-go v0.13.2/go.mod h1:27kfc1apuifUmJhp069y0+hwlKDg4bd8LWlu7oKeZvM=
 github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc=
-github.com/cockroachdb/apd v1.1.0/go.mod h1:8Sl8LxpKi29FqWXR16WEFZRNSz3SoPzUzeMeY4+DwBQ=
-github.com/cockroachdb/cockroach-go v0.0.0-20181001143604-e0a95dfd547c/go.mod h1:XGLbWH/ujMcbPbhZq52Nv6UrCghb1yGn//133kEsvDk=
 github.com/cockroachdb/datadriven v0.0.0-20190809214429-80d97fb3cbaa/go.mod h1:zn76sxSg3SzpJ0PPJaLDCu+Bu0Lg3sKTORVIj19EIF8=
-github.com/codahale/hdrhistogram v0.0.0-20161010025455-3a0bb77429bd/go.mod h1:sE/e/2PUdi/liOCUjSTXgM1o87ZssimdTWN964YiIeI=
-github.com/containerd/cgroups v0.0.0-20190919134610-bf292b21730f/go.mod h1:OApqhQ4XNSNC13gXIwDjhOQxjWa/NxkwZXJ1EvqT0ko=
-github.com/containerd/console v0.0.0-20180822173158-c12b1e7919c1/go.mod h1:Tj/on1eG8kiEhd0+fhSDzsPAFESxzBBvdyEgyryXffw=
-github.com/containerd/containerd v1.2.7/go.mod h1:bC6axHOhabU15QhwfG7w5PipXdVtMXFTttgp+kVtyUA=
-github.com/containerd/containerd v1.3.0-beta.2.0.20190828155532-0293cbd26c69/go.mod h1:bC6axHOhabU15QhwfG7w5PipXdVtMXFTttgp+kVtyUA=
-github.com/containerd/containerd v1.3.2/go.mod h1:bC6axHOhabU15QhwfG7w5PipXdVtMXFTttgp+kVtyUA=
-github.com/containerd/continuity v0.0.0-20190426062206-aaeac12a7ffc/go.mod h1:GL3xCUCBDV3CZiTSEKksMWbLE66hEyuu9qyDOOqM47Y=
-github.com/containerd/continuity v0.0.0-20200107194136-26c1120b8d41/go.mod h1:Dq467ZllaHgAtVp4p1xUQWBrFXR9s/wyoTpG8zOJGkY=
-github.com/containerd/continuity v0.0.0-20200413184840-d3ef23f19fbb/go.mod h1:Dq467ZllaHgAtVp4p1xUQWBrFXR9s/wyoTpG8zOJGkY=
-github.com/containerd/fifo v0.0.0-20190226154929-a9fb20d87448/go.mod h1:ODA38xgv3Kuk8dQz2ZQXpnv/UZZUHUCL7pnLehbXgQI=
-github.com/containerd/go-runc v0.0.0-20180907222934-5a6d9f37cfa3/go.mod h1:IV7qH3hrUgRmyYrtgEeGWJfWbgcHL9CSRruz2Vqcph0=
-github.com/containerd/ttrpc v0.0.0-20190828154514-0e0f228740de/go.mod h1:PvCDdDGpgqzQIzDW1TphrGLssLDZp2GuS+X5DkEJB8o=
-github.com/containerd/ttrpc v1.0.1/go.mod h1:UAxOpgT9ziI0gJrmKvgcZivgxOp8iFPSk8httJEt98Y=
-github.com/containerd/typeurl v0.0.0-20180627222232-a93fcdb778cd/go.mod h1:Cm3kwCdlkCfMSHURc+r6fwoGH6/F1hH3S4sg0rLFWPc=
 github.com/coreos/bbolt v1.3.2 h1:wZwiHHUieZCquLkDL0B8UhzreNWsPHooDAG3q34zk0s=
 github.com/coreos/bbolt v1.3.2/go.mod h1:iRUV2dpdMOn7Bo10OQBFzIJO9kkE559Wcmn+qkEiiKk=
 github.com/coreos/etcd v3.3.10+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE=
@@ -176,97 +114,47 @@ github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e/go.mod h1:F5haX7
 github.com/coreos/pkg v0.0.0-20160727233714-3ac0863d7acf/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA=
 github.com/coreos/pkg v0.0.0-20180928190104-399ea9e2e55f h1:lBNOc5arjvs8E5mO2tbpBpLoyyu8B6e44T7hJy6potg=
 github.com/coreos/pkg v0.0.0-20180928190104-399ea9e2e55f/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA=
-github.com/coreos/prometheus-operator v0.38.1-0.20200424145508-7e176fda06cc/go.mod h1:erio69w1R/aC14D5nfvAXSlE8FT8jt2Hnavc50Dp33A=
 github.com/cpu/goacmedns v0.0.3/go.mod h1:4MipLkI+qScwqtVxcNO6okBhbgRrr7/tKXUSgSL0teQ=
 github.com/cpuguy83/go-md2man v1.0.10/go.mod h1:SmD6nW6nTyfqj6ABTjUi3V3JVMnlJmwcJI5acqYI6dE=
 github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU=
 github.com/cpuguy83/go-md2man/v2 v2.0.0/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU=
 github.com/creack/pty v1.1.7/go.mod h1:lj5s0c3V2DBrqTV7llrYr5NG6My20zk30Fl46Y7DoTY=
-github.com/cyphar/filepath-securejoin v0.2.2/go.mod h1:FpkQEhXnPnOthhzymB7CGsFk2G9VLXONKD9G7QGMM+4=
-github.com/cznic/b v0.0.0-20180115125044-35e9bbe41f07/go.mod h1:URriBxXwVq5ijiJ12C7iIZqlA69nTlI+LgI6/pwftG8=
-github.com/cznic/fileutil v0.0.0-20180108211300-6a051e75936f/go.mod h1:8S58EK26zhXSxzv7NQFpnliaOQsmDUxvoQO3rt154Vg=
-github.com/cznic/golex v0.0.0-20170803123110-4ab7c5e190e4/go.mod h1:+bmmJDNmKlhWNG+gwWCkaBoTy39Fs+bzRxVBzoTQbIc=
-github.com/cznic/internal v0.0.0-20180608152220-f44710a21d00/go.mod h1:olo7eAdKwJdXxb55TKGLiJ6xt1H0/tiiRCWKVLmtjY4=
-github.com/cznic/lldb v1.1.0/go.mod h1:FIZVUmYUVhPwRiPzL8nD/mpFcJ/G7SSXjjXYG4uRI3A=
-github.com/cznic/mathutil v0.0.0-20180504122225-ca4c9f2c1369/go.mod h1:e6NPNENfs9mPDVNRekM7lKScauxd5kXTr1Mfyig6TDM=
-github.com/cznic/ql v1.2.0/go.mod h1:FbpzhyZrqr0PVlK6ury+PoW3T0ODUV22OeWIxcaOrSE=
-github.com/cznic/sortutil v0.0.0-20150617083342-4c7342852e65/go.mod h1:q2w6Bg5jeox1B+QkJ6Wp/+Vn0G/bo3f1uY7Fn3vivIQ=
-github.com/cznic/strutil v0.0.0-20171016134553-529a34b1c186/go.mod h1:AHHPPPXTw0h6pVabbcbyGRK1DckRn7r/STdZEeIDzZc=
-github.com/cznic/zappy v0.0.0-20160723133515-2533cb5b45cc/go.mod h1:Y1SNZ4dRUOKXshKUbwUapqNncRrho4mkjQebgEHZLj8=
-github.com/davecgh/go-spew v0.0.0-20151105211317-5215b55f46b2/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
 github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
 github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
 github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
 github.com/daviddengcn/go-colortext v0.0.0-20160507010035-511bcaf42ccd/go.mod h1:dv4zxwHi5C/8AeI+4gX4dCWOIvNi7I6JCSX0HvlKPgE=
-github.com/deislabs/oras v0.8.1/go.mod h1:Mx0rMSbBNaNfY9hjpccEnxkOqJL6KGjtxNHPLC4G4As=
-github.com/denisenkom/go-mssqldb v0.0.0-20190515213511-eb9f6a1743f3/go.mod h1:zAg7JM8CkOJ43xKXIj7eRO9kmWm/TW578qo+oDO6tuM=
-github.com/denisenkom/go-mssqldb v0.0.0-20191001013358-cfbb681360f0/go.mod h1:xbL0rPBG9cCiLr28tMa8zpbdarY27NDyej4t/EjAShU=
-github.com/denverdino/aliyungo v0.0.0-20190125010748-a747050bb1ba/go.mod h1:dV8lFg6daOBZbT6/BDGIz6Y3WFGn8juu6G+CQ6LHtl0=
-github.com/dgrijalva/jwt-go v0.0.0-20170104182250-a601269ab70c/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ=
 github.com/dgrijalva/jwt-go v3.2.0+incompatible h1:7qlOGliEKZXTDg6OTjfoBKDXWrumCAMpl/TFQ4/5kLM=
 github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ=
 github.com/dgryski/go-sip13 v0.0.0-20181026042036-e10d5fee7954/go.mod h1:vAd38F8PWV+bWy6jNmig1y/TA+kYO4g3RSRF0IAv0no=
-github.com/dgryski/go-sip13 v0.0.0-20190329191031-25c5027a8c7b/go.mod h1:vAd38F8PWV+bWy6jNmig1y/TA+kYO4g3RSRF0IAv0no=
-github.com/dhui/dktest v0.3.0/go.mod h1:cyzIUfGsBEbZ6BT7tnXqAShHSXCZhSNmFl70sZ7c1yc=
 github.com/digitalocean/godo v1.44.0/go.mod h1:p7dOjjtSBqCTUksqtA5Fd3uaKs9kyTq2xcz76ulEJRU=
-github.com/dnaeon/go-vcr v1.0.1/go.mod h1:aBB1+wY4s93YsC3HHjMBMrwTj2R9FHDzUr9KyGc8n1E=
-github.com/docker/cli v0.0.0-20200130152716-5d0cf8839492/go.mod h1:JLrzqnKDaYBop7H2jaqPtU4hHvMKP+vjCwu2uszcLI8=
-github.com/docker/distribution v0.0.0-20191216044856-a8371794149d/go.mod h1:0+TTO4EOBfRPhZXAeF1Vu+W3hHZ8eLp8PgKVZlcvtFY=
-github.com/docker/distribution v2.7.0+incompatible/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w=
 github.com/docker/distribution v2.7.1+incompatible/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w=
-github.com/docker/docker v0.7.3-0.20190103212154-2b7e084dc98b/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk=
-github.com/docker/docker v0.7.3-0.20190817195342-4760db040282/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk=
-github.com/docker/docker v1.4.2-0.20200203170920-46ec8731fbce/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk=
-github.com/docker/docker-credential-helpers v0.6.3/go.mod h1:WRaJzqw3CTB9bk10avuGsjVBZsD05qeibJ1/TYlvc0Y=
-github.com/docker/go-connections v0.4.0/go.mod h1:Gbd7IOopHjR8Iph03tsViu4nIes5XhDvyHbTtUxmeec=
-github.com/docker/go-events v0.0.0-20190806004212-e31b211e4f1c/go.mod h1:Uw6UezgYA44ePAFQYUehOuCzmy5zmg/+nl2ZfMWGkpA=
-github.com/docker/go-metrics v0.0.0-20180209012529-399ea8c73916/go.mod h1:/u0gXw0Gay3ceNrsHubL3BtdOL2fHf93USgMTe0W5dI=
 github.com/docker/go-units v0.3.3/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk=
 github.com/docker/go-units v0.4.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk=
-github.com/docker/libtrust v0.0.0-20150114040149-fa567046d9b1/go.mod h1:cyGadeNEkKy96OOhEzfZl+yxihPEzKnqJwvfuSUqbZE=
 github.com/docker/spdystream v0.0.0-20160310174837-449fdfce4d96/go.mod h1:Qh8CwZgvJUkLughtfhJv5dyTYa91l1fOUCrgjqmcifM=
 github.com/docopt/docopt-go v0.0.0-20180111231733-ee0de3bc6815/go.mod h1:WwZ+bS3ebgob9U8Nd0kOddGdZWjyMGR8Wziv+TBNwSE=
 github.com/dustin/go-humanize v0.0.0-20171111073723-bb3d318650d4/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk=
-github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk=
-github.com/eapache/go-resiliency v1.1.0/go.mod h1:kFI+JgMyC7bLPUVY133qvEBtVayf5mFgVsvEsIPBvNs=
-github.com/eapache/go-xerial-snappy v0.0.0-20180814174437-776d5712da21/go.mod h1:+020luEh2TKB4/GOp8oxxtq0Daoen/Cii55CzbTV6DU=
-github.com/eapache/queue v1.1.0/go.mod h1:6eCeP0CKFpHLu8blIFXhExK/dRa7WDZfr6jVFPTqq+I=
-github.com/edsrzf/mmap-go v0.0.0-20170320065105-0bce6a688712/go.mod h1:YO35OhQPt3KJa3ryjFM5Bs14WD66h8eGKpfaBNrHW5M=
-github.com/edsrzf/mmap-go v1.0.0/go.mod h1:YO35OhQPt3KJa3ryjFM5Bs14WD66h8eGKpfaBNrHW5M=
-github.com/elastic/go-sysinfo v1.0.1/go.mod h1:O/D5m1VpYLwGjCYzEt63g3Z1uO3jXfwyzzjiW90t8cY=
-github.com/elastic/go-sysinfo v1.1.1/go.mod h1:i1ZYdU10oLNfRzq4vq62BEwD2fH8KaWh6eh0ikPT9F0=
-github.com/elastic/go-windows v1.0.0/go.mod h1:TsU0Nrp7/y3+VwE82FoZF8gC/XFg/Elz6CcloAxnPgU=
-github.com/elastic/go-windows v1.0.1/go.mod h1:FoVvqWSun28vaDQPbj2Elfc0JahhPB7WQEGa3c814Ss=
 github.com/elazarl/goproxy v0.0.0-20180725130230-947c36da3153/go.mod h1:/Zj4wYkgs4iZTTu3o/KG3Itv/qCCa8VVMlb3i9OVuzc=
 github.com/emicklei/go-restful v0.0.0-20170410110728-ff4f55a20633/go.mod h1:otzb+WCGbkyDHkqmQmT5YD2WR4BBwUdeQoFo8l/7tVs=
 github.com/emicklei/go-restful v2.9.5+incompatible/go.mod h1:otzb+WCGbkyDHkqmQmT5YD2WR4BBwUdeQoFo8l/7tVs=
-github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
-github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
 github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98=
 github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c=
-github.com/evanphx/json-patch v4.1.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk=
 github.com/evanphx/json-patch v4.5.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk=
 github.com/evanphx/json-patch v4.9.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk=
 github.com/exponent-io/jsonpath v0.0.0-20151013193312-d6023ce2651d/go.mod h1:ZZMPRZwes7CROmyNKgQzC3XPs6L/G2EJLHddWejkmf4=
-github.com/facette/natsort v0.0.0-20181210072756-2cd4dd1e2dcb/go.mod h1:bH6Xx7IW64qjjJq8M2u4dxNaBiDfKK+z/3eGDpXEQhc=
 github.com/fatih/camelcase v1.0.0/go.mod h1:yN2Sb0lFhZJUdVvtELVWefmrXpuZESvPmqwoZc+/fpc=
 github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4=
 github.com/fatih/structs v1.1.0/go.mod h1:9NiDSp5zOcgEDl+j00MP/WkGVPOlPRLejGD8Ga6PJ7M=
-github.com/fatih/structtag v1.1.0/go.mod h1:mBJUNpUnHmRKrKlQQlmCrh5PuhftFbNv8Ys4/aAZl94=
-github.com/fortytw2/leaktest v1.3.0/go.mod h1:jDsjWgpAGjm2CA7WthBh/CdZYEPF31XHquHwclZch5g=
 github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
+github.com/fsnotify/fsnotify v1.4.9 h1:hsms1Qyu0jgnwNXIxa+/V/PDsU6CfLf6CNO8H7IWoS4=
 github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ=
-github.com/fsouza/fake-gcs-server v1.7.0/go.mod h1:5XIRs4YvwNbNoz+1JF8j6KLAyDh7RHGAyAK3EP2EsNk=
-github.com/garyburd/redigo v0.0.0-20150301180006-535138d7bcd7/go.mod h1:NR3MbYisc3/PwhQ00EMzDiPmrwpPxAn5GI05/YaO1SY=
 github.com/ghodss/yaml v0.0.0-20150909031657-73d445a93680/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04=
 github.com/ghodss/yaml v1.0.0 h1:wQHKEahhL6wmXdzwWG11gIVCkOv05bNOh+Rxn0yngAk=
 github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04=
 github.com/globalsign/mgo v0.0.0-20180905125535-1ca0a4f7cbcb/go.mod h1:xkRDCp4j0OGD1HRkm4kmhM+pmpv3AKq5SU7GMg4oO/Q=
 github.com/globalsign/mgo v0.0.0-20181015135952-eeefdecb41b8/go.mod h1:xkRDCp4j0OGD1HRkm4kmhM+pmpv3AKq5SU7GMg4oO/Q=
-github.com/go-bindata/go-bindata/v3 v3.1.3/go.mod h1:1/zrpXsLD8YDIbhZRqXzm1Ghc7NhEvIN9+Z6R5/xH4I=
 github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU=
 github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8=
-github.com/go-ini/ini v1.25.4/go.mod h1:ByCAeIL28uOIIG0E3PJtZPDL8WnHpFKFOtgjp+3Ies8=
+github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8=
 github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as=
 github.com/go-kit/kit v0.9.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as=
 github.com/go-ldap/ldap v3.0.2+incompatible/go.mod h1:qfd9rJvER9Q0/D/Sqn1DfHRoBp40uXYvFoEVrNEPqRc=
@@ -275,63 +163,51 @@ github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V
 github.com/go-logr/logr v0.1.0/go.mod h1:ixOQHD9gLJUVQQ2ZOR7zLEifBX6tGkNJF4QyIY7sIas=
 github.com/go-logr/logr v0.2.0/go.mod h1:z6/tIYblkpsD+a4lm/fGIIU9mZ+XfAiaFtq7xTgseGU=
 github.com/go-logr/logr v0.2.1-0.20200730175230-ee2de8da5be6/go.mod h1:z6/tIYblkpsD+a4lm/fGIIU9mZ+XfAiaFtq7xTgseGU=
-github.com/go-logr/logr v0.2.1 h1:fV3MLmabKIZ383XifUjFSwcoGee0v9qgPp8wy5svibE=
-github.com/go-logr/logr v0.2.1/go.mod h1:z6/tIYblkpsD+a4lm/fGIIU9mZ+XfAiaFtq7xTgseGU=
+github.com/go-logr/logr v1.2.0/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A=
+github.com/go-logr/logr v1.2.2 h1:ahHml/yUpnlb96Rp8HCvtYVPY8ZYpxq3g7UYchIYwbs=
+github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A=
 github.com/go-logr/zapr v0.1.0/go.mod h1:tabnROwaDl0UNxkVeFRbY8bwB37GwRv0P8lg6aAiEnk=
 github.com/go-logr/zapr v0.1.1/go.mod h1:tabnROwaDl0UNxkVeFRbY8bwB37GwRv0P8lg6aAiEnk=
-github.com/go-logr/zapr v0.2.0/go.mod h1:qhKdvif7YF5GI9NWEpyxTSSBdGmzkNguibrdCNVPunU=
 github.com/go-openapi/analysis v0.0.0-20180825180245-b006789cd277/go.mod h1:k70tL6pCuVxPJOHXQ+wIac1FUrvNkHolPie/cLEU6hI=
 github.com/go-openapi/analysis v0.17.0/go.mod h1:IowGgpVeD0vNm45So8nr+IcQ3pxVtpRoBWb8PVZO0ik=
-github.com/go-openapi/analysis v0.17.2/go.mod h1:IowGgpVeD0vNm45So8nr+IcQ3pxVtpRoBWb8PVZO0ik=
 github.com/go-openapi/analysis v0.18.0/go.mod h1:IowGgpVeD0vNm45So8nr+IcQ3pxVtpRoBWb8PVZO0ik=
 github.com/go-openapi/analysis v0.19.2/go.mod h1:3P1osvZa9jKjb8ed2TPng3f0i/UY9snX6gxi44djMjk=
 github.com/go-openapi/analysis v0.19.5/go.mod h1:hkEAkxagaIvIP7VTn8ygJNkd4kAYON2rCu0v0ObL0AU=
 github.com/go-openapi/errors v0.17.0/go.mod h1:LcZQpmvG4wyF5j4IhA73wkLFQg+QJXOQHVjmcZxhka0=
-github.com/go-openapi/errors v0.17.2/go.mod h1:LcZQpmvG4wyF5j4IhA73wkLFQg+QJXOQHVjmcZxhka0=
 github.com/go-openapi/errors v0.18.0/go.mod h1:LcZQpmvG4wyF5j4IhA73wkLFQg+QJXOQHVjmcZxhka0=
 github.com/go-openapi/errors v0.19.2/go.mod h1:qX0BLWsyaKfvhluLejVpVNwNRdXZhEbTA4kxxpKBC94=
 github.com/go-openapi/jsonpointer v0.0.0-20160704185906-46af16f9f7b1/go.mod h1:+35s3my2LFTysnkMfxsJBAMHj/DoqoB9knIWoYG/Vk0=
 github.com/go-openapi/jsonpointer v0.17.0/go.mod h1:cOnomiV+CVVwFLk0A/MExoFMjwdsUdVpsRhURCKh+3M=
-github.com/go-openapi/jsonpointer v0.17.2/go.mod h1:cOnomiV+CVVwFLk0A/MExoFMjwdsUdVpsRhURCKh+3M=
 github.com/go-openapi/jsonpointer v0.18.0/go.mod h1:cOnomiV+CVVwFLk0A/MExoFMjwdsUdVpsRhURCKh+3M=
 github.com/go-openapi/jsonpointer v0.19.2/go.mod h1:3akKfEdA7DF1sugOqz1dVQHBcuDBPKZGEoHC/NkiQRg=
 github.com/go-openapi/jsonpointer v0.19.3/go.mod h1:Pl9vOtqEWErmShwVjC8pYs9cog34VGT37dQOVbmoatg=
 github.com/go-openapi/jsonreference v0.0.0-20160704190145-13c6e3589ad9/go.mod h1:W3Z9FmVs9qj+KR4zFKmDPGiLdk1D9Rlm7cyMvf57TTg=
 github.com/go-openapi/jsonreference v0.17.0/go.mod h1:g4xxGn04lDIRh0GJb5QlpE3HfopLOL6uZrK/VgnsK9I=
-github.com/go-openapi/jsonreference v0.17.2/go.mod h1:g4xxGn04lDIRh0GJb5QlpE3HfopLOL6uZrK/VgnsK9I=
 github.com/go-openapi/jsonreference v0.18.0/go.mod h1:g4xxGn04lDIRh0GJb5QlpE3HfopLOL6uZrK/VgnsK9I=
 github.com/go-openapi/jsonreference v0.19.2/go.mod h1:jMjeRr2HHw6nAVajTXJ4eiUwohSTlpa0o73RUL1owJc=
 github.com/go-openapi/jsonreference v0.19.3/go.mod h1:rjx6GuL8TTa9VaixXglHmQmIL98+wF9xc8zWvFonSJ8=
 github.com/go-openapi/loads v0.17.0/go.mod h1:72tmFy5wsWx89uEVddd0RjRWPZm92WRLhf7AC+0+OOU=
-github.com/go-openapi/loads v0.17.2/go.mod h1:72tmFy5wsWx89uEVddd0RjRWPZm92WRLhf7AC+0+OOU=
 github.com/go-openapi/loads v0.18.0/go.mod h1:72tmFy5wsWx89uEVddd0RjRWPZm92WRLhf7AC+0+OOU=
 github.com/go-openapi/loads v0.19.0/go.mod h1:72tmFy5wsWx89uEVddd0RjRWPZm92WRLhf7AC+0+OOU=
 github.com/go-openapi/loads v0.19.2/go.mod h1:QAskZPMX5V0C2gvfkGZzJlINuP7Hx/4+ix5jWFxsNPs=
 github.com/go-openapi/loads v0.19.4/go.mod h1:zZVHonKd8DXyxyw4yfnVjPzBjIQcLt0CCsn0N0ZrQsk=
 github.com/go-openapi/runtime v0.0.0-20180920151709-4f900dc2ade9/go.mod h1:6v9a6LTXWQCdL8k1AO3cvqx5OtZY/Y9wKTgaoP6YRfA=
-github.com/go-openapi/runtime v0.18.0/go.mod h1:uI6pHuxWYTy94zZxgcwJkUWa9wbIlhteGfloI10GD4U=
 github.com/go-openapi/runtime v0.19.0/go.mod h1:OwNfisksmmaZse4+gpV3Ne9AyMOlP1lt4sK4FXt0O64=
 github.com/go-openapi/runtime v0.19.4/go.mod h1:X277bwSUBxVlCYR3r7xgZZGKVvBd/29gLDlFGtJ8NL4=
 github.com/go-openapi/spec v0.0.0-20160808142527-6aced65f8501/go.mod h1:J8+jY1nAiCcj+friV/PDoE1/3eeccG9LYBs0tYvLOWc=
 github.com/go-openapi/spec v0.17.0/go.mod h1:XkF/MOi14NmjsfZ8VtAKf8pIlbZzyoTvZsdfssdxcBI=
-github.com/go-openapi/spec v0.17.2/go.mod h1:XkF/MOi14NmjsfZ8VtAKf8pIlbZzyoTvZsdfssdxcBI=
 github.com/go-openapi/spec v0.18.0/go.mod h1:XkF/MOi14NmjsfZ8VtAKf8pIlbZzyoTvZsdfssdxcBI=
 github.com/go-openapi/spec v0.19.2/go.mod h1:sCxk3jxKgioEJikev4fgkNmwS+3kuYdJtcsZsD5zxMY=
 github.com/go-openapi/spec v0.19.3/go.mod h1:FpwSN1ksY1eteniUU7X0N/BgJ7a4WvBFVA8Lj9mJglo=
-github.com/go-openapi/spec v0.19.4/go.mod h1:FpwSN1ksY1eteniUU7X0N/BgJ7a4WvBFVA8Lj9mJglo=
 github.com/go-openapi/strfmt v0.17.0/go.mod h1:P82hnJI0CXkErkXi8IKjPbNBM6lV6+5pLP5l494TcyU=
-github.com/go-openapi/strfmt v0.17.2/go.mod h1:P82hnJI0CXkErkXi8IKjPbNBM6lV6+5pLP5l494TcyU=
 github.com/go-openapi/strfmt v0.18.0/go.mod h1:P82hnJI0CXkErkXi8IKjPbNBM6lV6+5pLP5l494TcyU=
 github.com/go-openapi/strfmt v0.19.0/go.mod h1:+uW+93UVvGGq2qGaZxdDeJqSAqBqBdl+ZPMF/cC8nDY=
-github.com/go-openapi/strfmt v0.19.2/go.mod h1:0yX7dbo8mKIvc3XSKp7MNfxw4JytCfCD6+bY1AVL9LU=
 github.com/go-openapi/strfmt v0.19.3/go.mod h1:0yX7dbo8mKIvc3XSKp7MNfxw4JytCfCD6+bY1AVL9LU=
 github.com/go-openapi/swag v0.0.0-20160704191624-1d0bd113de87/go.mod h1:DXUve3Dpr1UfpPtxFw+EFuQ41HhCWZfha5jSVRG7C7I=
 github.com/go-openapi/swag v0.17.0/go.mod h1:AByQ+nYG6gQg71GINrmuDXCPWdL640yX49/kXLo40Tg=
-github.com/go-openapi/swag v0.17.2/go.mod h1:AByQ+nYG6gQg71GINrmuDXCPWdL640yX49/kXLo40Tg=
 github.com/go-openapi/swag v0.18.0/go.mod h1:AByQ+nYG6gQg71GINrmuDXCPWdL640yX49/kXLo40Tg=
 github.com/go-openapi/swag v0.19.2/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh66Z9tfKk=
 github.com/go-openapi/swag v0.19.5/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh66Z9tfKk=
-github.com/go-openapi/validate v0.17.2/go.mod h1:Uh4HdOzKt19xGIGm1qHf/ofbX1YQ4Y+MYsct2VUrAJ4=
 github.com/go-openapi/validate v0.18.0/go.mod h1:Uh4HdOzKt19xGIGm1qHf/ofbX1YQ4Y+MYsct2VUrAJ4=
 github.com/go-openapi/validate v0.19.2/go.mod h1:1tRCw7m3jtI8eNWEEliiAqUIcBztB2KDnRCRMUi7GTA=
 github.com/go-openapi/validate v0.19.5/go.mod h1:8DJv2CVJQ6kGNpFW6eV9N3JviE1C85nY1c2z52x1Gk4=
@@ -343,49 +219,36 @@ github.com/go-playground/universal-translator v0.17.0 h1:icxd5fm+REJzpZx7ZfpaD87
 github.com/go-playground/universal-translator v0.17.0/go.mod h1:UkSxE5sNxxRwHyU+Scu5vgOQjsIJAF8j9muTVoKLVtA=
 github.com/go-playground/validator/v10 v10.4.1 h1:pH2c5ADXtd66mxoE0Zm9SUhxE20r7aM3F26W0hOn+GE=
 github.com/go-playground/validator/v10 v10.4.1/go.mod h1:nlOn6nFhuKACm19sB/8EGNn9GlaMV7XkbRSipzJ0Ii4=
-github.com/go-sql-driver/mysql v1.4.0/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w=
-github.com/go-sql-driver/mysql v1.4.1/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w=
 github.com/go-sql-driver/mysql v1.5.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg=
 github.com/go-stack/stack v1.8.0 h1:5SgMzNM5HxrEjV0ww2lTmX6E2Izsfxas4+YHWRs3Lsk=
 github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY=
 github.com/go-test/deep v1.0.2-0.20181118220953-042da051cf31/go.mod h1:wGDj63lr65AM2AQyKZd/NYHGb0R+1RLqB8NKt3aSFNA=
-github.com/gobuffalo/envy v1.6.5/go.mod h1:N+GkhhZ/93bGZc6ZKhJLP6+m+tCNPKwgSpH9kaifseQ=
-github.com/gobuffalo/envy v1.7.0/go.mod h1:n7DRkBerg/aorDM8kbduw5dN3oXGswK5liaSCx4T5NI=
-github.com/gobuffalo/envy v1.7.1/go.mod h1:FurDp9+EDPE4aIUS3ZLyD+7/9fpx7YRt/ukY6jIHf0w=
-github.com/gobuffalo/flect v0.1.5/go.mod h1:W3K3X9ksuZfir8f/LrfVtWmCDQFfayuylOJ7sz/Fj80=
 github.com/gobuffalo/flect v0.2.0/go.mod h1:W3K3X9ksuZfir8f/LrfVtWmCDQFfayuylOJ7sz/Fj80=
-github.com/gobuffalo/flect v0.2.1/go.mod h1:vmkQwuZYhN5Pc4ljYQZzP+1sq+NEkK+lh20jmEmX3jc=
-github.com/gobuffalo/logger v1.0.1/go.mod h1:2zbswyIUa45I+c+FLXuWl9zSWEiVuthsk8ze5s8JvPs=
-github.com/gobuffalo/packd v0.3.0/go.mod h1:zC7QkmNkYVGKPw4tHpBQ+ml7W/3tIebgeo1b36chA3Q=
-github.com/gobuffalo/packr/v2 v2.7.1/go.mod h1:qYEvAazPaVxy7Y7KR0W8qYEE+RymX74kETFqjFoFlOc=
-github.com/gobwas/glob v0.2.3/go.mod h1:d3Ez4x06l9bZtSvzIay5+Yzi0fmZzPgnTbPcKjJAkT8=
-github.com/gocql/gocql v0.0.0-20190301043612-f6df8288f9b4/go.mod h1:4Fw1eo5iaEhDUs8XyuhSVCVy52Jq3L+/3GJgYkwc+/0=
-github.com/godbus/dbus v0.0.0-20190422162347-ade71ed3457e/go.mod h1:bBOAhwG1umN6/6ZUMtDFBMQR8jRg9O75tm9K00oMsK4=
-github.com/gofrs/flock v0.7.1/go.mod h1:F1TvTiK9OcQqauNUHlbJvyl9Qa1QvF/gOUDKA14jxHU=
 github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=
-github.com/gogo/protobuf v1.2.0/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=
 github.com/gogo/protobuf v1.2.1/go.mod h1:hp+jE20tsWTFYpLwKvXlhS1hjn+gTNwPg2I6zVXpSg4=
-github.com/gogo/protobuf v1.2.2-0.20190730201129-28a6bbf47e48/go.mod h1:SlYgWuQ5SjCEi6WLHjHCa1yvBfUnHcTbrrZtXPKa29o=
-github.com/gogo/protobuf v1.3.1 h1:DqDEcV5aeaTmdFBePNpYsp3FlcVH/2ISVVM9Qf8PSls=
 github.com/gogo/protobuf v1.3.1/go.mod h1:SlYgWuQ5SjCEi6WLHjHCa1yvBfUnHcTbrrZtXPKa29o=
-github.com/golang-migrate/migrate/v4 v4.6.2/go.mod h1:JYi6reN3+Z734VZ0akNuyOJNcrg45ZL7LDBMW3WGJL0=
-github.com/golang-sql/civil v0.0.0-20190719163853-cb61b32ac6fe/go.mod h1:8vg3r2VgvsThLBIFL93Qb5yWzgyZWhEmBwUJWevAkK0=
+github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q=
+github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q=
 github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
 github.com/golang/groupcache v0.0.0-20160516000752-02826c3e7903/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
 github.com/golang/groupcache v0.0.0-20190129154638-5b532d6fd5ef/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
 github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
-github.com/golang/groupcache v0.0.0-20191027212112-611e8accdfc9/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
-github.com/golang/groupcache v0.0.0-20191227052852-215e87163ea7 h1:5ZkaAPbicIKTF2I64qf5Fh8Aa83Q/dnOafMYV0OMwjA=
 github.com/golang/groupcache v0.0.0-20191227052852-215e87163ea7/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
+github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e h1:1r7pUrabqp18hOBcwBwiTsbnFeTZHV9eER/QT5JVZxY=
+github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
 github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
 github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
 github.com/golang/mock v1.3.1/go.mod h1:sBzyDLLjw3U8JLTeZvSv8jJB+tU5PVekmnlKIyFUx0Y=
-github.com/golang/protobuf v0.0.0-20161109072736-4bd1920723d7/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
+github.com/golang/mock v1.4.0/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw=
+github.com/golang/mock v1.4.1/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw=
+github.com/golang/mock v1.4.3/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw=
+github.com/golang/mock v1.4.4/go.mod h1:l3mdAwkq5BuhzHwde/uurv3sEJeZMXNpwsxVWU71h+4=
 github.com/golang/protobuf v1.0.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
 github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
 github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
 github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
 github.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw=
+github.com/golang/protobuf v1.3.4/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw=
 github.com/golang/protobuf v1.3.5/go.mod h1:6O5/vntMXwX2lRkT1hjjk0nAC1IDOTvTlVgjlRvqsdk=
 github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8=
 github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA=
@@ -393,97 +256,80 @@ github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrU
 github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w=
 github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0=
 github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QDs8UjoX8=
-github.com/golang/protobuf v1.4.2 h1:+Z5KGCizgyZCbGh1KZqA0fcLLkwbsjIzS4aV2v7wJX0=
 github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=
-github.com/golang/snappy v0.0.0-20170215233205-553a64147049/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
-github.com/golang/snappy v0.0.0-20180518054509-2e65f85255db/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
+github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk=
+github.com/golang/protobuf v1.5.2 h1:ROPKBNFfQgOUMifHyP+KYbvpjbdoFNs+aK7DXlji0Tw=
+github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY=
 github.com/golang/snappy v0.0.1 h1:Qgr9rKW7uDUkrbSmQeiDsGa8SjGyCOGtuasMWwvp2P4=
 github.com/golang/snappy v0.0.1/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
 github.com/golangplus/bytes v0.0.0-20160111154220-45c989fe5450/go.mod h1:Bk6SMAONeMXrxql8uvOKuAZSu8aM5RUGv+1C6IJaEho=
 github.com/golangplus/fmt v0.0.0-20150411045040-2a5d6d7d2995/go.mod h1:lJgMEyOkYFkPcDKwRXegd+iM6E7matEszMG5HhwytU8=
 github.com/golangplus/testing v0.0.0-20180327235837-af21d9c3145e/go.mod h1:0AA//k/eakGydO4jKRoRL2j92ZKSzTgj9tclaCrvXHk=
 github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
-github.com/google/btree v1.0.0 h1:0udJVsspx3VBr5FwtLhQQtuAsVc79tTq0ocGIPAU6qo=
 github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
+github.com/google/btree v1.0.1 h1:gK4Kx5IaGY9CD5sPJ36FHiBJ6ZXl0kilRiiCj+jdYp4=
 github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M=
 github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
 github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
 github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
-github.com/google/go-cmp v0.4.1 h1:/exdXoGamhu5ONeUJH0deniYLWYvQwW66yvlfiiKTu0=
 github.com/google/go-cmp v0.4.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
-github.com/google/go-github v17.0.0+incompatible/go.mod h1:zLgOLi98H3fifZn+44m+umXrS52loVEgC2AApnigrVQ=
+github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
+github.com/google/go-cmp v0.5.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
+github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
+github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
+github.com/google/go-cmp v0.5.6 h1:BKbKCqvP6I+rmFHt06ZmyQtvB8xAkWdhFyr0ZUNZcxQ=
 github.com/google/go-querystring v1.0.0/go.mod h1:odCYkC5MyYFN7vkCjXpyrEuKhc/BUO6wN/zVPAxq5ck=
-github.com/google/gofuzz v0.0.0-20161122191042-44d81051d367/go.mod h1:HP5RmnzzSNb993RKQDq4+1A4ia9nllfqcQFTQJedwGI=
 github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
 github.com/google/gofuzz v1.1.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
 github.com/google/gofuzz v1.2.0 h1:xRy4A+RhZaiKjJ1bPfwQ8sedCA+YS2YcCHW6ec7JMi0=
 github.com/google/gofuzz v1.2.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
 github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs=
+github.com/google/martian/v3 v3.0.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0=
 github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc=
 github.com/google/pprof v0.0.0-20190515194954-54271f7e092f/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc=
-github.com/google/pprof v0.0.0-20190723021845-34ac40c74b70/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc=
 github.com/google/pprof v0.0.0-20191218002539-d4f498aebedc/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=
+github.com/google/pprof v0.0.0-20200212024743-f11f1df84d12/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=
+github.com/google/pprof v0.0.0-20200229191704-1ebb73c60ed3/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=
+github.com/google/pprof v0.0.0-20200430221834-fc25d7d30c6d/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=
+github.com/google/pprof v0.0.0-20200708004538-1a94d8640e99/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=
 github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI=
-github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510/go.mod h1:pupxD2MaaD3pAXIBCelhxNneeOaAeabZDe5s4K6zSpQ=
 github.com/google/uuid v1.0.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
-github.com/google/uuid v1.1.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
 github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
-github.com/googleapis/gax-go v2.0.2+incompatible/go.mod h1:SFVmujtThgffbyetf+mdk2eWhX2bMyUtNHzFKcPA9HY=
 github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg=
 github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk=
-github.com/googleapis/gnostic v0.0.0-20170729233727-0c5108395e2d/go.mod h1:sJBsCZ4ayReDTBIg8b9dl28c5xFWyhBTVRp3pOg5EKY=
 github.com/googleapis/gnostic v0.3.1/go.mod h1:on+2t9HRStVgn95RSsFWFz+6Q0Snyqv1awfrALZdbtU=
-github.com/googleapis/gnostic v0.4.1 h1:DLJCy1n/vrD4HPjOvYcT8aYQXpPIzoRZONaYwyycI+I=
 github.com/googleapis/gnostic v0.4.1/go.mod h1:LRhVm6pbyptWbWbuZ38d1eyptfvIytN3ir6b65WBswg=
-github.com/gophercloud/gophercloud v0.2.0/go.mod h1:vxM41WHh5uqHVBMZHzuwNOHh8XEoIEcSTewFxm1c5g8=
-github.com/gophercloud/gophercloud v0.3.0/go.mod h1:vxM41WHh5uqHVBMZHzuwNOHh8XEoIEcSTewFxm1c5g8=
-github.com/gophercloud/gophercloud v0.6.0/go.mod h1:GICNByuaEBibcjmjvI7QvYJSZEbGkcYwAR7EZK2WMqM=
+github.com/googleapis/gnostic v0.5.5 h1:9fHAtK0uDfpveeqqo1hkEZJcFvYXAiCN3UutL8F9xHw=
+github.com/googleapis/gnostic v0.5.5/go.mod h1:7+EbHbldMins07ALC74bsA81Ovc97DwqyJO1AENw9kA=
 github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY=
-github.com/gopherjs/gopherjs v0.0.0-20191106031601-ce3c9ade29de/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY=
-github.com/gorilla/context v1.1.1/go.mod h1:kBGZzfjB9CEq2AlWe17Uuf7NDRt0dE0s8S51q0aT7Yg=
-github.com/gorilla/handlers v0.0.0-20150720190736-60c7bfde3e33 h1:893HsJqtxp9z1SF76gg6hY70hRY1wVlTSnC/h1yUDCo=
-github.com/gorilla/handlers v0.0.0-20150720190736-60c7bfde3e33/go.mod h1:Qkdc/uu4tH4g6mTK6auzZ766c4CA0Ng8+o/OAirnOIQ=
-github.com/gorilla/mux v1.6.2/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs=
-github.com/gorilla/mux v1.7.1/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs=
+github.com/gorilla/handlers v1.3.0 h1:tsg9qP3mjt1h4Roxp+M1paRjrVBfPSOpBuVclh6YluI=
+github.com/gorilla/handlers v1.3.0/go.mod h1:Qkdc/uu4tH4g6mTK6auzZ766c4CA0Ng8+o/OAirnOIQ=
 github.com/gorilla/mux v1.7.2 h1:zoNxOV7WjqXptQOVngLmcSQgXmgk4NMz1HibBchjl/I=
 github.com/gorilla/mux v1.7.2/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs=
 github.com/gorilla/websocket v0.0.0-20170926233335-4201258b820c/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ=
 github.com/gorilla/websocket v1.4.0/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ=
 github.com/gorilla/websocket v1.4.2 h1:+/TMaTYc4QFitKJxsQ7Yye35DkWvkdLcvGKqM+x0Ufc=
 github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
-github.com/gosuri/uitable v0.0.4/go.mod h1:tKR86bXuXPZazfOTG1FIzvjIdXzd0mo4Vtn16vt0PJo=
 github.com/gregjones/httpcache v0.0.0-20180305231024-9cad4c3443a7/go.mod h1:FecbI9+v66THATjSRHfNgh1IVFe/9kFxbXtjV0ctIMA=
 github.com/grpc-ecosystem/go-grpc-middleware v1.0.0/go.mod h1:FiyG127CGDf3tlThmgyCl78X/SZQqEOJBCDaAfeWzPs=
+github.com/grpc-ecosystem/go-grpc-middleware v1.0.1-0.20190118093823-f849b5445de4 h1:z53tR0945TRRQO/fLEVPI6SMv7ZflF0TEaTAoU7tOzg=
 github.com/grpc-ecosystem/go-grpc-middleware v1.0.1-0.20190118093823-f849b5445de4/go.mod h1:FiyG127CGDf3tlThmgyCl78X/SZQqEOJBCDaAfeWzPs=
-github.com/grpc-ecosystem/go-grpc-middleware v1.1.0 h1:THDBEeQ9xZ8JEaCLyLQqXMMdRqNr0QAUJTIkQAUtFjg=
-github.com/grpc-ecosystem/go-grpc-middleware v1.1.0/go.mod h1:f5nM7jw/oeRSadq3xCzHAvxcr8HZnzsqU6ILg/0NiiE=
 github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0 h1:Ovs26xHkKqVztRpIrF/92BcuyuQ/YW4NSIpoGtfXNho=
 github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0/go.mod h1:8NvIoxWQoOIhqOTXgfV/d3M/q6VIi02HzZEHgUlZvzk=
 github.com/grpc-ecosystem/grpc-gateway v1.9.0/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY=
-github.com/grpc-ecosystem/grpc-gateway v1.9.4/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY=
+github.com/grpc-ecosystem/grpc-gateway v1.9.5 h1:UImYN5qQ8tuGpGE16ZmjvcTtTw24zw1QAp/SlnNrZhI=
 github.com/grpc-ecosystem/grpc-gateway v1.9.5/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY=
-github.com/grpc-ecosystem/grpc-gateway v1.12.1 h1:zCy2xE9ablevUOrUZc3Dl72Dt+ya2FNAvC2yLYMHzi4=
-github.com/grpc-ecosystem/grpc-gateway v1.12.1/go.mod h1:8XEsbTttt/W+VvjtQhLACqCisSPWTxCZ7sBRjU6iH9c=
-github.com/grpc-ecosystem/grpc-health-probe v0.2.1-0.20181220223928-2bf0a5b182db/go.mod h1:uBKkC2RbarFsvS5jMJHpVhTLvGlGQj9JJwkaePE3FWI=
-github.com/hailocab/go-hostpool v0.0.0-20160125115350-e80d13ce29ed/go.mod h1:tMWxXQ9wFIaZeTI9F+hmhFiGpFmhOHzyShyFUhRm0H4=
 github.com/hashicorp/consul/api v1.1.0/go.mod h1:VmuI/Lkw1nC05EYQWNKwWGbkg+FbDBtguAZLlVdkD9Q=
-github.com/hashicorp/consul/api v1.3.0/go.mod h1:MmDNSzIMUjNpY/mQ398R4bk2FnqQLoPndWW5VkKPlCE=
 github.com/hashicorp/consul/sdk v0.1.1/go.mod h1:VKf9jXwCTEY1QZP2MOLRhb5i/I/ssyNV1vwHyQBF0x8=
-github.com/hashicorp/consul/sdk v0.3.0/go.mod h1:VKf9jXwCTEY1QZP2MOLRhb5i/I/ssyNV1vwHyQBF0x8=
-github.com/hashicorp/errwrap v0.0.0-20141028054710-7554cd9344ce/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4=
 github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4=
 github.com/hashicorp/go-cleanhttp v0.5.0/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80=
 github.com/hashicorp/go-cleanhttp v0.5.1/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80=
 github.com/hashicorp/go-hclog v0.0.0-20180709165350-ff2cf002a8dd/go.mod h1:9bjs9uLqI8l75knNv3lV1kA55veR+WUPSiKIWcQHudI=
 github.com/hashicorp/go-hclog v0.8.0/go.mod h1:5CU+agLiy3J7N7QjHK5d05KxGsuXiQLrjA0H7acj2lQ=
 github.com/hashicorp/go-immutable-radix v1.0.0/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60=
-github.com/hashicorp/go-immutable-radix v1.1.0/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60=
 github.com/hashicorp/go-msgpack v0.5.3/go.mod h1:ahLV/dePpqEmjfWmKiqvPkv/twdG7iPBM1vqhUKIvfM=
-github.com/hashicorp/go-msgpack v0.5.5/go.mod h1:ahLV/dePpqEmjfWmKiqvPkv/twdG7iPBM1vqhUKIvfM=
-github.com/hashicorp/go-multierror v0.0.0-20161216184304-ed905158d874/go.mod h1:JMRHfdO9jKNzS/+BTlxCjKNQHg/jZAft8U7LloJvN7I=
 github.com/hashicorp/go-multierror v1.0.0/go.mod h1:dHtQlpGsu+cZNNAkkCN/P3hoUDHhCYQXV3UM06sGGrk=
 github.com/hashicorp/go-plugin v1.0.1/go.mod h1:++UyYGoz3o5w9ZzAdZxtQKrWWP+iqPBn3cQptSMzBuY=
-github.com/hashicorp/go-retryablehttp v0.5.3/go.mod h1:9B5zBasrRhHXnJnui7y6sL7es7NDiJgTc6Er0maI1Xs=
 github.com/hashicorp/go-retryablehttp v0.5.4/go.mod h1:9B5zBasrRhHXnJnui7y6sL7es7NDiJgTc6Er0maI1Xs=
 github.com/hashicorp/go-rootcerts v1.0.0/go.mod h1:K6zTfqpRlCUIjkwsN4Z+hiSfzSTQa6eBIzfwKfwNnHU=
 github.com/hashicorp/go-rootcerts v1.0.1/go.mod h1:pqUvnprVnM5bf7AOirdbb01K4ccR319Vf4pU3K5EGc8=
@@ -496,71 +342,46 @@ github.com/hashicorp/go-version v1.1.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09
 github.com/hashicorp/go.net v0.0.1/go.mod h1:hjKkEWcCURg++eb33jQU7oqQcI9XDCnUzHA0oac0k90=
 github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
 github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
-github.com/hashicorp/golang-lru v0.5.3/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4=
 github.com/hashicorp/golang-lru v0.5.4/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4=
 github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ=
 github.com/hashicorp/logutils v1.0.0/go.mod h1:QIAnNjmIWmVIIkWDTG1z5v++HQmx9WQRO+LraFDTW64=
 github.com/hashicorp/mdns v1.0.0/go.mod h1:tL+uN++7HEJ6SQLQ2/p+z2pH24WQKWjBPkE0mNTz8vQ=
 github.com/hashicorp/memberlist v0.1.3/go.mod h1:ajVTdAv/9Im8oMAAj5G31PhhMCZJV2pPBoIllUwCN7I=
-github.com/hashicorp/memberlist v0.1.4/go.mod h1:ajVTdAv/9Im8oMAAj5G31PhhMCZJV2pPBoIllUwCN7I=
-github.com/hashicorp/memberlist v0.1.5/go.mod h1:ajVTdAv/9Im8oMAAj5G31PhhMCZJV2pPBoIllUwCN7I=
 github.com/hashicorp/serf v0.8.2/go.mod h1:6hOLApaqBFA1NXqRQAsxw9QxuDEvNxSQRwA/JwenrHc=
-github.com/hashicorp/serf v0.8.5/go.mod h1:UpNcs7fFbpKIyZaUuSW6EPiH+eZC7OuyFD+wc1oal+k=
 github.com/hashicorp/vault/api v1.0.4/go.mod h1:gDcqh3WGcR1cpF5AJz/B1UFheUEneMoIospckxBxk6Q=
 github.com/hashicorp/vault/sdk v0.1.13/go.mod h1:B+hVj7TpuQY1Y/GPbCpffmgd+tSEwvhkWnjtSYCaS2M=
 github.com/hashicorp/yamux v0.0.0-20180604194846-3520598351bb/go.mod h1:+NfK9FKeTrX5uv1uIXGdwYDTeHna2qgaIlx54MXqjAM=
 github.com/hashicorp/yamux v0.0.0-20181012175058-2f1d1f20f75d/go.mod h1:+NfK9FKeTrX5uv1uIXGdwYDTeHna2qgaIlx54MXqjAM=
 github.com/howeyc/gopass v0.0.0-20170109162249-bf9dde6d0d2c/go.mod h1:lADxMC39cJJqL93Duh1xhAs4I2Zs8mKS89XWXFGp9cs=
 github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU=
-github.com/huandu/xstrings v1.3.1/go.mod h1:y5/lhBue+AyNmUVz9RLU9xbLR0o4KIIExikq4ovT0aE=
-github.com/iancoleman/strcase v0.0.0-20190422225806-e506e3ef7365/go.mod h1:SK73tn/9oHe+/Y0h39VT4UCxmurVJkR5NA7kMEAOgSE=
 github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc=
 github.com/imdario/mergo v0.3.5/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJh5FfA=
-github.com/imdario/mergo v0.3.6/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJh5FfA=
-github.com/imdario/mergo v0.3.7/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJh5FfA=
-github.com/imdario/mergo v0.3.8/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJh5FfA=
 github.com/imdario/mergo v0.3.9/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJh5FfA=
-github.com/imdario/mergo v0.3.11 h1:3tnifQM4i+fbajXKBHXWEH+KvNHqojZ778UH75j3bGA=
-github.com/imdario/mergo v0.3.11/go.mod h1:jmQim1M+e3UYxmgPu/WyfjB3N3VflVyUjjjwH0dnCYA=
+github.com/imdario/mergo v0.3.12 h1:b6R2BslTbIEToALKP7LxUvijTsNI9TAe80pLWN2g/HU=
+github.com/imdario/mergo v0.3.12/go.mod h1:jmQim1M+e3UYxmgPu/WyfjB3N3VflVyUjjjwH0dnCYA=
 github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8=
-github.com/influxdata/influxdb v1.7.7/go.mod h1:qZna6X/4elxqT3yI9iZYdZrWWdeFOOprn86kgg4+IzY=
-github.com/jackc/fake v0.0.0-20150926172116-812a484cc733/go.mod h1:WrMFNQdiFJ80sQsxDoMokWK1W5TQtxBFNpzWTD84ibQ=
-github.com/jackc/pgx v3.2.0+incompatible/go.mod h1:0ZGrqGqkRlliWnWB4zKnWtjbSWbGkVEFm4TeybAXq+I=
-github.com/jessevdk/go-flags v0.0.0-20180331124232-1c38ed7ad0cc/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI=
-github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI=
 github.com/jetstack/cert-manager v1.2.0 h1:xgXGdvHxGwCFjB13rCQ/fwa4A7FMpPRewa3wiW++EP4=
 github.com/jetstack/cert-manager v1.2.0/go.mod h1:maDZ7RUO9H6RB+/ks9XBe8jf9zdC8cI0dGY3HBLzTVQ=
-github.com/jmespath/go-jmespath v0.0.0-20160202185014-0b12d6b521d8/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k=
-github.com/jmespath/go-jmespath v0.0.0-20160803190731-bd40a432e4c7/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k=
-github.com/jmespath/go-jmespath v0.0.0-20180206201540-c2b33e8439af/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k=
 github.com/jmespath/go-jmespath v0.4.0/go.mod h1:T8mJZnbsbmF+m6zOOFylbeCJqk5+pHWvzYPziyZiYoo=
 github.com/jmespath/go-jmespath/internal/testify v1.5.1/go.mod h1:L3OGu8Wl2/fWfCI6z80xFu9LTZmf1ZRjMHUOPmWr69U=
-github.com/jmoiron/sqlx v1.2.0/go.mod h1:1FEQNm3xlJgrMD+FBdI9+xvCksHtbpVBBw5dYhBSsks=
-github.com/joefitzgerald/rainbow-reporter v0.1.0/go.mod h1:481CNgqmVHQZzdIbN52CupLJyoVwB10FQ/IQlF1pdL8=
-github.com/joeshaw/multierror v0.0.0-20140124173710-69b34d4ec901/go.mod h1:Z86h9688Y0wesXCyonoVr47MasHilkuLMqGhRZ4Hpak=
-github.com/joho/godotenv v1.3.0/go.mod h1:7hK45KPybAkOC6peb+G5yklZfMxEjkZhHbwpqxOKXbg=
-github.com/jonboulle/clockwork v0.1.0 h1:VKV+ZcuP6l3yW9doeqz6ziZGgcynBVQO+obU0+0hcPo=
 github.com/jonboulle/clockwork v0.1.0/go.mod h1:Ii8DK3G1RaLaWxj9trq07+26W01tbo22gdxWY5EU2bo=
-github.com/jpillora/backoff v1.0.0/go.mod h1:J/6gKK9jxlEcS3zixgDgUAsiuZ7yrSoa/FX5e0EB2j4=
-github.com/json-iterator/go v0.0.0-20180612202835-f2b4162afba3/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU=
+github.com/jonboulle/clockwork v0.2.2 h1:UOGuzwb1PwsrDAObMuhUnj0p5ULPj8V/xJ7Kx9qUBdQ=
 github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU=
 github.com/json-iterator/go v1.1.7/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
-github.com/json-iterator/go v1.1.8/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
-github.com/json-iterator/go v1.1.9/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
-github.com/json-iterator/go v1.1.10 h1:Kz6Cvnvv2wGdaG/V8yMvfkmNiXq9Ya2KUv4rouJJr68=
 github.com/json-iterator/go v1.1.10/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
-github.com/jsonnet-bundler/jsonnet-bundler v0.3.1/go.mod h1:/by7P/OoohkI3q4CgSFqcoFsVY+IaNbzOVDknEsKDeU=
+github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM=
+github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo=
 github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU=
 github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/XSXhF0NWZEnDohbsk=
 github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU=
 github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w=
-github.com/julienschmidt/httprouter v1.3.0/go.mod h1:JR6WtHb+2LUe8TCKY3cZOxFyyO8IZAc4RVcycCCAKdM=
-github.com/kardianos/osext v0.0.0-20190222173326-2bc1f35cddc0/go.mod h1:1NbS8ALrpOvjt0rHPNLyCIeMtbizbir8U//inJ+zuB8=
 github.com/kisielk/errcheck v1.1.0/go.mod h1:EZBBE59ingxPouuu3KfxchcWSUPOHkagtvWXihfKN4Q=
 github.com/kisielk/errcheck v1.2.0/go.mod h1:/BMXB+zMLi60iA8Vv6Ksmxu/1UDYcXs4uQLJ+jE2L00=
+github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8=
 github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
+github.com/klauspost/compress v1.13.6 h1:P76CopJELS0TiO2mebmnzgWaajssP/EszplttgQxcgc=
+github.com/klauspost/compress v1.13.6/go.mod h1:/3/Vjq9QcHkK5uEr5lBEmyoZ1iFhe47etQ6QUkpK6sk=
 github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
-github.com/konsorten/go-windows-terminal-sequences v1.0.2/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
 github.com/konsorten/go-windows-terminal-sequences v1.0.3/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
 github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc=
 github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
@@ -571,22 +392,10 @@ github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
 github.com/kr/pty v1.1.5/go.mod h1:9r2w37qlBe7rQ6e1fg1S/9xpWHSnaqNdHD3WcMdbPDA=
 github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE=
 github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
-github.com/kshvakov/clickhouse v1.3.5/go.mod h1:DMzX7FxRymoNkVgizH0DWAL8Cur7wHLgx3MUnGwJqpE=
-github.com/kylelemons/godebug v0.0.0-20160406211939-eadb3ce320cb/go.mod h1:B69LEHPfb2qLo0BaaOLcbitczOKLWTsrBG9LczfCD4k=
-github.com/kylelemons/godebug v0.0.0-20170820004349-d65d576e9348/go.mod h1:B69LEHPfb2qLo0BaaOLcbitczOKLWTsrBG9LczfCD4k=
-github.com/lann/builder v0.0.0-20180802200727-47ae307949d0/go.mod h1:dXGbAdH5GtBTC4WfIxhKZfyBF/HBFgRZSWwZ9g/He9o=
-github.com/lann/ps v0.0.0-20150810152359-62de8c46ede0/go.mod h1:vmVJ0l/dxyfGW6FmdpVm2joNMFikkuWg0EoCKLGUMNw=
-github.com/leanovate/gopter v0.2.4/go.mod h1:gNcbPWNEWRe4lm+bycKqxUYoH5uoVje5SkOJ3uoLer8=
 github.com/leodido/go-urn v1.2.0 h1:hpXL4XnriNwQ/ABnpepYM/1vCLWNDfUNts8dX3xTG6Y=
 github.com/leodido/go-urn v1.2.0/go.mod h1:+8+nEpDfqqsY+g338gtMEUOtuK+4dEMhiQEgxpxOKII=
-github.com/lib/pq v1.0.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo=
-github.com/lib/pq v1.2.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo=
-github.com/lib/pq v1.3.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo=
 github.com/liggitt/tabwriter v0.0.0-20181228230101-89fcab3d43de/go.mod h1:zAbeS9B/r2mtpb6U+EI2rYA5OAXxsYw6wTamcNW+zcE=
-github.com/lightstep/lightstep-tracer-common/golang/gogo v0.0.0-20190605223551-bc2310a04743/go.mod h1:qklhhLq1aX+mtWk9cPHPzaBjWImj5ULL6C7HFJtXQMM=
-github.com/lightstep/lightstep-tracer-go v0.18.0/go.mod h1:jlF1pusYV4pidLvZ+XD0UBX0ZE6WURAspgAczcDHrL4=
 github.com/lithammer/dedent v1.1.0/go.mod h1:jrXYCQtgg0nJiN+StA2KgR7w6CiQNv9Fd/Z9BP0jIOc=
-github.com/lovoo/gcloud-opentracing v0.3.0/go.mod h1:ZFqk2y38kMDDikZPAK7ynTTGuyt17nSPdS3K5e+ZTBY=
 github.com/magiconair/properties v1.8.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ=
 github.com/magiconair/properties v1.8.1/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ=
 github.com/mailru/easyjson v0.0.0-20160728113105-d5b7844b561a/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc=
@@ -595,41 +404,21 @@ github.com/mailru/easyjson v0.0.0-20190312143242-1de009706dbe/go.mod h1:C1wdFJiN
 github.com/mailru/easyjson v0.0.0-20190614124828-94de47d64c63/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc=
 github.com/mailru/easyjson v0.0.0-20190626092158-b2ccc519800e/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc=
 github.com/mailru/easyjson v0.7.0/go.mod h1:KAzv3t3aY1NaHWoQz1+4F1ccyAH66Jk7yos7ldAVICs=
-github.com/markbates/inflect v1.0.4/go.mod h1:1fR9+pO2KHEO9ZRtto13gDwwZaAKstQzferVeWqbgNs=
-github.com/marstr/guid v1.1.0/go.mod h1:74gB1z2wpxxInTG6yaqA7KrtM0NZ+RbrcqDvYHefzho=
 github.com/matryer/runner v0.0.0-20190427160343-b472a46105b1 h1:pef9ZgSvXvPH2mhGE52qUbaub5A/yboHEOk1si1PFcw=
 github.com/matryer/runner v0.0.0-20190427160343-b472a46105b1/go.mod h1:lISxzZiuWDeqvTOUohfA3Wgu+WktSrH1pxW02wZ9mUQ=
 github.com/mattbaird/jsonpatch v0.0.0-20171005235357-81af80346b1a/go.mod h1:M1qoD/MqPgTZIk0EWKB38wE28ACRfVcn+cU08jyArI0=
 github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU=
 github.com/mattn/go-colorable v0.1.2/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE=
-github.com/mattn/go-ieproxy v0.0.0-20190610004146-91bb50d98149/go.mod h1:31jz6HNzdxOmlERGGEc4v/dMssOfmp2p5bT/okiKFFc=
-github.com/mattn/go-ieproxy v0.0.0-20190702010315-6dee0af9227d/go.mod h1:31jz6HNzdxOmlERGGEc4v/dMssOfmp2p5bT/okiKFFc=
-github.com/mattn/go-ieproxy v0.0.0-20191113090002-7c0f6868bffe/go.mod h1:pYabZ6IHcRpFh7vIaLfK7rdcWgFEb3SFJ6/gNWuh88E=
 github.com/mattn/go-isatty v0.0.3/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4=
 github.com/mattn/go-isatty v0.0.4/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4=
-github.com/mattn/go-isatty v0.0.6/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s=
 github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s=
-github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU=
 github.com/mattn/go-runewidth v0.0.2/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU=
-github.com/mattn/go-runewidth v0.0.4/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU=
-github.com/mattn/go-runewidth v0.0.6/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI=
 github.com/mattn/go-runewidth v0.0.7/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI=
-github.com/mattn/go-shellwords v1.0.10/go.mod h1:EZzvwXDESEeg03EKmM+RmDnNOPKG4lLtQsUlTZDWQ8Y=
-github.com/mattn/go-sqlite3 v1.9.0/go.mod h1:FPy6KqzDD04eiIsT53CuJW3U88zkxoIYsOqkbpncsNc=
-github.com/mattn/go-sqlite3 v1.10.0/go.mod h1:FPy6KqzDD04eiIsT53CuJW3U88zkxoIYsOqkbpncsNc=
-github.com/mattn/go-sqlite3 v1.12.0/go.mod h1:FPy6KqzDD04eiIsT53CuJW3U88zkxoIYsOqkbpncsNc=
 github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0=
 github.com/matttproud/golang_protobuf_extensions v1.0.2-0.20181231171920-c182affec369 h1:I0XW9+e1XWDxdcEniV4rQAIOPUGDq67JSCiRCgGCZLI=
 github.com/matttproud/golang_protobuf_extensions v1.0.2-0.20181231171920-c182affec369/go.mod h1:BSXmuO+STAnVfrANrmjBb36TMTDstsz7MSK+HVaYKv4=
-github.com/maxbrunsfeld/counterfeiter/v6 v6.2.2/go.mod h1:eD9eIE7cdwcMi9rYluz88Jz2VyhSmden33/aXg4oVIY=
 github.com/miekg/dns v1.0.14/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg=
-github.com/miekg/dns v1.1.15/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg=
-github.com/miekg/dns v1.1.22/go.mod h1:bPDLeHnStXmXAq1m/Ch/hvfNHr14JKNPMBo3VZKjuso=
 github.com/miekg/dns v1.1.31/go.mod h1:KNUDUusw/aVsxyTYZM1oqvCicbwhgbNgztCETuNZ7xM=
-github.com/mikefarah/yaml/v2 v2.4.0/go.mod h1:ahVqZF4n1W4NqwvVnZzC4es67xsW9uR/RRf2RRxieJU=
-github.com/mikefarah/yq/v2 v2.4.1/go.mod h1:i8SYf1XdgUvY2OFwSqGAtWOOgimD2McJ6iutoxRm4k0=
-github.com/minio/minio-go/v6 v6.0.49/go.mod h1:qD0lajrGW49lKZLtXKtCB4X/qkMf0a5tBvN2PaZg7Gg=
-github.com/minio/sha256-simd v0.1.1/go.mod h1:B5e1o+1/KgNmWrSQK08Y6Z1Vb5pwIktudl0J58iy0KM=
 github.com/mitchellh/cli v1.0.0/go.mod h1:hNIlj7HEI86fIcpObd7a0FcrxTWetlwJDGcceTlRvqc=
 github.com/mitchellh/copystructure v1.0.0/go.mod h1:SNtv71yrdKgLRyLFxmLdkAbkKEFWgYaq1OVrnRcwhnw=
 github.com/mitchellh/go-homedir v1.0.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0=
@@ -638,214 +427,109 @@ github.com/mitchellh/go-testing-interface v0.0.0-20171004221916-a61a99592b77/go.
 github.com/mitchellh/go-testing-interface v1.0.0/go.mod h1:kRemZodwjscx+RGhAo8eIhFbs2+BFgRtFPeD/KE+zxI=
 github.com/mitchellh/go-wordwrap v1.0.0/go.mod h1:ZXFpozHsX6DPmq2I0TCekCxypsnAUbP2oI0UX1GXzOo=
 github.com/mitchellh/gox v0.4.0/go.mod h1:Sd9lOJ0+aimLBi73mGofS1ycjY8lL3uZM3JPS42BGNg=
-github.com/mitchellh/hashstructure v0.0.0-20170609045927-2bca23e0e452/go.mod h1:QjSHrPWS+BGUVBYkbTZWEnOh3G1DutKwClXU/ABz6AQ=
 github.com/mitchellh/iochan v1.0.0/go.mod h1:JwYml1nuB7xOzsp52dPpHFffvOCDupsG0QubkSMEySY=
 github.com/mitchellh/mapstructure v0.0.0-20160808181253-ca63d7c062ee/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y=
 github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y=
-github.com/mitchellh/osext v0.0.0-20151018003038-5e2d6d41470f/go.mod h1:OkQIRizQZAeMln+1tSwduZz7+Af5oFlKirV/MSYes2A=
 github.com/mitchellh/reflectwalk v1.0.0/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw=
 github.com/moby/term v0.0.0-20200312100748-672ec06f55cd/go.mod h1:DdlQx2hp0Ss5/fLikoLlEeIYiATotOjgB//nb973jeo=
 github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
 github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg=
 github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
-github.com/modern-go/reflect2 v0.0.0-20180320133207-05fbef0ca5da/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
 github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
-github.com/modern-go/reflect2 v1.0.1 h1:9f412s+6RmYXLWZSEzVVgPGK7C2PphHj5RJrvfx9AWI=
 github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
-github.com/morikuni/aec v0.0.0-20170113033406-39771216ff4c/go.mod h1:BbKIizmSmc5MMPqRYbxO4ZU0S0+P200+tUnFx7PXmsc=
-github.com/morikuni/aec v1.0.0/go.mod h1:BbKIizmSmc5MMPqRYbxO4ZU0S0+P200+tUnFx7PXmsc=
-github.com/mozillazg/go-cos v0.13.0/go.mod h1:Zp6DvvXn0RUOXGJ2chmWt2bLEqRAnJnS3DnAZsJsoaE=
-github.com/mozillazg/go-httpheader v0.2.1/go.mod h1:jJ8xECTlalr6ValeXYdOF8fFUISeBAdw6E61aqQma60=
+github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M=
+github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk=
+github.com/montanaflynn/stats v0.0.0-20171201202039-1bf9dbcd8cbe/go.mod h1:wL8QJuTMNUDYhXwkmfOly8iTdp5TEcJFWZD2D7SIkUc=
 github.com/munnerz/crd-schema-fuzz v1.0.0/go.mod h1:4z/rcm37JxUkSsExFcLL6ZIT1SgDRdLiu7qq1evdVS0=
 github.com/munnerz/goautoneg v0.0.0-20120707110453-a547fc61f48d/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ=
 github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U=
-github.com/mwitkow/go-conntrack v0.0.0-20190716064945-2f068394615f/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U=
 github.com/mxk/go-flowrate v0.0.0-20140419014527-cca7078d478f/go.mod h1:ZdcZmHo+o7JKHSa8/e818NopupXU1YMK5fe1lsApnBw=
-github.com/nakagami/firebirdsql v0.0.0-20190310045651-3c02a58cfed8/go.mod h1:86wM1zFnC6/uDBfZGNwB65O+pR2OFi5q/YQaEUid1qA=
-github.com/ncw/swift v1.0.47/go.mod h1:23YIA4yWVnGwv2dQlN4bB7egfYX6YLn0Yo/S6zZO/ZM=
+github.com/nxadm/tail v1.4.4 h1:DQuhQpB1tVlglWS2hLQ5OV6B5r8aGxSrPc5Qo6uTN78=
 github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A=
 github.com/oklog/run v1.0.0/go.mod h1:dlhp/R75TPv97u0XWUtDeV/lRKWPKSdTuV0TZvrmrQA=
-github.com/oklog/ulid v0.0.0-20170117200651-66bb6560562f/go.mod h1:CirwcVhetQ6Lv90oh/F+FBtV6XMibvdAFo93nm5qn4U=
 github.com/oklog/ulid v1.3.1/go.mod h1:CirwcVhetQ6Lv90oh/F+FBtV6XMibvdAFo93nm5qn4U=
 github.com/olekukonko/tablewriter v0.0.0-20170122224234-a0225b3f23b5/go.mod h1:vsDQFd/mU46D+Z4whnwzcISnGGzXWMclvtLoiIKAKIo=
-github.com/olekukonko/tablewriter v0.0.1/go.mod h1:vsDQFd/mU46D+Z4whnwzcISnGGzXWMclvtLoiIKAKIo=
-github.com/olekukonko/tablewriter v0.0.2/go.mod h1:rSAaSIOAGT9odnlyGlUfAJaoc5w2fSBUmeGDbRWPxyQ=
 github.com/olekukonko/tablewriter v0.0.4/go.mod h1:zq6QwlOf5SlnkVbMSr5EoBv3636FWnp+qbPhuoO21uA=
 github.com/onsi/ginkgo v0.0.0-20170829012221-11459a886d9c/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
 github.com/onsi/ginkgo v1.4.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
 github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
-github.com/onsi/ginkgo v1.7.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
-github.com/onsi/ginkgo v1.8.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
-github.com/onsi/ginkgo v1.10.1/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
-github.com/onsi/ginkgo v1.10.3/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
 github.com/onsi/ginkgo v1.11.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
-github.com/onsi/ginkgo v1.12.0/go.mod h1:oUhWkIvk5aDxtKvDDuw8gItl8pKl42LzjC9KZE0HfGg=
+github.com/onsi/ginkgo v1.12.1 h1:mFwc4LvZ0xpSvDZ3E+k8Yte0hLOMxXUlP+yXtJqkYfQ=
 github.com/onsi/ginkgo v1.12.1/go.mod h1:zj2OWP4+oCPe1qIXoGWkgMRwljMUYCdkwsT2108oapk=
 github.com/onsi/gomega v0.0.0-20170829124025-dcabb60a477c/go.mod h1:C1qb7wdrVGGVU+Z6iS04AVkA3Q65CEZX59MT0QO5uiA=
 github.com/onsi/gomega v1.3.0/go.mod h1:C1qb7wdrVGGVU+Z6iS04AVkA3Q65CEZX59MT0QO5uiA=
-github.com/onsi/gomega v1.4.3/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY=
-github.com/onsi/gomega v1.5.0/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY=
 github.com/onsi/gomega v1.7.0/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY=
 github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY=
 github.com/onsi/gomega v1.8.1/go.mod h1:Ho0h+IUsWyvy1OpqCwxlQ/21gkhVunqlU8fDGcoTdcA=
-github.com/onsi/gomega v1.9.0/go.mod h1:Ho0h+IUsWyvy1OpqCwxlQ/21gkhVunqlU8fDGcoTdcA=
+github.com/onsi/gomega v1.10.1 h1:o0+MgICZLuZ7xjH7Vx6zS/zcu93/BEp1VwkIW1mEXCE=
 github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo=
-github.com/opencontainers/go-digest v0.0.0-20170106003457-a6d0ee40d420/go.mod h1:cMLVZDEM3+U2I4VmLI6N8jQYUd2OVphdqWwCJHrFt2s=
-github.com/opencontainers/go-digest v0.0.0-20180430190053-c9281466c8b2/go.mod h1:cMLVZDEM3+U2I4VmLI6N8jQYUd2OVphdqWwCJHrFt2s=
 github.com/opencontainers/go-digest v1.0.0-rc1/go.mod h1:cMLVZDEM3+U2I4VmLI6N8jQYUd2OVphdqWwCJHrFt2s=
-github.com/opencontainers/image-spec v1.0.0/go.mod h1:BtxoFyWECRxE4U/7sNtV5W15zMzWCbyJoFRP3s7yZA0=
-github.com/opencontainers/image-spec v1.0.1/go.mod h1:BtxoFyWECRxE4U/7sNtV5W15zMzWCbyJoFRP3s7yZA0=
-github.com/opencontainers/image-spec v1.0.2-0.20190823105129-775207bd45b6/go.mod h1:BtxoFyWECRxE4U/7sNtV5W15zMzWCbyJoFRP3s7yZA0=
-github.com/opencontainers/runc v0.0.0-20190115041553-12f6a991201f/go.mod h1:qT5XzbpPznkRYVz/mWwUaVBUv2rmF59PVA73FjuZG0U=
-github.com/opencontainers/runc v0.1.1/go.mod h1:qT5XzbpPznkRYVz/mWwUaVBUv2rmF59PVA73FjuZG0U=
-github.com/opencontainers/runtime-spec v0.1.2-0.20190507144316-5b71a03e2700/go.mod h1:jwyrGlmzljRJv/Fgzds9SsS/C5hL+LL3ko9hs6T5lQ0=
-github.com/opencontainers/runtime-tools v0.0.0-20181011054405-1d69bd0f9c39/go.mod h1:r3f7wjNzSs2extwzU3Y+6pKfobzPh+kKFJ3ofN+3nfs=
-github.com/openshift/origin v0.0.0-20160503220234-8f127d736703/go.mod h1:0Rox5r9C8aQn6j1oAOQ0c1uC86mYbUFObzjBRvUKHII=
-github.com/openshift/prom-label-proxy v0.1.1-0.20191016113035-b8153a7f39f1/go.mod h1:p5MuxzsYP1JPsNGwtjtcgRHHlGziCJJfztff91nNixw=
-github.com/opentracing-contrib/go-stdlib v0.0.0-20190519235532-cf7a6c988dc9/go.mod h1:PLldrQSroqzH70Xl+1DQcGnefIbqsKR7UDaiux3zV+w=
-github.com/opentracing/basictracer-go v1.0.0/go.mod h1:QfBfYuafItcjQuMwinw9GhYKwFXS9KnPs5lxoYwgW74=
-github.com/opentracing/opentracing-go v1.0.2/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o=
-github.com/opentracing/opentracing-go v1.1.0/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o=
-github.com/openzipkin/zipkin-go v0.1.6/go.mod h1:QgAqvLzwWbR/WpD4A3cGpPtJrZXNIiJc5AZX7/PBEpw=
-github.com/operator-framework/api v0.3.7-0.20200602203552-431198de9fc2/go.mod h1:Xbje9x0SHmh0nihE21kpesB38vk3cyxnE6JdDS8Jo1Q=
-github.com/operator-framework/api v0.3.8/go.mod h1:Xbje9x0SHmh0nihE21kpesB38vk3cyxnE6JdDS8Jo1Q=
-github.com/operator-framework/operator-registry v1.12.6-0.20200611222234-275301b779f8/go.mod h1:loVINznYhgBIkmv83kU4yee88RS0BBk+hqOw9r4bhJk=
-github.com/operator-framework/operator-sdk v0.19.0/go.mod h1:8MR6CguLizat2RGjdSMifGwW6mEMwKqAtZnSUHJ6SxU=
-github.com/otiai10/copy v1.2.0/go.mod h1:rrF5dJ5F0t/EWSYODDu4j9/vEeYHMkc8jt0zJChqQWw=
-github.com/otiai10/curr v0.0.0-20150429015615-9b4961190c95/go.mod h1:9qAhocn7zKJG+0mI8eUu6xqkFDYS2kb2saOteoSB3cE=
-github.com/otiai10/curr v1.0.0/go.mod h1:LskTG5wDwr8Rs+nNQ+1LlxRjAtTZZjtJW4rMXl6j4vs=
-github.com/otiai10/mint v1.3.0/go.mod h1:F5AjcsTsWUqX+Na9fpHb52P8pcRX2CI6A3ctIT91xUo=
-github.com/otiai10/mint v1.3.1/go.mod h1:/yxELlJQ0ufhjUwhshSj+wFjZ78CnZ48/1wtmBH1OTc=
 github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc=
 github.com/pascaldekloe/goe v0.1.0/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc=
 github.com/pavel-v-chernykh/keystore-go v2.1.0+incompatible/go.mod h1:xlUlxe/2ItGlQyMTstqeDv9r3U4obH7xYd26TbDQutY=
 github.com/pborman/uuid v1.2.0/go.mod h1:X/NO0urCmaxf9VXbdlT7C2Yzkj2IKimNn4k+gtPdI/k=
 github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic=
 github.com/peterbourgon/diskv v2.0.1+incompatible/go.mod h1:uqqh8zWWbv1HBMNONnaR/tNboyR3/BZd58JJSHlUSCU=
-github.com/phayes/freeport v0.0.0-20180830031419-95f893ade6f2/go.mod h1:iIss55rKnNBTvrwdmkUpLnDpZoAHvWaiq5+iMmen4AE=
 github.com/pierrec/lz4 v2.0.5+incompatible/go.mod h1:pdkljMzZIN41W+lC3N2tnIh5sFi+IEE17M5jbnwPHcY=
 github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
-github.com/pkg/errors v0.8.1-0.20171018195549-f15c970de5b7/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
 github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
 github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
 github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
-github.com/pmezard/go-difflib v0.0.0-20151028094244-d8ed2627bdf0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
 github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
 github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
 github.com/posener/complete v1.1.1/go.mod h1:em0nMJCgc9GFtwrmVmEMR/ZL6WyhyjMBndrE9hABlRI=
-github.com/prometheus/alertmanager v0.18.0/go.mod h1:WcxHBl40VSPuOaqWae6l6HpnEOVRIycEJ7i9iYkadEE=
-github.com/prometheus/alertmanager v0.20.0/go.mod h1:9g2i48FAyZW6BtbsnvHtMHQXl2aVtrORKwKVCQ+nbrg=
-github.com/prometheus/client_golang v0.0.0-20180209125602-c332b6f63c06/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw=
 github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw=
-github.com/prometheus/client_golang v0.9.2/go.mod h1:OsXs2jCmiKlQ1lTBmv21f2mNfw4xf/QclQDMrYNZzcM=
-github.com/prometheus/client_golang v0.9.3-0.20190127221311-3c4408c8b829/go.mod h1:p2iRAGwDERtqlqzRXnrOVns+ignqQo//hLXqYxZYVNs=
 github.com/prometheus/client_golang v0.9.3/go.mod h1:/TN21ttK/J9q6uSwhBd54HahCDft0ttaMvbicHlPoso=
 github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo=
-github.com/prometheus/client_golang v1.1.0/go.mod h1:I1FGZT9+L76gKKOs5djB6ezCbFQP1xR9D75/vuwEF3g=
-github.com/prometheus/client_golang v1.2.0/go.mod h1:XMU6Z2MjaRKVu/dC1qupJI9SiNkDYzz3xecMgSW/F+U=
-github.com/prometheus/client_golang v1.2.1/go.mod h1:XMU6Z2MjaRKVu/dC1qupJI9SiNkDYzz3xecMgSW/F+U=
-github.com/prometheus/client_golang v1.5.1/go.mod h1:e9GMxYsXl05ICDXkRhurwBS4Q3OK1iX/F2sw+iXX5zU=
 github.com/prometheus/client_golang v1.7.1 h1:NTGy1Ja9pByO+xAeH/qiWnLrKtr3hJPNjaVUwnjpdpA=
 github.com/prometheus/client_golang v1.7.1/go.mod h1:PY5Wy2awLA44sXw4AOSfFBetzPP4j5+D6mVACh+pe2M=
-github.com/prometheus/client_model v0.0.0-20171117100541-99fa1f4be8e5/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo=
 github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo=
-github.com/prometheus/client_model v0.0.0-20190115171406-56726106282f/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo=
 github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
 github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
 github.com/prometheus/client_model v0.2.0 h1:uq5h0d+GuxiXLJLNABMgp2qUWDPiLvgCzz2dUR+/W/M=
 github.com/prometheus/client_model v0.2.0/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
-github.com/prometheus/common v0.0.0-20180110214958-89604d197083/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro=
 github.com/prometheus/common v0.0.0-20181113130724-41aa239b4cce/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro=
-github.com/prometheus/common v0.0.0-20181126121408-4724e9255275/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro=
-github.com/prometheus/common v0.2.0/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4=
 github.com/prometheus/common v0.4.0/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4=
 github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4=
-github.com/prometheus/common v0.6.0/go.mod h1:eBmuwkDJBwy6iBfxCBob6t6dR6ENT/y+J+Zk0j9GMYc=
-github.com/prometheus/common v0.7.0/go.mod h1:DjGbpBbp5NYNiECxcL/VnbXCCaQpKd3tt26CguLLsqA=
-github.com/prometheus/common v0.9.1/go.mod h1:yhUN8i9wzaXS3w1O07YhxHEBxD+W35wd8bs7vj7HSQ4=
 github.com/prometheus/common v0.10.0 h1:RyRA7RzGXQZiW+tGMr7sxa85G1z0yOpM1qq5c8lNawc=
 github.com/prometheus/common v0.10.0/go.mod h1:Tlit/dnDKsSWFlCLTWaA1cyBgKHSMdTB80sz/V91rCo=
-github.com/prometheus/procfs v0.0.0-20180125133057-cb4147076ac7/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk=
 github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk=
-github.com/prometheus/procfs v0.0.0-20181204211112-1dc9a6cbc91a/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk=
-github.com/prometheus/procfs v0.0.0-20190117184657-bf6a532e95b1/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk=
-github.com/prometheus/procfs v0.0.0-20190425082905-87a4384529e0/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA=
 github.com/prometheus/procfs v0.0.0-20190507164030-5867b95ac084/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA=
-github.com/prometheus/procfs v0.0.0-20190522114515-bc1a522cf7b1/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA=
 github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA=
-github.com/prometheus/procfs v0.0.3/go.mod h1:4A/X28fw3Fc593LaREMrKMqOKvUAntwMDaekg4FpcdQ=
-github.com/prometheus/procfs v0.0.5/go.mod h1:4A/X28fw3Fc593LaREMrKMqOKvUAntwMDaekg4FpcdQ=
-github.com/prometheus/procfs v0.0.6/go.mod h1:7Qr8sr6344vo1JqZ6HhLceV9o3AJ1Ff+GxbHq6oeK9A=
-github.com/prometheus/procfs v0.0.8/go.mod h1:7Qr8sr6344vo1JqZ6HhLceV9o3AJ1Ff+GxbHq6oeK9A=
 github.com/prometheus/procfs v0.0.11/go.mod h1:lV6e/gmhEcM9IjHGsFOCxxuZ+z1YqCvr4OA4YeYWdaU=
 github.com/prometheus/procfs v0.1.3 h1:F0+tqvhOksq22sc6iCHF5WGlWjdwj92p0udFh1VFBS8=
 github.com/prometheus/procfs v0.1.3/go.mod h1:lV6e/gmhEcM9IjHGsFOCxxuZ+z1YqCvr4OA4YeYWdaU=
-github.com/prometheus/prometheus v0.0.0-20180315085919-58e2a31db8de/go.mod h1:oAIUtOny2rjMX0OWN5vPR5/q/twIROJvdqnQKDdil/s=
-github.com/prometheus/prometheus v1.8.2-0.20200110114423-1e64d757f711/go.mod h1:7U90zPoLkWjEIQcy/rweQla82OCTUzxVHE51G3OhJbI=
-github.com/prometheus/prometheus v2.3.2+incompatible/go.mod h1:oAIUtOny2rjMX0OWN5vPR5/q/twIROJvdqnQKDdil/s=
 github.com/prometheus/tsdb v0.7.1/go.mod h1:qhTCs0VvXwvX/y3TZrWD7rabWM+ijKTux40TwIPHuXU=
-github.com/rcrowley/go-metrics v0.0.0-20181016184325-3113b8401b8a/go.mod h1:bCqnVzQkZxMG4s8nGwiZ5l3QUCyqpo9Y+/ZMZ9VjZe4=
-github.com/robfig/cron v0.0.0-20170526150127-736158dc09e1/go.mod h1:JGuDeoQd7Z6yL4zQhZ3OPEVHB7fL6Ka6skscFHfmt2k=
 github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6SoW27p1b0cqNHllgS5HIMJraePCO15w5zCzIWYg=
-github.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ=
-github.com/rogpeppe/go-internal v1.1.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
 github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
-github.com/rogpeppe/go-internal v1.3.2/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTEfhy4qGm1nDQc=
-github.com/rogpeppe/go-internal v1.4.0/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTEfhy4qGm1nDQc=
-github.com/rogpeppe/go-internal v1.5.0/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTEfhy4qGm1nDQc=
-github.com/rs/cors v1.6.0/go.mod h1:gFx+x8UowdsKA9AchylcLynDq+nNFfI8FkUZdN/jGCU=
-github.com/rubenv/sql-migrate v0.0.0-20200212082348-64f95ea68aa3/go.mod h1:rtQlpHw+eR6UrqaS3kX1VYeaCxzCVdimDS7g5Ln4pPc=
 github.com/russross/blackfriday v1.5.2/go.mod h1:JO/DiYxRf+HjHt06OyowR9PTA263kcR/rfWxYHBV53g=
 github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
 github.com/ryanuber/columnize v0.0.0-20160712163229-9b3edd62028f/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts=
 github.com/ryanuber/columnize v2.1.0+incompatible/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts=
 github.com/ryanuber/go-glob v1.0.0/go.mod h1:807d1WSdnB0XRJzKNil9Om6lcp/3a0v4qIHxIXzX/Yc=
-github.com/samuel/go-zookeeper v0.0.0-20190810000440-0ceca61e4d75/go.mod h1:gi+0XIa01GRL2eRQVjQkKGqKF3SF9vZR/HnPullcV2E=
-github.com/samuel/go-zookeeper v0.0.0-20190923202752-2cc03de413da/go.mod h1:gi+0XIa01GRL2eRQVjQkKGqKF3SF9vZR/HnPullcV2E=
-github.com/santhosh-tekuri/jsonschema v1.2.4/go.mod h1:TEAUOeZSmIxTTuHatJzrvARHiuO9LYd+cIxzgEHCQI4=
-github.com/satori/go.uuid v0.0.0-20160603004225-b111a074d5ef/go.mod h1:dA0hQrYB0VpLJoorglMZABFdXlWrHn1NEOzdhQKdks0=
-github.com/satori/go.uuid v1.2.0/go.mod h1:dA0hQrYB0VpLJoorglMZABFdXlWrHn1NEOzdhQKdks0=
-github.com/sclevine/spec v1.2.0/go.mod h1:W4J29eT/Kzv7/b9IWLB055Z+qvVC9vt0Arko24q7p+U=
 github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529/go.mod h1:DxrIzT+xaE7yg65j358z/aeFdxmN0P9QXhEzd20vsDc=
 github.com/sergi/go-diff v1.0.0/go.mod h1:0CfEIISq7TuYL3j771MWULgwwjU+GofnZX9QAmXWZgo=
 github.com/sergi/go-diff v1.1.0/go.mod h1:STckp+ISIX8hZLjrqAeVduY0gWCT9IjLuqbuNXdaHfM=
-github.com/shopspring/decimal v0.0.0-20180709203117-cd690d0c9e24/go.mod h1:M+9NzErvs504Cn4c5DxATwIqPbtswREoFCre64PpcG4=
-github.com/shurcooL/httpfs v0.0.0-20171119174359-809beceb2371/go.mod h1:ZY1cvUeJuFPAdZ/B6v7RHavJWZn2YPVFQ1OSXhCGOkg=
-github.com/shurcooL/httpfs v0.0.0-20190707220628-8d4bc4ba7749/go.mod h1:ZY1cvUeJuFPAdZ/B6v7RHavJWZn2YPVFQ1OSXhCGOkg=
 github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc=
-github.com/shurcooL/vfsgen v0.0.0-20180825020608-02ddb050ef6b/go.mod h1:TrYk7fJVaAttu97ZZKrO9UbRa8izdowaMIZcxYMbVaw=
-github.com/shurcooL/vfsgen v0.0.0-20181202132449-6a9ea43bcacd/go.mod h1:TrYk7fJVaAttu97ZZKrO9UbRa8izdowaMIZcxYMbVaw=
-github.com/sirupsen/logrus v1.0.4-0.20170822132746-89742aefa4b2/go.mod h1:pMByvHTf9Beacp5x1UXfOR9xyW/9antXMhjMPG0dEzc=
 github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo=
-github.com/sirupsen/logrus v1.4.1/go.mod h1:ni0Sbl8bgC9z8RoU9G6nDWqqs/fq4eDPysMBDgk/93Q=
 github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE=
-github.com/sirupsen/logrus v1.5.0/go.mod h1:+F7Ogzej0PZc/94MaYx/nvG9jOFMD2osvC3s+Squfpo=
 github.com/sirupsen/logrus v1.6.0/go.mod h1:7uNnSEd1DgxDLC74fIahvMZmmYsHGZGEOFrfsX/uA88=
-github.com/sirupsen/logrus v1.7.0 h1:ShrD1U9pZB12TX0cVy0DtePoCH97K8EtX+mg7ZARUtM=
-github.com/sirupsen/logrus v1.7.0/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0=
+github.com/sirupsen/logrus v1.8.1 h1:dJKuHgqk1NNQlqoA6BTlM1Wf9DOH3NBjQyu0h9+AZZE=
+github.com/sirupsen/logrus v1.8.1/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0=
 github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc=
-github.com/smartystreets/assertions v1.0.1/go.mod h1:kHHU4qYBaI3q23Pp3VPrmWhuIUrLW/7eUrw0BU5VaoM=
 github.com/smartystreets/assertions v1.2.0/go.mod h1:tcbTF8ujkAEcZ8TElKY+i30BzYlVhC/LOxJk7iOWnoo=
-github.com/smartystreets/goconvey v0.0.0-20190330032615-68dc04aab96a/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA=
 github.com/smartystreets/goconvey v1.6.4/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA=
 github.com/soheilhy/cmux v0.1.4 h1:0HKaf1o97UwFjHH9o5XsHUOF+tqmdA7KEzXLpiyaw0E=
 github.com/soheilhy/cmux v0.1.4/go.mod h1:IM3LyeVVIOuxMH7sFAkER9+bJ4dT7Ms6E4xg4kGIyLM=
 github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA=
-github.com/spaolacci/murmur3 v1.1.0/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA=
 github.com/spf13/afero v1.1.2/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B0CQ=
 github.com/spf13/afero v1.2.2/go.mod h1:9ZxEEn6pIJ8Rxe320qSDBk6AsU0r9pR7Q4OcevTdifk=
 github.com/spf13/cast v1.3.0/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE=
-github.com/spf13/cast v1.3.1/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE=
-github.com/spf13/cobra v0.0.2-0.20171109065643-2da4a54c5cee/go.mod h1:1l0Ry5zgKvJasoi3XT1TypsSe7PqH0Sj9dhYf7v3XqQ=
 github.com/spf13/cobra v0.0.3/go.mod h1:1l0Ry5zgKvJasoi3XT1TypsSe7PqH0Sj9dhYf7v3XqQ=
 github.com/spf13/cobra v0.0.5/go.mod h1:3K3wKZymM7VvHMDS9+Akkh4K60UwM26emMESw8tLCHU=
-github.com/spf13/cobra v0.0.6/go.mod h1:/6GTrnGXV9HjY+aR4k0oJ5tcvakLuG6EuKReYlHNrgE=
-github.com/spf13/cobra v0.0.7/go.mod h1:/6GTrnGXV9HjY+aR4k0oJ5tcvakLuG6EuKReYlHNrgE=
 github.com/spf13/cobra v1.0.0/go.mod h1:/6GTrnGXV9HjY+aR4k0oJ5tcvakLuG6EuKReYlHNrgE=
-github.com/spf13/cobra v1.1.1/go.mod h1:WnodtKOvamDL/PwE2M4iKs8aMDBZ5Q5klgD3qfVJQMI=
 github.com/spf13/jwalterweatherman v1.0.0/go.mod h1:cQK4TGJAtQXfYWX+Ddv3mKDzgVb68N+wFjFa4jdeBTo=
 github.com/spf13/pflag v0.0.0-20170130214245-9ff6c6923cff/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4=
-github.com/spf13/pflag v1.0.1-0.20171106142849-4c012f6dcd95/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4=
 github.com/spf13/pflag v1.0.1/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4=
 github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4=
 github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA=
@@ -853,125 +537,105 @@ github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An
 github.com/spf13/viper v1.3.2/go.mod h1:ZiWeW+zYFKm7srdB9IoDzzZXaJaI5eL9QjNiN/DMA2s=
 github.com/spf13/viper v1.4.0/go.mod h1:PTJ7Z/lr49W6bUbkmS1V3by4uWynFiR9p7+dSq/yZzE=
 github.com/spf13/viper v1.7.0/go.mod h1:8WkrPz2fc9jxqZNCJI/76HCieCp4Q8HaLFoCha5qpdg=
+github.com/stoewer/go-strcase v1.2.0/go.mod h1:IBiWB2sKIp3wVVQ3Y035++gc+knqhUQag1KpM8ahLw8=
 github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
 github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
 github.com/stretchr/objx v0.2.0/go.mod h1:qt09Ya8vawLte6SNmTgCsAVtYtaKzEcn8ATUoHMkEqE=
-github.com/stretchr/testify v0.0.0-20151208002404-e3a8ff8ce365/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
 github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
 github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
 github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
 github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA=
-github.com/stretchr/testify v1.6.1 h1:hDPOHmpOpP40lSULcqw7IrRb/u7w6RpDC9399XyoNd0=
 github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
+github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY=
 github.com/subosito/gotenv v1.2.0/go.mod h1:N0PQaV/YGNqwC0u51sEeR/aUtSLEXKX9iv69rRypqCw=
-github.com/syndtr/gocapability v0.0.0-20170704070218-db04d3cc01c8/go.mod h1:hkRG7XYTFWNJGYcbNJQlaLq0fg1yr4J4t/NcTQtrfww=
-github.com/thanos-io/thanos v0.11.0/go.mod h1:N/Yes7J68KqvmY+xM6J5CJqEvWIvKSR5sqGtmuD6wDc=
-github.com/tidwall/pretty v0.0.0-20180105212114-65a9db5fad51/go.mod h1:XNkn88O1ChpSDQmQeStsy+sBenx6DDtFZJxhVysOjyk=
-github.com/tidwall/pretty v1.0.0 h1:HsD+QiTn7sK6flMKIvNmpqz1qrpP3Ps6jOKIKMooyg4=
+github.com/tidwall/gjson v1.14.0 h1:6aeJ0bzojgWLa82gDQHcx3S0Lr/O51I9bJ5nv6JFx5w=
+github.com/tidwall/gjson v1.14.0/go.mod h1:/wbyibRr2FHMks5tjHJ5F8dMZh3AcwJEMf5vlfC0lxk=
+github.com/tidwall/match v1.1.1 h1:+Ho715JplO36QYgwN9PGYNhgZvoUSc9X2c80KVTi+GA=
+github.com/tidwall/match v1.1.1/go.mod h1:eRSPERbgtNPcGhD8UCthc6PmLEQXEWd3PRB5JTxsfmM=
 github.com/tidwall/pretty v1.0.0/go.mod h1:XNkn88O1ChpSDQmQeStsy+sBenx6DDtFZJxhVysOjyk=
+github.com/tidwall/pretty v1.2.0 h1:RWIZEg2iJ8/g6fDDYzMpobmaoGh5OLl4AXtGUGPcqCs=
+github.com/tidwall/pretty v1.2.0/go.mod h1:ITEVvHYasfjBbM0u2Pg8T2nJnzm8xPwvNhhsoaGGjNU=
 github.com/tmc/grpc-websocket-proxy v0.0.0-20170815181823-89b8d40f7ca8/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U=
 github.com/tmc/grpc-websocket-proxy v0.0.0-20190109142713-0ad062ec5ee5 h1:LnC5Kc/wtumK+WB441p7ynQJzVuNRJiqddSIE3IlSEQ=
 github.com/tmc/grpc-websocket-proxy v0.0.0-20190109142713-0ad062ec5ee5/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U=
-github.com/tv42/httpunix v0.0.0-20150427012821-b75d8614f926/go.mod h1:9ESjWnEqriFuLhtthL60Sar/7RFoluCcXsuvEwTV5KM=
-github.com/uber/jaeger-client-go v2.20.1+incompatible/go.mod h1:WVhlPFC8FDjOFMMWRy2pZqQJSXxYSwNYOkTr/Z6d3Kk=
-github.com/uber/jaeger-lib v2.2.0+incompatible/go.mod h1:ComeNDZlWwrWnDv8aPp0Ba6+uUTzImX/AauajbLI56U=
 github.com/ugorji/go v1.1.4/go.mod h1:uQMGLiO92mf5W77hV/PUCpI3pbzQx3CRekS0kk+RGrc=
 github.com/ugorji/go/codec v0.0.0-20181204163529-d75b2dcb6bc8/go.mod h1:VFNgLljTbGfSG7qAOspJ7OScBnGdDN/yBr0sguwnwf0=
-github.com/urfave/cli v0.0.0-20171014202726-7bc6a0acffa5/go.mod h1:70zkFmudgCuE/ngEzBv17Jvp/497gISqfk5gWijbERA=
 github.com/urfave/cli v1.20.0/go.mod h1:70zkFmudgCuE/ngEzBv17Jvp/497gISqfk5gWijbERA=
 github.com/urfave/cli v1.22.4/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0=
 github.com/urfave/cli/v2 v2.1.1/go.mod h1:SE9GqnLQmjVa0iPEY0f1w3ygNIYcIJ0OKPMoW2caLfQ=
 github.com/vektah/gqlparser v1.1.2/go.mod h1:1ycwN7Ij5njmMkPPAOaRFY4rET2Enx7IkVv3vaXspKw=
-github.com/xanzy/go-gitlab v0.15.0/go.mod h1:8zdQa/ri1dfn8eS3Ir1SyfvOKlw7WBJ8DVThkpGiXrs=
-github.com/xdg/scram v0.0.0-20180814205039-7eeb5667e42c h1:u40Z8hqBAAQyv+vATcGgV0YCnDjqSL7/q/JyPhhJSPk=
-github.com/xdg/scram v0.0.0-20180814205039-7eeb5667e42c/go.mod h1:lB8K/P019DLNhemzwFU4jHLhdvlE6uDZjXFejJXr49I=
-github.com/xdg/stringprep v1.0.0 h1:d9X0esnoa3dFsV0FG35rAT0RIhYFlPq7MiP+DW89La0=
-github.com/xdg/stringprep v1.0.0/go.mod h1:Jhud4/sHMO4oL310DaZAKk9ZaJ08SJfe+sJh0HrGL1Y=
+github.com/xdg-go/pbkdf2 v1.0.0 h1:Su7DPu48wXMwC3bs7MCNG+z4FhcyEuz5dlvchbq0B0c=
+github.com/xdg-go/pbkdf2 v1.0.0/go.mod h1:jrpuAogTd400dnrH08LKmI/xc1MbPOebTwRqcT5RDeI=
+github.com/xdg-go/scram v1.0.2 h1:akYIkZ28e6A96dkWNJQu3nmCzH3YfwMPQExUYDaRv7w=
+github.com/xdg-go/scram v1.0.2/go.mod h1:1WAq6h33pAW+iRreB34OORO2Nf7qel3VV3fjBj+hCSs=
+github.com/xdg-go/stringprep v1.0.2 h1:6iq84/ryjjeRmMJwxutI51F2GIPlP5BfTvXHeYjyhBc=
+github.com/xdg-go/stringprep v1.0.2/go.mod h1:8F9zXuvzgwmyT5DUm4GUfZGDdT3W+LCvS6+da4O5kxM=
 github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f h1:J9EGpcZtP0E/raorCMxlFGSTBrsSlaDGf3jU/qvAE2c=
 github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f/go.mod h1:N2zxlSyiKSe5eX1tZViRH5QA0qijqEDrYZiPEAiq3wU=
 github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415 h1:EzJWgHovont7NscjpAxXsDA8S8BMYve8Y5+7cuRE7R0=
 github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415/go.mod h1:GwrjFmJcFw6At/Gs6z4yjiIwzuJ1/+UwLxMQDVQXShQ=
-github.com/xeipuuv/gojsonschema v0.0.0-20180618132009-1d523034197f/go.mod h1:5yf86TLmAcydyeJq5YvxkGPE2fm/u4myDekKRoLuqhs=
-github.com/xeipuuv/gojsonschema v1.1.0 h1:ngVtJC9TY/lg0AA/1k48FYhBrhRoFlEmWzsehpNAaZg=
-github.com/xeipuuv/gojsonschema v1.1.0/go.mod h1:5yf86TLmAcydyeJq5YvxkGPE2fm/u4myDekKRoLuqhs=
+github.com/xeipuuv/gojsonschema v1.2.0 h1:LhYJRs+L4fBtjZUfuSZIKGeVu0QRy8e5Xi7D17UxZ74=
+github.com/xeipuuv/gojsonschema v1.2.0/go.mod h1:anYRn/JVcOK2ZgGU+IjEV4nwlhoK5sQluxsYJ78Id3Y=
 github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2 h1:eY9dn8+vbi4tKz5Qo6v2eYzo7kUS51QINcR5jNpbZS8=
 github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU=
 github.com/xlab/handysort v0.0.0-20150421192137-fb3537ed64a1/go.mod h1:QcJo0QPSfTONNIgpN5RA8prR7fF8nkF6cTWTcNerRO8=
-github.com/xlab/treeprint v0.0.0-20180616005107-d6fb6747feb6/go.mod h1:ce1O1j6UtZfjr22oyGxGLbauSBp2YVXpARAosm7dHBg=
 github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77/go.mod h1:aYKd//L2LvnjZzWKhF00oedf4jCCReLcmhLdhm1A27Q=
+github.com/youmark/pkcs8 v0.0.0-20181117223130-1be2e3e5546d h1:splanxYIlg+5LfHAM6xpdFEAYOk8iySO56hMFq6uLyA=
+github.com/youmark/pkcs8 v0.0.0-20181117223130-1be2e3e5546d/go.mod h1:rHwXgn7JulP+udvsHwJoVG1YGAP6VLg4y9I5dyZdqmA=
+github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
 github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
-github.com/yvasiyarov/go-metrics v0.0.0-20140926110328-57bccd1ccd43/go.mod h1:aX5oPXxHm3bOH+xeAttToC8pqch2ScQN/JoXYupl6xs=
-github.com/yvasiyarov/gorelic v0.0.0-20141212073537-a9bba5b9ab50/go.mod h1:NUSPSUX/bi6SeDMUh6brw0nXpxHnc96TguQh0+r/ssA=
-github.com/yvasiyarov/newrelic_platform_go v0.0.0-20140908184405-b21fdbd4370f/go.mod h1:GlGEuHIJweS1mbCqG+7vt2nvWLzLLnRHbXz5JKd/Qbg=
-github.com/ziutek/mymysql v1.5.4/go.mod h1:LMSpPZ6DbqWFxNCHW77HeMg9I646SAhApZ/wKdgO/C0=
-gitlab.com/nyarla/go-crypt v0.0.0-20160106005555-d9a5dc2b789b/go.mod h1:T3BPAOm2cqquPa0MKWeNkmOM5RQsRhkrwMWonFMN7fE=
-go.elastic.co/apm v1.5.0/go.mod h1:OdB9sPtM6Vt7oz3VXt7+KR96i9li74qrxBGHTQygFvk=
-go.elastic.co/apm/module/apmhttp v1.5.0/go.mod h1:1FbmNuyD3ddauwzgVwFB0fqY6KbZt3JkV187tGCYYhY=
-go.elastic.co/apm/module/apmot v1.5.0/go.mod h1:d2KYwhJParTpyw2WnTNy8geNlHKKFX+4oK3YLlsesWE=
-go.elastic.co/fastjson v1.0.0/go.mod h1:PmeUOMMtLHQr9ZS9J9owrAVg0FkaZDRZJEFTTGHtchs=
+github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
+github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
+github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k=
 go.etcd.io/bbolt v1.3.2/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU=
 go.etcd.io/bbolt v1.3.3/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU=
-go.etcd.io/bbolt v1.3.4/go.mod h1:G5EMThwa9y8QZGBClrRx5EY+Yw9kAhnjy3bSjsnlVTQ=
 go.etcd.io/etcd v0.5.0-alpha.5.0.20200819165624-17cef6e3e9d5/go.mod h1:skWido08r9w6Lq/w70DO5XYIKMu4QFu1+4VsqLQuJy8=
 go.etcd.io/etcd v3.3.12+incompatible h1:V6PRYRGpU4k5EajJaaj/GL3hqIdzyPnBU8aPUp+35yw=
 go.etcd.io/etcd v3.3.12+incompatible/go.mod h1:yaeTdrJi5lOmYerz05bd8+V7KubZs8YSFZfzsF9A6aI=
 go.mongodb.org/mongo-driver v1.0.3/go.mod h1:u7ryQJ+DOzQmeO7zB6MHyr8jkEQvC8vH7qLUO4lqsUM=
-go.mongodb.org/mongo-driver v1.1.0/go.mod h1:u7ryQJ+DOzQmeO7zB6MHyr8jkEQvC8vH7qLUO4lqsUM=
 go.mongodb.org/mongo-driver v1.1.1/go.mod h1:u7ryQJ+DOzQmeO7zB6MHyr8jkEQvC8vH7qLUO4lqsUM=
-go.mongodb.org/mongo-driver v1.1.2 h1:jxcFYjlkl8xaERsgLo+RNquI0epW6zuy/ZRQs6jnrFA=
 go.mongodb.org/mongo-driver v1.1.2/go.mod h1:u7ryQJ+DOzQmeO7zB6MHyr8jkEQvC8vH7qLUO4lqsUM=
-go.opencensus.io v0.20.1/go.mod h1:6WKK9ahsWS3RSO+PY9ZHZUfv2irvY6gN279GOPZjmmk=
-go.opencensus.io v0.20.2/go.mod h1:6WKK9ahsWS3RSO+PY9ZHZUfv2irvY6gN279GOPZjmmk=
+go.mongodb.org/mongo-driver v1.8.4 h1:NruvZPPL0PBcRJKmbswoWSrmHeUvzdxA3GCPfD/NEOA=
+go.mongodb.org/mongo-driver v1.8.4/go.mod h1:0sQWfOeY63QTntERDJJ/0SuKK0T1uVSgKCuAROlKEPY=
 go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU=
 go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8=
 go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
+go.opencensus.io v0.22.3/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
+go.opencensus.io v0.22.4/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
 go.uber.org/atomic v1.3.2/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE=
 go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE=
-go.uber.org/atomic v1.5.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ=
-go.uber.org/atomic v1.6.0 h1:Ezj3JGmsOnG1MoRWQkPBsKLe9DwWD9QeXzTRzzldNVk=
-go.uber.org/atomic v1.6.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ=
-go.uber.org/automaxprocs v1.2.0/go.mod h1:YfO3fm683kQpzETxlTGZhGIVmXAhaw3gxeBADbpZtnU=
+go.uber.org/atomic v1.7.0 h1:ADUqmZGgLDDfbSL9ZmPxKTybcoEYHgpYfELNoN+7hsw=
 go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0=
-go.uber.org/multierr v1.5.0 h1:KCa4XfM8CWFCpxXRGok+Q0SS/0XBhMDbHHGABQLvD2A=
-go.uber.org/multierr v1.5.0/go.mod h1:FeouvMocqHpRaaGuG9EjoKcStLC43Zu/fmqdUMPcKYU=
-go.uber.org/tools v0.0.0-20190618225709-2cfd321de3ee/go.mod h1:vJERXedbb3MVM5f9Ejo0C68/HhF8uaILCdgjnY+goOA=
-go.uber.org/zap v1.8.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q=
+go.uber.org/multierr v1.6.0 h1:y6IPFStTAIT5Ytl7/XYmHvzXQ7S3g/IeZW9hyZ5thw4=
 go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q=
-go.uber.org/zap v1.14.1 h1:nYDKopTbvAPq/NrUVZwT15y2lpROBiLLyoRTbXOYWOo=
-go.uber.org/zap v1.14.1/go.mod h1:Mb2vm2krFEG5DV0W9qcHBYFtp/Wku1cvYaqPsS/WYfc=
-golang.org/x/crypto v0.0.0-20171113213409-9f005a07e0d3/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
+go.uber.org/zap v1.19.1 h1:ue41HOKd1vGURxrmeKIgELGb3jPW9DMUDGtsinblHwI=
 golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
 golang.org/x/crypto v0.0.0-20181029021203-45a5f77698d3/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
 golang.org/x/crypto v0.0.0-20181203042331-505ab145d0a9/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
-golang.org/x/crypto v0.0.0-20190211182817-74369b46fc67/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
 golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
 golang.org/x/crypto v0.0.0-20190320223903-b7391e95e576/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
-golang.org/x/crypto v0.0.0-20190325154230-a5d413f7728c/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
-golang.org/x/crypto v0.0.0-20190426145343-a29dc8fdc734/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
 golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
-golang.org/x/crypto v0.0.0-20190513172903-22d7a77e9e5f/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
 golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
 golang.org/x/crypto v0.0.0-20190611184440-5c40567a22f8/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
 golang.org/x/crypto v0.0.0-20190617133340-57b3e21c3d56/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
-golang.org/x/crypto v0.0.0-20190621222207-cc06ce4a13d4/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
-golang.org/x/crypto v0.0.0-20190923035154-9ee001bba392/go.mod h1:/lpIB1dKB+9EgE3H3cr1v9wB50oz8l4C4h62xy7jSTY=
 golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
-golang.org/x/crypto v0.0.0-20191112222119-e1110fd1c708/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
 golang.org/x/crypto v0.0.0-20191206172530-e9b2fee46413/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
-golang.org/x/crypto v0.0.0-20200128174031-69ecbb4d6d5d/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
-golang.org/x/crypto v0.0.0-20200414173820-0848c9571904/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
 golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
-golang.org/x/crypto v0.0.0-20201221181555-eec23a3978ad h1:DN0cp81fZ3njFcrLCytUHRSUkqBjfTo4Tx9RJTWs0EY=
-golang.org/x/crypto v0.0.0-20201221181555-eec23a3978ad/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I=
+golang.org/x/crypto v0.0.0-20201216223049-8b5274cf687f/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I=
+golang.org/x/crypto v0.0.0-20211215153901-e495a2d5b3d3 h1:0es+/5331RGQPcXlMfP+WrnIIS6dNnNRe0WB02W0F4M=
+golang.org/x/crypto v0.0.0-20211215153901-e495a2d5b3d3/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
 golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
 golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
 golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8=
 golang.org/x/exp v0.0.0-20190829153037-c13cbed26979/go.mod h1:86+5VVa7VpoJ4kLfm080zCjGlMRFzhUhsZKEZO7MGek=
 golang.org/x/exp v0.0.0-20191030013958-a1ab85dbe136/go.mod h1:JXzH8nQsPlswgeRAPE3MuO9GYsAcnJvJ4vnMwN/5qkY=
+golang.org/x/exp v0.0.0-20191129062945-2f5052295587/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4=
 golang.org/x/exp v0.0.0-20191227195350-da58074b4299/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4=
+golang.org/x/exp v0.0.0-20200119233911-0405dc783f0a/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4=
+golang.org/x/exp v0.0.0-20200207192155-f17229e696bd/go.mod h1:J/WKrq2StrnmMY6+EHIKF9dgMWnmCNThgcyBT1FY9mM=
+golang.org/x/exp v0.0.0-20200224162631-6cc2880d07d6/go.mod h1:3jZMyOhIsHpP37uCMkUooju7aAi5cS1Q23tOzKc+0MU=
 golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js=
 golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0=
-golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
 golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU=
 golang.org/x/lint v0.0.0-20190301231843-5614ed5bae6f/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
 golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
@@ -979,158 +643,158 @@ golang.org/x/lint v0.0.0-20190409202823-959b441ac422/go.mod h1:6SW0HCj/g11FgYtHl
 golang.org/x/lint v0.0.0-20190909230951-414d861bb4ac/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
 golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
 golang.org/x/lint v0.0.0-20191125180803-fdd1cda4f05f/go.mod h1:5qLYkcX4OjUUV8bRuDixDT3tpyyb+LUpUlRWLxfhWrs=
+golang.org/x/lint v0.0.0-20200130185559-910be7a94367/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY=
+golang.org/x/lint v0.0.0-20200302205851-738671d3881b/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY=
+golang.org/x/lint v0.0.0-20210508222113-6edffad5e616/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY=
 golang.org/x/mobile v0.0.0-20190312151609-d3739f865fa6/go.mod h1:z+o9i4GpDbdi3rU15maQ/Ox0txvL9dWGYEHz965HBQE=
 golang.org/x/mobile v0.0.0-20190719004257-d2bd2a29d028/go.mod h1:E/iHnbuqvinMTCcRqshq8CkpyQDoeVncDDYHnLhea+o=
 golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc=
 golang.org/x/mod v0.1.0/go.mod h1:0QHyrYULN0/3qlju5TqG8bIK38QM8yzMo5ekMj3DlcY=
 golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg=
+golang.org/x/mod v0.1.1-0.20191107180719-034126e5016b/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg=
 golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
 golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
-golang.org/x/net v0.0.0-20170114055629-f2499483f923/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
+golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
 golang.org/x/net v0.0.0-20180112015858-5ccada7d0a7b/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
 golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
 golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
 golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
 golang.org/x/net v0.0.0-20181005035420-146acd28ed58/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
 golang.org/x/net v0.0.0-20181023162649-9b4f9f5ad519/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
-golang.org/x/net v0.0.0-20181108082009-03003ca0c849/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
 golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
 golang.org/x/net v0.0.0-20181201002055-351d144fa1fc/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
 golang.org/x/net v0.0.0-20181220203305-927f97764cc3/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
 golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
-golang.org/x/net v0.0.0-20190125091013-d26f9f9a57f3/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
 golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
 golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
 golang.org/x/net v0.0.0-20190320064053-1272bf9dcd53/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
 golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
-golang.org/x/net v0.0.0-20190424112056-4829fb13d2c6/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
 golang.org/x/net v0.0.0-20190501004415-9ce7a6920f09/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
 golang.org/x/net v0.0.0-20190503192946-f4e77d36d62c/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
 golang.org/x/net v0.0.0-20190522155817-f3200d17e092/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks=
 golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks=
 golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
-golang.org/x/net v0.0.0-20190619014844-b5b0513f8c1b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
 golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
 golang.org/x/net v0.0.0-20190628185345-da137c7871d7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
 golang.org/x/net v0.0.0-20190724013045-ca1201d0de80/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
 golang.org/x/net v0.0.0-20190813141303-74dc4d7220e7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
 golang.org/x/net v0.0.0-20190827160401-ba9fcec4b297/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
 golang.org/x/net v0.0.0-20190923162816-aa69164e4478/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
-golang.org/x/net v0.0.0-20191002035440-2ec189313ef0/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
-golang.org/x/net v0.0.0-20191004110552-13f9640d40b9/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
-golang.org/x/net v0.0.0-20191028085509-fe3aa8a45271/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
-golang.org/x/net v0.0.0-20191112182307-2180aed22343/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
 golang.org/x/net v0.0.0-20191209160850-c0dbc17a3553/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
+golang.org/x/net v0.0.0-20200114155413-6afb5195e5aa/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
 golang.org/x/net v0.0.0-20200202094626-16171245cfb2/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
+golang.org/x/net v0.0.0-20200222125558-5a598a2470a0/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
 golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
 golang.org/x/net v0.0.0-20200301022130-244492dfa37a/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
 golang.org/x/net v0.0.0-20200324143707-d3edc9973b7e/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
+golang.org/x/net v0.0.0-20200501053045-e0ff5e5a1de5/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
+golang.org/x/net v0.0.0-20200506145744-7e3656a0809f/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
+golang.org/x/net v0.0.0-20200513185701-a91f0712d120/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
 golang.org/x/net v0.0.0-20200520004742-59133d7f0dd7/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
+golang.org/x/net v0.0.0-20200520182314-0ba52f642ac2/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
+golang.org/x/net v0.0.0-20200625001655-4c5254603344/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
 golang.org/x/net v0.0.0-20200707034311-ab3426394381/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
-golang.org/x/net v0.0.0-20200822124328-c89045814202 h1:VvcQYSHwXgi7W+TpUR6A9g6Up98WAHf3f/ulnJ62IyA=
 golang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
+golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
+golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM=
+golang.org/x/net v0.0.0-20220127200216-cd36cc0744dd h1:O7DYs+zxREGLKzKoMQrtrEacpb0ZVXA5rIwylE2Xchk=
+golang.org/x/net v0.0.0-20220127200216-cd36cc0744dd/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk=
 golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
-golang.org/x/oauth2 v0.0.0-20181106182150-f42d05182288/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
 golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
-golang.org/x/oauth2 v0.0.0-20190402181905-9f3314589c9a/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
 golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
 golang.org/x/oauth2 v0.0.0-20191202225959-858c2ad4c8b6/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
-golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d h1:TzXSXBo42m9gQenoE3b9BGiEpg5IG2JkU5FkPIawgtw=
 golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
+golang.org/x/oauth2 v0.0.0-20210819190943-2bc19b11175f h1:Qmd2pbz05z7z6lm0DrgQVVPuBm92jqujBKMHMOlOQEw=
+golang.org/x/oauth2 v0.0.0-20210819190943-2bc19b11175f/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
 golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
 golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
 golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
 golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
 golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
 golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
-golang.org/x/sync v0.0.0-20201207232520-09787c993a3a h1:DcqTD9SDLc+1P/r1EmRBwnVsrOwW+kk2vWf9n+1sGhs=
-golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
-golang.org/x/sys v0.0.0-20170830134202-bb24a47a89ea/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
+golang.org/x/sync v0.0.0-20200317015054-43a5402ce75a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
+golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
+golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
+golang.org/x/sync v0.0.0-20210220032951-036812b2e83c h1:5KslGYwFpkhGh+Q16bwMP3cOontH8FOep7tGV86Y7SQ=
+golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
 golang.org/x/sys v0.0.0-20180117170059-2c42eef0765b/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
 golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
-golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
 golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
 golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
 golang.org/x/sys v0.0.0-20181026203630-95b1ffbd15a5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
 golang.org/x/sys v0.0.0-20181107165924-66b7b1311ac8/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
 golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
-golang.org/x/sys v0.0.0-20181122145206-62eef0e2fa9b/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
 golang.org/x/sys v0.0.0-20181205085412-a5c9d58dba9a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
-golang.org/x/sys v0.0.0-20190102155601-82a175fd1598/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
 golang.org/x/sys v0.0.0-20190129075346-302c3dd5f1cc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
-golang.org/x/sys v0.0.0-20190209173611-3b5209105503/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
 golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
 golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
-golang.org/x/sys v0.0.0-20190310054646-10058d7d4faa/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 golang.org/x/sys v0.0.0-20190321052220-f7bb7a8bee54/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 golang.org/x/sys v0.0.0-20190403152447-81d4e9dc473e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/sys v0.0.0-20190425145619-16072639606e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/sys v0.0.0-20190426135247-a129542de9ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 golang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/sys v0.0.0-20190514135907-3a4b5fb9f71f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/sys v0.0.0-20190515120540-06a5c4944438/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/sys v0.0.0-20190602015325-4c4f7f33c9ed/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 golang.org/x/sys v0.0.0-20190616124812-15dcb6c0061f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/sys v0.0.0-20190626221950-04f50cda93cb/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/sys v0.0.0-20190712062909-fae7ac547cb7/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 golang.org/x/sys v0.0.0-20190726091711-fc99dfbffb4e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/sys v0.0.0-20190801041406-cbf593c0f2f3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/sys v0.0.0-20190813064441-fde4db37ae7a/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 golang.org/x/sys v0.0.0-20190826190057-c7b8b68b1456/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 golang.org/x/sys v0.0.0-20190904154756-749cb33beabd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/sys v0.0.0-20190916202348-b4ddaad3f8a3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/sys v0.0.0-20190922100055-0a153f010e69/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 golang.org/x/sys v0.0.0-20190924154521-2837fb4f24fe/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20191001151750-bb3f8db39f24/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/sys v0.0.0-20191010194322-b09406accb47/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/sys v0.0.0-20191025021431-6c3a3bfe00ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/sys v0.0.0-20191112214154-59a1497f0cea/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/sys v0.0.0-20191113165036-4c7a9d0fe056/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 golang.org/x/sys v0.0.0-20191120155948-bd437916bb0e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 golang.org/x/sys v0.0.0-20191228213918-04cbcbbfeed8/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 golang.org/x/sys v0.0.0-20200106162015-b016eb3dc98e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/sys v0.0.0-20200120151820-655fe14d7479/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20200113162924-86b910548bc1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 golang.org/x/sys v0.0.0-20200122134326-e047566fdf82/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 golang.org/x/sys v0.0.0-20200202164722-d101bd2416d5/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20200212091648-12a6c2dcc1e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 golang.org/x/sys v0.0.0-20200302150141-5c8b2ff67527/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20200331124033-c3d80250170d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20200501052902-10377860bb8e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20200511232937-7e40ca221e25/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20200515095857-1151b9dac4a9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20200523222454-059865788121/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 golang.org/x/sys v0.0.0-20200615200032-f1bc736245b1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 golang.org/x/sys v0.0.0-20200622214017-ed371f2e16b4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c h1:VwygUrnw9jn88c4u8GD3rZQbqrP/tgas88tPUbBxQrk=
-golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/term v0.0.0-20201117132131-f5c789dd3221 h1:/ZHdbVpdR/jk3g30/d4yUL0JU9kksj8+F/bnQUVLGDM=
+golang.org/x/sys v0.0.0-20200803210538-64077c9b5642/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e h1:fLOSk5Q00efkSvAm+4xcoXD+RRmLmmulPn5I3Y9F2EM=
+golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
 golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw=
-golang.org/x/text v0.0.0-20160726164857-2910a502d2bf/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
+golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
+golang.org/x/term v0.0.0-20210927222741-03fcf44c2211 h1:JGgROgKl9N8DuW20oFS5gxc+lE67/N3FcwmBPMe7ArY=
+golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
+golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
 golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
 golang.org/x/text v0.3.1-0.20171227012246-e19ae1496984/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
-golang.org/x/text v0.3.1-0.20180805044716-cb6730876b98/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
 golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
 golang.org/x/text v0.3.1-0.20181227161524-e6919f6577db/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
 golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
-golang.org/x/text v0.3.3 h1:cokOdA+Jmi5PJGXLlLllQSgYigAEfHXJAERHVMaCc2k=
 golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
+golang.org/x/text v0.3.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
+golang.org/x/text v0.3.7 h1:olpwvP2KacW1ZWvsR7uQhoyTYvKAupfQrRGBFM352Gk=
+golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
 golang.org/x/time v0.0.0-20180412165947-fbb02b2291d2/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
 golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
 golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
 golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
-golang.org/x/time v0.0.0-20200630173020-3af7569d3a1e h1:EHBhcS0mlXEAVwNyO2dLfjToGsyY4j24pTs2ScHnX7s=
 golang.org/x/time v0.0.0-20200630173020-3af7569d3a1e/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
+golang.org/x/time v0.0.0-20210723032227-1f47c861a9ac h1:7zkz7BUtwNFFqcowJ+RIgu2MaV/MapERkDIy+mwPyjs=
+golang.org/x/time v0.0.0-20210723032227-1f47c861a9ac/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
 golang.org/x/tools v0.0.0-20180221164845-07fd8470d635/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
-golang.org/x/tools v0.0.0-20180828015842-6cd1fcedba52/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
 golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
 golang.org/x/tools v0.0.0-20181011042414-1f849cf54d09/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
 golang.org/x/tools v0.0.0-20181030221726-6c7e314b6563/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
-golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
-golang.org/x/tools v0.0.0-20190118193359-16909d206f00/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
 golang.org/x/tools v0.0.0-20190125232054-d66bd3c5d5a6/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
 golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY=
 golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
@@ -1138,47 +802,56 @@ golang.org/x/tools v0.0.0-20190312151545-0bb0c0a6e846/go.mod h1:LCzVGOaR6xXOjkQ3
 golang.org/x/tools v0.0.0-20190312170243-e65039ee4138/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
 golang.org/x/tools v0.0.0-20190328211700-ab21143f2384/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
 golang.org/x/tools v0.0.0-20190425150028-36563e24a262/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
-golang.org/x/tools v0.0.0-20190425222832-ad9eeb80039a/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
 golang.org/x/tools v0.0.0-20190506145303-2d16b83fe98c/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
 golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
+golang.org/x/tools v0.0.0-20190531172133-b3315ee88b7d/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
 golang.org/x/tools v0.0.0-20190606124116-d0a3d012864b/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
 golang.org/x/tools v0.0.0-20190614205625-5aca471b1d59/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
 golang.org/x/tools v0.0.0-20190617190820-da514acc4774/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
 golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
 golang.org/x/tools v0.0.0-20190624222133-a101b041ded4/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
 golang.org/x/tools v0.0.0-20190628153133-6cdbf07be9d0/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
-golang.org/x/tools v0.0.0-20190706070813-72ffa07ba3db/go.mod h1:jcCCGcm9btYwXyDqrUWc6MKQKKGJCWEQ3AfLSRIbEuI=
-golang.org/x/tools v0.0.0-20190813034749-528a2984e271/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
 golang.org/x/tools v0.0.0-20190816200558-6889da9d5479/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
-golang.org/x/tools v0.0.0-20190907020128-2ca718005c18/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
 golang.org/x/tools v0.0.0-20190911174233-4f2ddba30aff/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
-golang.org/x/tools v0.0.0-20190918214516-5a1a30219888/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
 golang.org/x/tools v0.0.0-20190920225731-5eefd052ad72/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
-golang.org/x/tools v0.0.0-20191004055002-72853e10c5a3/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
 golang.org/x/tools v0.0.0-20191012152004-8de300cfc20a/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
-golang.org/x/tools v0.0.0-20191029041327-9cc4af7d6b2c/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
-golang.org/x/tools v0.0.0-20191029190741-b9c20aec41a5/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
-golang.org/x/tools v0.0.0-20191030203535-5e247c9ad0a0/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
-golang.org/x/tools v0.0.0-20191111182352-50fa39b762bc/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
 golang.org/x/tools v0.0.0-20191112195655-aa38f8e97acc/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
 golang.org/x/tools v0.0.0-20191113191852-77e3bb0ad9e7/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
 golang.org/x/tools v0.0.0-20191115202509-3a792d9c32b2/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
 golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
 golang.org/x/tools v0.0.0-20191125144606-a911d9008d1f/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
+golang.org/x/tools v0.0.0-20191130070609-6e064ea0cf2d/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
 golang.org/x/tools v0.0.0-20191216052735-49a3e744a425/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
+golang.org/x/tools v0.0.0-20191216173652-a0e659d51361/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
 golang.org/x/tools v0.0.0-20191227053925-7b8e75db28f4/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
-golang.org/x/tools v0.0.0-20200403190813-44a64ad78b9b/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
+golang.org/x/tools v0.0.0-20200117161641-43d50277825c/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
+golang.org/x/tools v0.0.0-20200122220014-bf1340f18c4a/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
+golang.org/x/tools v0.0.0-20200130002326-2f3ba24bd6e7/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
+golang.org/x/tools v0.0.0-20200204074204-1cc6d1ef6c74/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
+golang.org/x/tools v0.0.0-20200207183749-b753a1ba74fa/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
+golang.org/x/tools v0.0.0-20200212150539-ea181f53ac56/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
+golang.org/x/tools v0.0.0-20200224181240-023911ca70b2/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
+golang.org/x/tools v0.0.0-20200227222343-706bc42d1f0d/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
+golang.org/x/tools v0.0.0-20200304193943-95d2e580d8eb/go.mod h1:o4KQGtdN14AW+yjsvvwRTJJuXz8XRtIHtEnmAXLyFUw=
+golang.org/x/tools v0.0.0-20200312045724-11d5b4c81c7d/go.mod h1:o4KQGtdN14AW+yjsvvwRTJJuXz8XRtIHtEnmAXLyFUw=
+golang.org/x/tools v0.0.0-20200331025713-a30bf2db82d4/go.mod h1:Sl4aGygMT6LrqrWclx+PTx3U+LnKx/seiNR+3G19Ar8=
+golang.org/x/tools v0.0.0-20200501065659-ab2804fb9c9d/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
+golang.org/x/tools v0.0.0-20200512131952-2bc93b1c0c88/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
+golang.org/x/tools v0.0.0-20200515010526-7d3b6ebf133d/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
 golang.org/x/tools v0.0.0-20200616133436-c1934b75d054/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
+golang.org/x/tools v0.0.0-20200618134242-20370b0cb4b2/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
+golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
+golang.org/x/tools v0.0.0-20200729194436-6467de6f59a7/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA=
+golang.org/x/tools v0.0.0-20200804011535-6c149bb5ef0d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA=
+golang.org/x/tools v0.0.0-20200825202427-b303f430e36d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA=
+golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
+golang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
 golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
 golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
-golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543 h1:E7g+9GITq07hpfrRu66IVDexMakfv52eLZ2CXBWiKr4=
 golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
+golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE=
+golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
 gomodules.xyz/jsonpatch/v2 v2.0.1/go.mod h1:IhYNNY4jnS53ZnfE4PAmpKtDpTCj1JFXc+3mwe7XcUU=
-gomodules.xyz/jsonpatch/v3 v3.0.1/go.mod h1:CBhndykehEwTOlEfnsfJwvkFQbSN8YZFr9M+cIHAJto=
-gomodules.xyz/orderedmap v0.1.0/go.mod h1:g9/TPUCm1t2gwD3j3zfV8uylyYhVdCNSi+xCEIu7yTU=
-google.golang.org/api v0.0.0-20160322025152-9bf6e6e569ff/go.mod h1:4mhQ8q/RsB7i+udVvVy5NUi08OU8ZlA0gRVgrF7VFY0=
-google.golang.org/api v0.3.1/go.mod h1:6wY9I6uQWHQ8EM57III9mq/AjF+i8G65rmVagqKMtkk=
-google.golang.org/api v0.3.2/go.mod h1:6wY9I6uQWHQ8EM57III9mq/AjF+i8G65rmVagqKMtkk=
 google.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE=
 google.golang.org/api v0.7.0/go.mod h1:WtwebWUNSVBH/HAw79HIFXZNqEvBhG+Ra+ax0hx3E3M=
 google.golang.org/api v0.8.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg=
@@ -1186,49 +859,57 @@ google.golang.org/api v0.9.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEn
 google.golang.org/api v0.13.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI=
 google.golang.org/api v0.14.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI=
 google.golang.org/api v0.15.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI=
-google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM=
-google.golang.org/appengine v1.3.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
+google.golang.org/api v0.17.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE=
+google.golang.org/api v0.18.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE=
+google.golang.org/api v0.19.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE=
+google.golang.org/api v0.20.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE=
+google.golang.org/api v0.22.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE=
+google.golang.org/api v0.24.0/go.mod h1:lIXQywCXRcnZPGlsd8NbLnOjtAoL6em04bJ9+z0MncE=
+google.golang.org/api v0.28.0/go.mod h1:lIXQywCXRcnZPGlsd8NbLnOjtAoL6em04bJ9+z0MncE=
+google.golang.org/api v0.29.0/go.mod h1:Lcubydp8VUV7KeIHD9z2Bys/sm/vGKnG1UHuDBSrHWM=
+google.golang.org/api v0.30.0/go.mod h1:QGmEvQ87FHZNiUVJkT14jQNYJ4ZJjdRF23ZXz5138Fc=
 google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
 google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
 google.golang.org/appengine v1.6.1/go.mod h1:i06prIuMbXzDqacNJfV5OdTW448YApPu5ww/cMBSeb0=
-google.golang.org/appengine v1.6.5 h1:tycE03LOZYQNhDpS27tcQdAzLCVMaj7QT2SXxebnpCM=
 google.golang.org/appengine v1.6.5/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc=
-google.golang.org/cloud v0.0.0-20151119220103-975617b05ea8/go.mod h1:0H1ncTHf11KCFhTc/+EFRbzSCOZx+VUbRMk55Yv5MYk=
+google.golang.org/appengine v1.6.6/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc=
+google.golang.org/appengine v1.6.7 h1:FZR1q0exgwxzPzp/aF+VccGrSfxfPpkBqjIIEq3ru6c=
+google.golang.org/appengine v1.6.7/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc=
 google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
 google.golang.org/genproto v0.0.0-20190307195333-5fe7a883aa19/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
 google.golang.org/genproto v0.0.0-20190404172233-64821d5d2107/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
 google.golang.org/genproto v0.0.0-20190418145605-e7d98fc518a7/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
 google.golang.org/genproto v0.0.0-20190425155659-357c62f0e4bb/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
 google.golang.org/genproto v0.0.0-20190502173448-54afdca5d873/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
-google.golang.org/genproto v0.0.0-20190530194941-fb225487d101/go.mod h1:z3L6/3dTEVtUr6QSP8miRzeRqwQOioJ9I66odjN4I7s=
-google.golang.org/genproto v0.0.0-20190716160619-c506a9f90610/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc=
 google.golang.org/genproto v0.0.0-20190801165951-fa694d86fc64/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc=
 google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc=
 google.golang.org/genproto v0.0.0-20190911173649-1774047e7e51/go.mod h1:IbNlFCBrqXvoKpeg0TB2l7cyZUmoaFKYIwrEpbDKLA8=
-google.golang.org/genproto v0.0.0-20190927181202-20e1ac93f88c/go.mod h1:IbNlFCBrqXvoKpeg0TB2l7cyZUmoaFKYIwrEpbDKLA8=
 google.golang.org/genproto v0.0.0-20191108220845-16a3f7862a1a/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
 google.golang.org/genproto v0.0.0-20191115194625-c23dd37a84c9/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
+google.golang.org/genproto v0.0.0-20191216164720-4f79533eabd1/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
 google.golang.org/genproto v0.0.0-20191230161307-f3c370f40bfb/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
-google.golang.org/genproto v0.0.0-20200117163144-32f20d992d24/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
-google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013 h1:+kGHl1aib/qcwaRi1CbqBZ1rk19r85MNUf8HaBghugY=
+google.golang.org/genproto v0.0.0-20200115191322-ca5a22157cba/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
+google.golang.org/genproto v0.0.0-20200122232147-0452cf42e150/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
+google.golang.org/genproto v0.0.0-20200204135345-fa8e72b47b90/go.mod h1:GmwEX6Z4W5gMy59cAlVYjN9JhxgbQH6Gn+gFDQe2lzA=
+google.golang.org/genproto v0.0.0-20200212174721-66ed5ce911ce/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
+google.golang.org/genproto v0.0.0-20200224152610-e50cd9704f63/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
+google.golang.org/genproto v0.0.0-20200228133532-8c2c7df3a383/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
+google.golang.org/genproto v0.0.0-20200305110556-506484158171/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
+google.golang.org/genproto v0.0.0-20200312145019-da6875a35672/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
+google.golang.org/genproto v0.0.0-20200331122359-1ee6d9798940/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
+google.golang.org/genproto v0.0.0-20200430143042-b979b6f78d84/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
+google.golang.org/genproto v0.0.0-20200511104702-f5ebc3bea380/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
+google.golang.org/genproto v0.0.0-20200515170657-fc4c6c6a6587/go.mod h1:YsZOwe1myG/8QRHRsmBRE1LrgQY60beZKjly0O1fX9U=
 google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo=
-google.golang.org/grpc v0.0.0-20160317175043-d3ddb4469d5a/go.mod h1:yo6s7OP7yaDglbqo1J04qKzAhqBH6lvTonzMVmEdcZw=
-google.golang.org/grpc v1.14.0/go.mod h1:yo6s7OP7yaDglbqo1J04qKzAhqBH6lvTonzMVmEdcZw=
-google.golang.org/grpc v1.17.0/go.mod h1:6QZJwpn2B+Zp71q/5VxRsJ6NXXVCE5NRUHRo+f3cWCs=
-google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
-google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38=
-google.golang.org/grpc v1.21.0/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM=
-google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM=
-google.golang.org/grpc v1.22.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg=
-google.golang.org/grpc v1.22.1/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg=
-google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg=
-google.golang.org/grpc v1.23.1/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg=
-google.golang.org/grpc v1.24.0/go.mod h1:XDChyiUovWa60DnaeDeZmSW86xtLtjtZbwvSiRnRtcA=
-google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY=
-google.golang.org/grpc v1.26.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk=
-google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk=
-google.golang.org/grpc v1.28.0 h1:bO/TA4OxCOummhSf10siHuG7vJOiwh7SpRpFZDkOgl4=
-google.golang.org/grpc v1.28.0/go.mod h1:rpkK4SK4GF4Ach/+MFLZUBavHOvF2JJB5uozKKal+60=
+google.golang.org/genproto v0.0.0-20200618031413-b414f8b61790/go.mod h1:jDfRM7FcilCzHH/e9qn6dsT145K34l5v+OpcnNgKAAA=
+google.golang.org/genproto v0.0.0-20200729003335-053ba62fc06f/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
+google.golang.org/genproto v0.0.0-20200804131852-c06518451d9c/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
+google.golang.org/genproto v0.0.0-20200825200019-8632dd797987/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
+google.golang.org/genproto v0.0.0-20201019141844-1ed22bb0c154/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
+google.golang.org/genproto v0.0.0-20210831024726-fe130286e0e2 h1:NHN4wOCScVzKhPenJ2dt+BTs3X/XkBVI/Rh4iDt55T8=
+google.golang.org/genproto v0.0.0-20210831024726-fe130286e0e2/go.mod h1:eFjDcFEctNawg4eG61bRv87N7iHBWyVhJu7u1kqDUXY=
+google.golang.org/grpc v1.29.0 h1:2pJjwYOdkZ9HlN4sWRYBg9ttH5bCOlsueaM+b/oYjwo=
+google.golang.org/grpc v1.29.0/go.mod h1:itym6AZVZYACWQqET3MqgPpjcuV5QH3BxFS3IjizoKk=
 google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8=
 google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0=
 google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM=
@@ -1237,57 +918,54 @@ google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzi
 google.golang.org/protobuf v1.22.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
 google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
 google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
-google.golang.org/protobuf v1.24.0 h1:UhZDfRO8JRQru4/+LlLE0BRKGF8L+PICnvYZmx/fEGA=
 google.golang.org/protobuf v1.24.0/go.mod h1:r/3tXBNzIEhYS9I1OUVjXDlt8tc493IdKGjtUeSXeh4=
-gopkg.in/airbrake/gobrake.v2 v2.0.9/go.mod h1:/h5ZAUhDkGaJfjzjKLSjv6zCL6O0LLBxU4K+aSYdM/U=
+google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c=
+google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw=
+google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
+google.golang.org/protobuf v1.27.1 h1:SnqbnDw1V7RiZcXPx5MEeqPv2s79L9i7BJUlG/+RurQ=
+google.golang.org/protobuf v1.27.1/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
 gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw=
 gopkg.in/asn1-ber.v1 v1.0.0-20181015200546-f715ec2f112d/go.mod h1:cuepJuh7vyXfUyUwEgHQXw849cJrilpS5NeIjOWESAw=
 gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
-gopkg.in/check.v1 v1.0.0-20141024133853-64131543e789/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
 gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
 gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15 h1:YR8cESwS4TdDjEe65xsg0ogRM/Nc3DYOhEAlW+xobZo=
 gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
 gopkg.in/cheggaaa/pb.v1 v1.0.25/go.mod h1:V/YB90LKu/1FcN3WVnfiiE5oMCibMjukxqG/qStrOgw=
 gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI=
 gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys=
-gopkg.in/fsnotify/fsnotify.v1 v1.4.7/go.mod h1:Fyux9zXlo4rWoMSIzpn9fDAYjalPqJ/K1qJ27s+7ltE=
-gopkg.in/gemnasium/logrus-airbrake-hook.v2 v2.1.2/go.mod h1:Xk6kEKp8OKb+X14hQBKWaSkCsqBpgog8nAV2xsGOxlo=
-gopkg.in/gorp.v1 v1.7.2/go.mod h1:Wo3h+DBQZIxATwftsglhdD/62zRFPhGhTiu5jUJmCaw=
-gopkg.in/imdario/mergo.v0 v0.3.7/go.mod h1:9qPP6AGrlC1G2PTNXko614FwGZvorN7MiBU0Eppok+U=
 gopkg.in/inf.v0 v0.9.1 h1:73M5CoZyi3ZLMOyDlQh031Cx6N9NDJ2Vvfl76EDAgDc=
 gopkg.in/inf.v0 v0.9.1/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw=
-gopkg.in/ini.v1 v1.42.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
 gopkg.in/ini.v1 v1.51.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
 gopkg.in/ini.v1 v1.52.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
-gopkg.in/op/go-logging.v1 v1.0.0-20160211212156-b2cb9fa56473/go.mod h1:N1eN2tsCx0Ydtgjl4cqmbRCsY4/+z4cYDeqwZTk6zog=
 gopkg.in/resty.v1 v1.12.0/go.mod h1:mDo4pnntr5jdWRML875a/NmxYqAlA73dVijT2AXvQQo=
 gopkg.in/square/go-jose.v2 v2.3.1/go.mod h1:M9dMgbHiYLoDGQrXy7OpJDJWiKiU//h+vD76mk0e1AI=
+gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ=
 gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw=
 gopkg.in/yaml.v2 v2.0.0-20170812160011-eb3733d160e7/go.mod h1:JAlM8MvJe8wmxCU4Bli9HhUf9+ttbYbLASfIpnQbh74=
 gopkg.in/yaml.v2 v2.0.0/go.mod h1:JAlM8MvJe8wmxCU4Bli9HhUf9+ttbYbLASfIpnQbh74=
-gopkg.in/yaml.v2 v2.1.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
 gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
 gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
-gopkg.in/yaml.v2 v2.2.3/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
 gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
 gopkg.in/yaml.v2 v2.2.5/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
 gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
-gopkg.in/yaml.v2 v2.3.0 h1:clyUAQHOM3G0M3f5vQj7LuJrETvjVot3Z5el9nffUtU=
 gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
+gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY=
+gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
 gopkg.in/yaml.v3 v3.0.0-20190905181640-827449938966/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
 gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
-gopkg.in/yaml.v3 v3.0.0-20200605160147-a5ece683394c h1:grhR+C34yXImVGp7EzNk+DTIk+323eIUWOmEevy6bDo=
 gopkg.in/yaml.v3 v3.0.0-20200605160147-a5ece683394c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
+gopkg.in/yaml.v3 v3.0.0-20200615113413-eeeca48fe776/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
+gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b h1:h8qDotaEPuJATrMmW04NCwg7v22aHH28wwpauUhK9Oo=
+gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
 gotest.tools v2.2.0+incompatible/go.mod h1:DsYFclhRJ6vuDpmuTbkuFWG+y2sxOXAzmJt81HFBacw=
 gotest.tools/v3 v3.0.2/go.mod h1:3SzNCllyD9/Y+b5r9JIKQ474KzkZyqLqEfYqMsX94Bk=
-helm.sh/helm/v3 v3.2.4/go.mod h1:ZaXz/vzktgwjyGGFbUWtIQkscfE7WYoRGP2szqAFHR0=
-honnef.co/go/tools v0.0.0-20180728063816-88497007e858/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
 honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
 honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
 honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
 honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
 honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg=
-howett.net/plist v0.0.0-20181124034731-591f970eefbb/go.mod h1:vMygbs4qMhSZSc4lCUl2OEE+rDiIIJAIdR4m7MiMcm0=
+honnef.co/go/tools v0.0.1-2020.1.3/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k=
+honnef.co/go/tools v0.0.1-2020.1.4/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k=
 k8s.io/api v0.19.0 h1:XyrFIJqTYZJ2DU7FBE/bSPz7b1HvbVBuBf07oeo6eTc=
 k8s.io/api v0.19.0/go.mod h1:I1K45XlvTrDjmj5LoM5LuP/KYrhWbjUKT/SoPG0qTjw=
 k8s.io/apiextensions-apiserver v0.19.0 h1:jlY13lvZp+0p9fRX2khHFdiT9PYzT7zUrANz6R1NKtY=
@@ -1295,67 +973,40 @@ k8s.io/apiextensions-apiserver v0.19.0/go.mod h1:znfQxNpjqz/ZehvbfMg5N6fvBJW5Lqu
 k8s.io/apimachinery v0.19.0 h1:gjKnAda/HZp5k4xQYjL0K/Yb66IvNqjthCb03QlKpaQ=
 k8s.io/apimachinery v0.19.0/go.mod h1:DnPGDnARWFvYa3pMHgSxtbZb7gpzzAZ1pTfaUNDVlmA=
 k8s.io/apiserver v0.0.0-20190409021813-1ec86e4da56c/go.mod h1:6bqaTSOSJavUIXUtfaR9Os9JtTCm8ZqH2SUl2S60C4w=
-k8s.io/autoscaler v0.0.0-20190607113959-1b4f1855cb8e/go.mod h1:QEXezc9uKPT91dwqhSJq3GNI3B1HxFRQHiku9kmrsSA=
 k8s.io/cli-runtime v0.19.0/go.mod h1:tun9l0eUklT8IHIM0jors17KmUjcrAxn0myoBYwuNuo=
 k8s.io/client-go v0.19.0 h1:1+0E0zfWFIWeyRhQYWzimJOyAk2UT7TiARaLNwJCf7k=
 k8s.io/client-go v0.19.0/go.mod h1:H9E/VT95blcFQnlyShFgnFT9ZnJOAceiUHM3MlRC+mU=
-k8s.io/code-generator v0.18.2/go.mod h1:+UHX5rSbxmR8kzS+FAv7um6dtYrZokQvjHpDSYRVkTc=
 k8s.io/code-generator v0.19.0/go.mod h1:moqLn7w0t9cMs4+5CQyxnfA/HV8MF6aAVENF+WZZhgk=
-k8s.io/component-base v0.0.0-20191122220729-2684fb322cb9/go.mod h1:NFuUusy/X4Tk21m21tcNUihnmp4OI7lXU7/xA+rYXkc=
-k8s.io/component-base v0.18.2/go.mod h1:kqLlMuhJNHQ9lz8Z7V5bxUUtjFZnrypArGl58gmDfUM=
 k8s.io/component-base v0.19.0/go.mod h1:dKsY8BxkA+9dZIAh2aWJLL/UdASFDNtGYTCItL4LM7Y=
-k8s.io/gengo v0.0.0-20190128074634-0689ccc1d7d6/go.mod h1:ezvh/TsK7cY6rbqRK0oQQ8IAqLxYwwyPxAX1Pzy0ii0=
-k8s.io/gengo v0.0.0-20200114144118-36b2048a9120/go.mod h1:ezvh/TsK7cY6rbqRK0oQQ8IAqLxYwwyPxAX1Pzy0ii0=
 k8s.io/gengo v0.0.0-20200413195148-3a45101e95ac/go.mod h1:ezvh/TsK7cY6rbqRK0oQQ8IAqLxYwwyPxAX1Pzy0ii0=
 k8s.io/gengo v0.0.0-20200428234225-8167cfdcfc14/go.mod h1:ezvh/TsK7cY6rbqRK0oQQ8IAqLxYwwyPxAX1Pzy0ii0=
-k8s.io/klog v0.0.0-20181102134211-b9b56d5dfc92/go.mod h1:Gq+BEi5rUBO/HRz0bTSXDUcqjScdoY3a9IHpCEIOOfk=
-k8s.io/klog v0.3.0/go.mod h1:Gq+BEi5rUBO/HRz0bTSXDUcqjScdoY3a9IHpCEIOOfk=
-k8s.io/klog v0.3.3/go.mod h1:Gq+BEi5rUBO/HRz0bTSXDUcqjScdoY3a9IHpCEIOOfk=
-k8s.io/klog v0.4.0/go.mod h1:4Bi6QPql/J/LkTDqv7R/cd3hPo4k2DG6Ptcz060Ez5I=
-k8s.io/klog v1.0.0 h1:Pt+yjF5aB1xDSVbau4VsWe+dQNzA0qv1LlXdC2dF6Q8=
-k8s.io/klog v1.0.0/go.mod h1:4Bi6QPql/J/LkTDqv7R/cd3hPo4k2DG6Ptcz060Ez5I=
 k8s.io/klog/v2 v2.0.0/go.mod h1:PBfzABfn139FHAV07az/IF9Wp1bkk3vpT2XSJ76fSDE=
 k8s.io/klog/v2 v2.2.0/go.mod h1:Od+F08eJP+W3HUb4pSrPpgp9DGU4GzlpG/TmITuYh/Y=
 k8s.io/klog/v2 v2.3.0/go.mod h1:Od+F08eJP+W3HUb4pSrPpgp9DGU4GzlpG/TmITuYh/Y=
-k8s.io/klog/v2 v2.4.0 h1:7+X0fUguPyrKEC4WjH8iGDg3laWgMo5tMnRTIGTTxGQ=
-k8s.io/klog/v2 v2.4.0/go.mod h1:Od+F08eJP+W3HUb4pSrPpgp9DGU4GzlpG/TmITuYh/Y=
+k8s.io/klog/v2 v2.30.0 h1:bUO6drIvCIsvZ/XFgfxoGFQU/a4Qkh0iAlvUR7vlHJw=
+k8s.io/klog/v2 v2.30.0/go.mod h1:y1WjHnz7Dj687irZUWR/WLkLc5N1YHtjLdmgWjndZn0=
 k8s.io/kube-aggregator v0.19.0/go.mod h1:1Ln45PQggFAG8xOqWPIYMxUq8WNtpPnYsbUJ39DpF/A=
-k8s.io/kube-openapi v0.0.0-20190320154901-5e45bb682580/go.mod h1:BXM9ceUBTj2QnfH2MK1odQs778ajze1RxcmP6S8RVVc=
-k8s.io/kube-openapi v0.0.0-20191107075043-30be4d16710a/go.mod h1:1TqjTSzOxsLGIKfj0lK8EeCP7K1iUG65v09OM0/WG5E=
-k8s.io/kube-openapi v0.0.0-20200121204235-bf4fb3bd569c/go.mod h1:GRQhZsXIAJ1xR0C9bd8UpWHZ5plfAS9fzPjJuQ6JL3E=
 k8s.io/kube-openapi v0.0.0-20200805222855-6aeccd4b50c6/go.mod h1:UuqjUnNftUyPE5H64/qeyjQoUZhGpeFDVdxjTeEVN2o=
-k8s.io/kube-openapi v0.0.0-20201113171705-d219536bb9fd/go.mod h1:WOJ3KddDSol4tAGcJo0Tvi+dK12EcqSLqcWsryKMpfM=
-k8s.io/kube-state-metrics v1.7.2/go.mod h1:U2Y6DRi07sS85rmVPmBFlmv+2peBcL8IWGjM+IjYA/E=
 k8s.io/kubectl v0.19.0/go.mod h1:gPCjjsmE6unJzgaUNXIFGZGafiUp5jh0If3F/x7/rRg=
-k8s.io/kubernetes v1.14.1/go.mod h1:ocZa8+6APFNC2tX1DZASIbocyYT5jHzqFVsY5aoB7Jk=
 k8s.io/metrics v0.19.0/go.mod h1:WykpW8B60OeAJx1imdwUgyOID2kDljr/Q+1zrPJ98Wo=
-k8s.io/utils v0.0.0-20190308190857-21c4ce38f2a7/go.mod h1:8k8uAuAQ0rXslZKaEWd0c3oVhZz7sSzSiPnVZayjIX0=
-k8s.io/utils v0.0.0-20190801114015-581e00157fb1/go.mod h1:sZAwmy6armz5eXlNoLmJcl4F1QuKu7sr+mFQ0byX7Ew=
-k8s.io/utils v0.0.0-20191114184206-e782cd3c129f/go.mod h1:sZAwmy6armz5eXlNoLmJcl4F1QuKu7sr+mFQ0byX7Ew=
-k8s.io/utils v0.0.0-20191114200735-6ca3b61696b6/go.mod h1:sZAwmy6armz5eXlNoLmJcl4F1QuKu7sr+mFQ0byX7Ew=
-k8s.io/utils v0.0.0-20200324210504-a9aa75ae1b89/go.mod h1:sZAwmy6armz5eXlNoLmJcl4F1QuKu7sr+mFQ0byX7Ew=
 k8s.io/utils v0.0.0-20200603063816-c1c6865ac451/go.mod h1:jPW/WVKK9YHAvNhRxK0md/EJ228hCsBRufyofKtW8HA=
-k8s.io/utils v0.0.0-20200729134348-d5654de09c73 h1:uJmqzgNWG7XyClnU/mLPBWwfKKF1K8Hf8whTseBgJcg=
 k8s.io/utils v0.0.0-20200729134348-d5654de09c73/go.mod h1:jPW/WVKK9YHAvNhRxK0md/EJ228hCsBRufyofKtW8HA=
+k8s.io/utils v0.0.0-20211208161948-7d6a63dca704 h1:ZKMMxTvduyf5WUtREOqg5LiXaN1KO/+0oOQPRFrClpo=
+k8s.io/utils v0.0.0-20211208161948-7d6a63dca704/go.mod h1:jPW/WVKK9YHAvNhRxK0md/EJ228hCsBRufyofKtW8HA=
 rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8=
-rsc.io/letsencrypt v0.0.3/go.mod h1:buyQKZ6IXrRnB7TdkHP0RyEybLx18HHyOSoTyoOLqNY=
-sigs.k8s.io/controller-runtime v0.6.0/go.mod h1:CpYf5pdNY/B352A1TFLAS2JVSlnGQ5O2cftPHndTroo=
+rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0=
+rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA=
 sigs.k8s.io/controller-runtime v0.6.2/go.mod h1:vhcq/rlnENJ09SIRp3EveTaZ0yqH526hjf9iJdbUJ/E=
-sigs.k8s.io/controller-tools v0.2.4/go.mod h1:m/ztfQNocGYBgTTCmFdnK94uVvgxeZeE3LtJvd/jIzA=
 sigs.k8s.io/controller-tools v0.2.9-0.20200414181213-645d44dca7c0/go.mod h1:YKE/iHvcKITCljdnlqHYe+kAt7ZldvtAwUzQff0k1T0=
-sigs.k8s.io/controller-tools v0.3.0/go.mod h1:enhtKGfxZD1GFEoMgP8Fdbu+uKQ/cq1/WGJhdVChfvI=
-sigs.k8s.io/kubebuilder v1.0.9-0.20200618125005-36aa113dbe99/go.mod h1:FGPx0hvP73+bapzWoy5ePuhAJYgJjrFbPxgvWyortM0=
 sigs.k8s.io/kustomize v2.0.3+incompatible/go.mod h1:MkjgH3RdOWrievjo6c9T245dYlB5QeXV4WCbnt/PEpU=
-sigs.k8s.io/structured-merge-diff v0.0.0-20190525122527-15d366b2352e h1:4Z09Hglb792X0kfOBBJUPFEyvVfQWrYT/l8h5EKA6JQ=
-sigs.k8s.io/structured-merge-diff v0.0.0-20190525122527-15d366b2352e/go.mod h1:wWxsB5ozmmv/SG7nM11ayaAW51xMvak/t1r0CSlcokI=
-sigs.k8s.io/structured-merge-diff/v3 v3.0.0-20200116222232-67a7b8c61874/go.mod h1:PlARxl6Hbt/+BC80dRLi1qAmnMqwqDg62YvvVkZjemw=
 sigs.k8s.io/structured-merge-diff/v4 v4.0.1/go.mod h1:bJZC9H9iH24zzfZ/41RGcq60oK1F7G282QMXDPYydCw=
-sigs.k8s.io/structured-merge-diff/v4 v4.0.2 h1:YHQV7Dajm86OuqnIR6zAelnDWBRjo+YhYV9PmGrh1s8=
-sigs.k8s.io/structured-merge-diff/v4 v4.0.2/go.mod h1:bJZC9H9iH24zzfZ/41RGcq60oK1F7G282QMXDPYydCw=
+sigs.k8s.io/structured-merge-diff/v4 v4.2.1 h1:bKCqE9GvQ5tiVHn5rfn1r+yao3aLQEaLzkkmAkf+A6Y=
+sigs.k8s.io/structured-merge-diff/v4 v4.2.1/go.mod h1:j/nl6xW8vLS49O8YvXW1ocPhZawJtm+Yrr7PPRQ0Vg4=
 sigs.k8s.io/testing_frameworks v0.1.2/go.mod h1:ToQrwSC3s8Xf/lADdZp3Mktcql9CG0UAmdJG9th5i0w=
 sigs.k8s.io/yaml v1.1.0/go.mod h1:UJmg0vDUVViEyp3mgSv9WPwZCDxu4rQW1olrI1uml+o=
-sigs.k8s.io/yaml v1.2.0 h1:kr/MCeFWJWTwyaHoR9c8EjH9OumOmoF9YGiZd7lFm/Q=
 sigs.k8s.io/yaml v1.2.0/go.mod h1:yfXDCHCao9+ENCvLSE62v9VSji2MKu5jeNfTrofGhJc=
+sigs.k8s.io/yaml v1.3.0 h1:a2VclLzOGrwOHDiV8EfBGhvjHvP46CtW5j6POvhYGGo=
+sigs.k8s.io/yaml v1.3.0/go.mod h1:GeOyir5tyXNByN85N/dRIT9es5UQNerPYEKK56eTBm8=
 software.sslmate.com/src/go-pkcs12 v0.0.0-20180114231543-2291e8f0f237/go.mod h1:/xvNRWUqm0+/ZMiF4EX00vrSCMsE4/NHb+Pt3freEeQ=
 software.sslmate.com/src/go-pkcs12 v0.0.0-20200830195227-52f69702a001/go.mod h1:/xvNRWUqm0+/ZMiF4EX00vrSCMsE4/NHb+Pt3freEeQ=
 vbom.ml/util v0.0.0-20160121211510-db5cfe13f5cc/go.mod h1:so/NYdZXCz+E3ZpW0uAoCj6uzU2+8OWDFv/HxUSs7kI=
index d26bf15..3551856 100644 (file)
@@ -8,10 +8,10 @@ import (
        "sync"
        "time"
 
-       log "github.com/open-ness/EMCO/src/orchestrator/pkg/infra/logutils"
-       "github.com/open-ness/EMCO/src/orchestrator/pkg/infra/rpc"
-       installpb "github.com/open-ness/EMCO/src/rsync/pkg/grpc/installapp"
        pkgerrors "github.com/pkg/errors"
+       log "gitlab.com/project-emco/core/emco-base/src/orchestrator/pkg/infra/logutils"
+       "gitlab.com/project-emco/core/emco-base/src/orchestrator/pkg/infra/rpc"
+       installpb "gitlab.com/project-emco/core/emco-base/src/rsync/pkg/grpc/installapp"
 )
 
 const rsyncName = "rsync"
index 509f742..c981de4 100644 (file)
@@ -20,8 +20,8 @@ import (
        "encoding/base64"
        "encoding/json"
        "github.com/akraino-edge-stack/icn-sdwan/central-controller/src/scc/pkg/module"
-       "github.com/open-ness/EMCO/src/orchestrator/pkg/infra/db"
        pkgerrors "github.com/pkg/errors"
+       "gitlab.com/project-emco/core/emco-base/src/orchestrator/pkg/infra/db"
        "io"
        "log"
 )
diff --git a/central-controller/src/scc/pkg/manager/clustersync_objectmanager.go b/central-controller/src/scc/pkg/manager/clustersync_objectmanager.go
new file mode 100644 (file)
index 0000000..4cd1903
--- /dev/null
@@ -0,0 +1,212 @@
+/*
+ * Copyright 2020 Intel Corporation, Inc
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES 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 (
+       "encoding/json"
+       "github.com/akraino-edge-stack/icn-sdwan/central-controller/src/scc/pkg/module"
+       pkgerrors "github.com/pkg/errors"
+       "gitlab.com/project-emco/core/emco-base/src/orchestrator/pkg/infra/db"
+       mtypes "gitlab.com/project-emco/core/emco-base/src/orchestrator/pkg/module/types"
+       rsync "gitlab.com/project-emco/core/emco-base/src/rsync/pkg/db"
+       "io"
+)
+
+type ClusterSyncObjectKey struct {
+       OverlayName     string `json:"overlay-name"`
+       ClusterSyncName string `json:"clustersync-name"`
+}
+
+// ClusterSyncObjectManager implements the ControllerObjectManager
+type ClusterSyncObjectManager struct {
+       BaseObjectManager
+}
+
+func NewClusterSyncObjectManager() *ClusterSyncObjectManager {
+       return &ClusterSyncObjectManager{
+               BaseObjectManager{
+                       storeName:      StoreName,
+                       tagMeta:        "clustersync",
+                       depResManagers: []ControllerObjectManager{},
+                       ownResManagers: []ControllerObjectManager{},
+               },
+       }
+}
+
+func (c *ClusterSyncObjectManager) GetResourceName() string {
+       return ClusterSyncResource
+}
+
+func (c *ClusterSyncObjectManager) IsOperationSupported(oper string) bool {
+       return true
+}
+
+func (c *ClusterSyncObjectManager) CreateEmptyObject() module.ControllerObject {
+       return &module.ClusterSyncObject{}
+}
+
+func (c *ClusterSyncObjectManager) GetStoreKey(m map[string]string, t module.ControllerObject, isCollection bool) (db.Key, error) {
+       overlay_name := m[OverlayResource]
+       key := ClusterSyncObjectKey{
+               OverlayName:     overlay_name,
+               ClusterSyncName: "",
+       }
+
+       if isCollection == true {
+               return key, nil
+       }
+
+       to := t.(*module.ClusterSyncObject)
+       meta_name := to.Metadata.Name
+       res_name := m[ClusterSyncResource]
+
+       if res_name != "" {
+               if meta_name != "" && res_name != meta_name {
+                       return key, pkgerrors.New("Resource name unmatched metadata name")
+               }
+
+               key.ClusterSyncName = res_name
+       } else {
+               if meta_name == "" {
+                       return key, pkgerrors.New("Unable to find resource name")
+               }
+
+               key.ClusterSyncName = meta_name
+       }
+
+       return key, nil
+}
+
+func (c *ClusterSyncObjectManager) getProvider(overlay string) string {
+       return PROVIDERNAME + "_" + overlay
+}
+
+func (c *ClusterSyncObjectManager) ParseObject(r io.Reader) (module.ControllerObject, error) {
+       var v module.ClusterSyncObject
+       err := json.NewDecoder(r).Decode(&v)
+
+       return &v, err
+}
+
+func (c *ClusterSyncObjectManager) CreateObject(m map[string]string, t module.ControllerObject) (module.ControllerObject, error) {
+       ccc := rsync.NewCloudConfigClient()
+       to := t.(*module.ClusterSyncObject)
+
+       overlay_name := m[OverlayResource]
+       _, err := ccc.CreateClusterSyncObjects(c.getProvider(overlay_name),
+               mtypes.ClusterSyncObjects{
+                       Metadata: mtypes.Metadata{
+                               Name:        to.Metadata.Name,
+                               Description: to.Metadata.Description,
+                               UserData1:   to.Metadata.UserData1,
+                               UserData2:   to.Metadata.UserData2,
+                       },
+                       Spec: mtypes.ClusterSyncObjectSpec{
+                               Kv: to.Specification.Kv,
+                       },
+               }, false)
+
+       if err != nil {
+               return c.CreateEmptyObject(), err
+       }
+
+       return t, nil
+}
+
+func (c *ClusterSyncObjectManager) GetObject(m map[string]string) (module.ControllerObject, error) {
+       ccc := rsync.NewCloudConfigClient()
+       overlay_name := m[OverlayResource]
+       res_name := m[ClusterSyncResource]
+
+       so, err := ccc.GetClusterSyncObjects(c.getProvider(overlay_name), res_name)
+       if err != nil {
+               return c.CreateEmptyObject(), err
+       }
+
+       return &module.ClusterSyncObject{
+               Metadata: module.ObjectMetaData{
+                       Name:        so.Metadata.Name,
+                       Description: so.Metadata.Description,
+                       UserData1:   so.Metadata.UserData1,
+                       UserData2:   so.Metadata.UserData2,
+               },
+               Specification: module.ClusterSyncObjectSpec{
+                       Kv: so.Spec.Kv,
+               },
+       }, nil
+}
+
+func (c *ClusterSyncObjectManager) GetObjects(m map[string]string) ([]module.ControllerObject, error) {
+       ccc := rsync.NewCloudConfigClient()
+       overlay_name := m[OverlayResource]
+
+       sos, err := ccc.GetAllClusterSyncObjects(c.getProvider(overlay_name))
+       if err != nil {
+               return []module.ControllerObject{}, err
+       }
+
+       var resp []module.ControllerObject
+       for _, so := range sos {
+               resp = append(resp,
+                       &module.ClusterSyncObject{
+                               Metadata: module.ObjectMetaData{
+                                       Name:        so.Metadata.Name,
+                                       Description: so.Metadata.Description,
+                                       UserData1:   so.Metadata.UserData1,
+                                       UserData2:   so.Metadata.UserData2,
+                               },
+                               Specification: module.ClusterSyncObjectSpec{
+                                       Kv: so.Spec.Kv,
+                               },
+                       })
+       }
+
+       return resp, nil
+}
+
+func (c *ClusterSyncObjectManager) UpdateObject(m map[string]string, t module.ControllerObject) (module.ControllerObject, error) {
+       ccc := rsync.NewCloudConfigClient()
+       to := t.(*module.ClusterSyncObject)
+
+       overlay_name := m[OverlayResource]
+       _, err := ccc.CreateClusterSyncObjects(c.getProvider(overlay_name),
+               mtypes.ClusterSyncObjects{
+                       Metadata: mtypes.Metadata{
+                               Name:        to.Metadata.Name,
+                               Description: to.Metadata.Description,
+                               UserData1:   to.Metadata.UserData1,
+                               UserData2:   to.Metadata.UserData2,
+                       },
+                       Spec: mtypes.ClusterSyncObjectSpec{
+                               Kv: to.Specification.Kv,
+                       },
+               }, true)
+
+       if err != nil {
+               return c.CreateEmptyObject(), err
+       }
+
+       return t, nil
+}
+
+func (c *ClusterSyncObjectManager) DeleteObject(m map[string]string) error {
+       ccc := rsync.NewCloudConfigClient()
+       overlay_name := m[OverlayResource]
+       res_name := m[ClusterSyncResource]
+
+       return ccc.DeleteClusterSyncObjects(c.getProvider(overlay_name), res_name)
+}
index c08fdca..6d4dd3c 100644 (file)
@@ -19,8 +19,8 @@ package manager
 import (
        "encoding/json"
        "github.com/akraino-edge-stack/icn-sdwan/central-controller/src/scc/pkg/module"
-       "github.com/open-ness/EMCO/src/orchestrator/pkg/infra/db"
        pkgerrors "github.com/pkg/errors"
+       "gitlab.com/project-emco/core/emco-base/src/orchestrator/pkg/infra/db"
        "io"
 
        "k8s.io/apimachinery/pkg/runtime/schema"
index ea38552..f661de1 100644 (file)
@@ -19,8 +19,8 @@ package manager
 import (
        "github.com/akraino-edge-stack/icn-sdwan/central-controller/src/scc/pkg/module"
        "github.com/akraino-edge-stack/icn-sdwan/central-controller/src/scc/pkg/resource"
-       "github.com/open-ness/EMCO/src/orchestrator/pkg/infra/db"
        pkgerrors "github.com/pkg/errors"
+       "gitlab.com/project-emco/core/emco-base/src/orchestrator/pkg/infra/db"
        "log"
 )
 
@@ -216,5 +216,24 @@ func (c *ConnectionManager) DeleteObject(overlay string, key1 string, key2 strin
                return pkgerrors.Wrap(err, "Delete Object")
        }
 
+       // Delete HubSite resource if required
+       t1, n1 := module.ParseEndName(key1)
+       t2, n2 := module.ParseEndName(key2)
+       hub_name := ""
+       dev_name := ""
+       if t1 == "Hub" && t2 == "Device" {
+               hub_name = n1
+               dev_name = n2
+       }
+       if t1 == "Device" && t2 == "Hub" {
+               hub_name = n2
+               dev_name = n1
+       }
+
+       if hub_name != "" && dev_name != "" {
+               ds_manager := GetManagerset().DeviceSite
+               ds_manager.TryDeleteSite(overlay, hub_name, dev_name)
+       }
+
        return err
 }
index 511372e..3e8f4b7 100644 (file)
 package manager
 
 const (
-        NameSpaceName               = "sdewan-system"
-        RootIssuerName              = "sdewan-controller"
-        RootCAIssuerName            = "sdewan-controller-ca"
-        RootCertName                = "sdewan-controller"
-        SCCCertName                 = "sdewan-controller-base"
-        StoreName                   = "centralcontroller"
-        OverlayCollection           = "overlays"
-        OverlayResource             = "overlay-name"
-        ProposalCollection          = "proposals"
-        ProposalResource            = "proposal-name"
-        HubCollection               = "hubs"
-        HubResource                 = "hub-name"
-        ConnectionCollection        = "connections"
-        ConnectionResource          = "connection-name"
-        CNFCollection               = "cnfs"
-        CNFResource                 = "cnf-name"
-        DeviceCollection            = "devices"
-        DeviceResource              = "device-name"
-        IPRangeCollection           = "ipranges"
-        IPRangeResource             = "iprange-name"
-        CertCollection              = "certificates"
-        CertResource                = "certificate-name"
-        Resource                    = "resource"
-        Resource_Status_NotDeployed = "NotDeployed"
-        Resource_Status_Deployed    = "Deployed"
+       NameSpaceName               = "sdewan-system"
+       RootIssuerName              = "sdewan-controller"
+       RootCAIssuerName            = "sdewan-controller-ca"
+       RootCertName                = "sdewan-controller"
+       SCCCertName                 = "sdewan-controller-base"
+       StoreName                   = "centralcontroller"
+       OverlayCollection           = "overlays"
+       OverlayResource             = "overlay-name"
+       ProposalCollection          = "proposals"
+       ProposalResource            = "proposal-name"
+       HubCollection               = "hubs"
+       HubResource                 = "hub-name"
+       ConnectionCollection        = "connections"
+       ConnectionResource          = "connection-name"
+       CNFCollection               = "cnfs"
+       CNFResource                 = "cnf-name"
+       DeviceCollection            = "devices"
+       DeviceResource              = "device-name"
+       IPRangeCollection           = "ipranges"
+       IPRangeResource             = "iprange-name"
+       CertCollection              = "certificates"
+       CertResource                = "certificate-name"
+       ClusterSyncCollection       = "cluster-sync-objects"
+       ClusterSyncResource         = "cluster-sync-object-name"
+       SiteCollection              = "sites"
+       SiteResource                = "site-name"
+       Resource                    = "resource"
+       Resource_Status_NotDeployed = "NotDeployed"
+       Resource_Status_Deployed    = "Deployed"
 )
index 5802ab2..121a4ae 100644 (file)
@@ -18,7 +18,7 @@ package manager
 
 import (
        "github.com/akraino-edge-stack/icn-sdwan/central-controller/src/scc/pkg/module"
-       "github.com/open-ness/EMCO/src/orchestrator/pkg/infra/db"
+       "gitlab.com/project-emco/core/emco-base/src/orchestrator/pkg/infra/db"
        "io"
 )
 
index 6e1c008..5af45bd 100644 (file)
@@ -18,10 +18,10 @@ package manager
 
 import (
        "github.com/akraino-edge-stack/icn-sdwan/central-controller/src/scc/pkg/module"
-       "github.com/open-ness/EMCO/src/orchestrator/pkg/infra/db"
-       mtypes "github.com/open-ness/EMCO/src/orchestrator/pkg/module/types"
-       rsync "github.com/open-ness/EMCO/src/rsync/pkg/db"
        pkgerrors "github.com/pkg/errors"
+       "gitlab.com/project-emco/core/emco-base/src/orchestrator/pkg/infra/db"
+       mtypes "gitlab.com/project-emco/core/emco-base/src/orchestrator/pkg/module/types"
+       rsync "gitlab.com/project-emco/core/emco-base/src/rsync/pkg/db"
 )
 
 const PROVIDERNAME = "akraino_scc"
@@ -189,3 +189,30 @@ func (d *DBUtils) UnregisterDevice(cluster_name string) error {
 
        return nil
 }
+
+func (d *DBUtils) RegisterGitOpsDevice(cluster_name string, gs mtypes.GitOpsSpec) error {
+       ccc := rsync.NewCloudConfigClient()
+
+       _, err := ccc.GetGitOpsConfig(PROVIDERNAME, cluster_name, "0", "default")
+       if err == nil {
+               ccc.DeleteGitOpsConfig(PROVIDERNAME, cluster_name, "0", "default")
+       }
+
+       _, err = ccc.CreateGitOpsConfig(PROVIDERNAME, cluster_name, gs, "0", "default")
+       if err != nil {
+               return pkgerrors.Wrap(err, "Error creating cloud config")
+       }
+
+       return nil
+}
+
+func (d *DBUtils) UnregisterGitOpsDevice(cluster_name string) error {
+       ccc := rsync.NewCloudConfigClient()
+
+       err := ccc.DeleteGitOpsConfig(PROVIDERNAME, cluster_name, "0", "default")
+       if err != nil {
+               return pkgerrors.Wrap(err, "Error deleting cloud config")
+       }
+
+       return nil
+}
index be64fbb..4b188af 100644 (file)
@@ -27,7 +27,7 @@ import (
        "time"
 
        "github.com/akraino-edge-stack/icn-sdwan/central-controller/src/scc/pkg/module"
-       "github.com/open-ness/EMCO/src/orchestrator/pkg/infra/db"
+       "gitlab.com/project-emco/core/emco-base/src/orchestrator/pkg/infra/db"
        //"github.com/akraino-edge-stack/icn-sdwan/central-controller/src/scc/pkg/client"
        "github.com/akraino-edge-stack/icn-sdwan/central-controller/src/scc/pkg/resource"
        pkgerrors "github.com/pkg/errors"
@@ -235,7 +235,7 @@ func (c *DeviceObjectManager) CreateObject(m map[string]string, t module.Control
 
        to := t.(*module.DeviceObject)
        task = runner.Go(func(ShouldStop runner.S) error {
-               for to.Status.Data[RegStatus] != "success" {
+               for to.Status.Data[RegStatus] == "pending" {
                        err = c.PostRegister(m, t)
                        if err != nil {
                                log.Println(err)
@@ -312,18 +312,18 @@ func (c *DeviceObjectManager) DeleteObject(m map[string]string) error {
                resutils.AddResource(&scc, "create", r)
 
                // Get all proposal resources
-                proposal := GetManagerset().Proposal
-                proposals, err := proposal.GetObjects(m)
-                if len(proposals) == 0 || err != nil {
-                        log.Println("Missing Proposal in the overlay")
-                        return pkgerrors.New("Error in getting proposals")
-                }
-
-                for i := 0; i < len(proposals); i++ {
-                        proposal_obj := proposals[i].(*module.ProposalObject)
-                        pr := proposal_obj.ToResource()
-                        resutils.AddResource(&scc, "create", pr)
-                }
+               proposal := GetManagerset().Proposal
+               proposals, err := proposal.GetObjects(m)
+               if len(proposals) == 0 || err != nil {
+                       log.Println("Missing Proposal in the overlay")
+                       return pkgerrors.New("Error in getting proposals")
+               }
+
+               for i := 0; i < len(proposals); i++ {
+                       proposal_obj := proposals[i].(*module.ProposalObject)
+                       pr := proposal_obj.ToResource()
+                       resutils.AddResource(&scc, "create", pr)
+               }
 
                resutils.Undeploy(overlay_name)
        }
@@ -336,6 +336,10 @@ func (c *DeviceObjectManager) DeleteObject(m map[string]string) error {
 
        // DB Operation
        err = GetDBUtils().DeleteObject(c, m)
+       err = GetDBUtils().UnregisterDevice(m[DeviceResource])
+       if err != nil {
+               log.Println(err)
+       }
 
        return err
 }
@@ -361,8 +365,9 @@ func (c *DeviceObjectManager) PostRegister(m map[string]string, t module.Control
 
        if to.Status.Mode == 2 {
                kube_config, err := base64.StdEncoding.DecodeString(to.Specification.KubeConfig)
-               if err != nil {
+               if err != nil || len(kube_config) == 0 {
                        to.Status.Data[RegStatus] = "failed"
+                       return pkgerrors.New("Error in decoding kubeconfig in registration")
                }
 
                kube_config, _, err = kubeutil.checkKubeConfigAvail(kube_config, []string{to.Status.Ip}, DEFAULT_K8S_API_SERVER_PORT)
@@ -382,21 +387,21 @@ func (c *DeviceObjectManager) PostRegister(m map[string]string, t module.Control
 
        } else {
                to.Status.Data[RegStatus] = "success"
-                err := GetDBUtils().RegisterDevice(to.Metadata.Name, to.Specification.KubeConfig)
-                if err != nil {
-                        log.Println(err)
-                        return err
-                }
-
-                overlay := GetManagerset().Overlay
-                overlay_name := m[OverlayResource]
-
-                log.Println("Create Certificate: " + to.GetCertName())
-                _, _, err = overlay.CreateCertificate(overlay_name, to.GetCertName())
-                if err != nil {
-                        log.Println(err)
-                        return err
-                }
+               err := GetDBUtils().RegisterDevice(to.Metadata.Name, to.Specification.KubeConfig)
+               if err != nil {
+                       log.Println(err)
+                       return err
+               }
+
+               overlay := GetManagerset().Overlay
+               overlay_name := m[OverlayResource]
+
+               log.Println("Create Certificate: " + to.GetCertName())
+               _, _, err = overlay.CreateCertificate(overlay_name, to.GetCertName())
+               if err != nil {
+                       log.Println(err)
+                       return err
+               }
        }
 
        if to.Status.Data[RegStatus] == "success" {
index 8b7387d..f95ff68 100644 (file)
@@ -19,9 +19,10 @@ package manager
 import (
        "encoding/json"
        "github.com/akraino-edge-stack/icn-sdwan/central-controller/src/scc/pkg/module"
-       "github.com/open-ness/EMCO/src/orchestrator/pkg/infra/db"
        pkgerrors "github.com/pkg/errors"
+       "gitlab.com/project-emco/core/emco-base/src/orchestrator/pkg/infra/db"
        "io"
+       "strings"
 )
 
 type DeviceConnObjectKey struct {
@@ -124,3 +125,40 @@ func (c *DeviceConnObjectManager) UpdateObject(m map[string]string, t module.Con
 func (c *DeviceConnObjectManager) DeleteObject(m map[string]string) error {
        return pkgerrors.New("Not implemented")
 }
+
+func (c *DeviceConnObjectManager) GetConnectedHubs(overlay_name string, device_name string) ([]string, error) {
+       m := make(map[string]string)
+       m[OverlayResource] = overlay_name
+       m[DeviceResource] = device_name
+
+       // get all connections
+       cs, err := c.GetObjects(m)
+       if err != nil {
+               return []string{}, err
+       }
+
+       var hub_names []string
+       for _, c := range cs {
+               co := c.(*module.ConnectionObject)
+               // get peer end's type and name
+               t, n, ip := co.GetPeer("Device", device_name)
+               if t == "Hub" {
+                       hub_names = append(hub_names, n+".."+ip)
+               }
+       }
+       return hub_names, nil
+}
+
+func (c *DeviceConnObjectManager) IsConnectedHub(overlay_name string, device_name string, hub string) bool {
+       hub_names, _ := c.GetConnectedHubs(overlay_name, device_name)
+       for _, hub_name := range hub_names {
+               strs := strings.SplitN(hub_name, "..", 2)
+               if len(strs) == 2 {
+                       if hub == strings.Replace(strs[0], "Hub.", "", 1) {
+                               return true
+                       }
+               }
+       }
+
+       return false
+}
diff --git a/central-controller/src/scc/pkg/manager/devicesite_objectmanager.go b/central-controller/src/scc/pkg/manager/devicesite_objectmanager.go
new file mode 100644 (file)
index 0000000..e10bbf5
--- /dev/null
@@ -0,0 +1,228 @@
+/*
+ * Copyright 2020 Intel Corporation, Inc
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES 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 (
+       "encoding/json"
+       "github.com/akraino-edge-stack/icn-sdwan/central-controller/src/scc/pkg/module"
+       "github.com/akraino-edge-stack/icn-sdwan/central-controller/src/scc/pkg/resource"
+       pkgerrors "github.com/pkg/errors"
+       "gitlab.com/project-emco/core/emco-base/src/orchestrator/pkg/infra/db"
+       "io"
+       "log"
+)
+
+type DeviceSiteObjectKey struct {
+       OverlayName string `json:"overlay-name"`
+       DeviceName  string `json:"device-name"`
+       SiteName    string `json:"site-name"`
+}
+
+// DeviceSiteObjectManager implements the ControllerObjectManager
+type DeviceSiteObjectManager struct {
+       BaseObjectManager
+}
+
+func NewDeviceSiteObjectManager() *DeviceSiteObjectManager {
+       return &DeviceSiteObjectManager{
+               BaseObjectManager{
+                       storeName:      StoreName,
+                       tagMeta:        "devicesite",
+                       depResManagers: []ControllerObjectManager{},
+                       ownResManagers: []ControllerObjectManager{},
+               },
+       }
+}
+
+func (c *DeviceSiteObjectManager) GetResourceName() string {
+       return SiteResource
+}
+
+func (c *DeviceSiteObjectManager) IsOperationSupported(oper string) bool {
+       return true
+}
+
+func (c *DeviceSiteObjectManager) CreateEmptyObject() module.ControllerObject {
+       return &module.SiteObject{}
+}
+
+func (c *DeviceSiteObjectManager) GetStoreKey(m map[string]string, t module.ControllerObject, isCollection bool) (db.Key, error) {
+       overlay_name := m[OverlayResource]
+       device_name := m[DeviceResource]
+       key := DeviceSiteObjectKey{
+               OverlayName: overlay_name,
+               DeviceName:  device_name,
+               SiteName:    "",
+       }
+
+       if isCollection == true {
+               return key, nil
+       }
+
+       to := t.(*module.SiteObject)
+       meta_name := to.Metadata.Name
+       res_name := m[SiteResource]
+
+       if res_name != "" {
+               if meta_name != "" && res_name != meta_name {
+                       return key, pkgerrors.New("Resource name unmatched metadata name")
+               }
+
+               key.SiteName = res_name
+       } else {
+               if meta_name == "" {
+                       return key, pkgerrors.New("Unable to find resource name")
+               }
+
+               key.SiteName = meta_name
+       }
+
+       return key, nil
+}
+
+func (c *DeviceSiteObjectManager) ParseObject(r io.Reader) (module.ControllerObject, error) {
+       var v module.SiteObject
+       err := json.NewDecoder(r).Decode(&v)
+
+       return &v, err
+}
+
+func (c *DeviceSiteObjectManager) deployResource(m map[string]string, t module.ControllerObject, update bool) error {
+       overlay_name := m[OverlayResource]
+       device_name := m[DeviceResource]
+
+       to := t.(*module.SiteObject)
+       site_name := to.Metadata.Name
+
+       if len(to.Specification.Hubs) < 1 {
+               return pkgerrors.New("Hub is required")
+       }
+
+       // Todo: support multiple hubs
+       hub := to.Specification.Hubs[0]
+       devConn := GetManagerset().DeviceConn
+       if !devConn.IsConnectedHub(overlay_name, device_name, hub) {
+               return pkgerrors.New("Hub does not connect to the device")
+       }
+
+       dev_manager := GetManagerset().Device
+       dev, err := dev_manager.GetObject(m)
+       if err != nil {
+               return pkgerrors.Wrap(err, "Device "+device_name+" is not defined")
+       }
+
+       // Deploy HubSite resource to device
+       devobj := dev.(*module.DeviceObject)
+       resutil := NewResUtil()
+       resutil.AddResource(dev, "create", &resource.HubSiteResource{
+               Name:      format_resource_name(site_name, ""),
+               Type:      "Device",
+               Site:      to.Specification.Url,
+               Subnet:    to.Specification.Subnet,
+               HubIP:     "",
+               DevicePIP: devobj.Status.DataIps[module.CreateEndName("Hub", hub)], // Todo: check if device mode = 1
+       })
+
+       err = resutil.DeployUpdate(overlay_name, "hubsite"+to.Metadata.Name, "YAML", update)
+
+       return err
+}
+
+func (c *DeviceSiteObjectManager) CreateObject(m map[string]string, t module.ControllerObject) (module.ControllerObject, error) {
+       err := c.deployResource(m, t, false)
+       if err != nil {
+               log.Println(err)
+               return c.CreateEmptyObject(), err
+       }
+
+       // DB Operation
+       t, err = GetDBUtils().CreateObject(c, m, t)
+
+       return t, err
+}
+
+func (c *DeviceSiteObjectManager) GetObject(m map[string]string) (module.ControllerObject, error) {
+       // DB Operation
+       t, err := GetDBUtils().GetObject(c, m)
+
+       return t, err
+}
+
+func (c *DeviceSiteObjectManager) GetObjects(m map[string]string) ([]module.ControllerObject, error) {
+       // DB Operation
+       t, err := GetDBUtils().GetObjects(c, m)
+
+       return t, err
+}
+
+func (c *DeviceSiteObjectManager) UpdateObject(m map[string]string, t module.ControllerObject) (module.ControllerObject, error) {
+       err := c.deployResource(m, t, true)
+       if err != nil {
+               log.Println(err)
+               return c.CreateEmptyObject(), err
+       }
+
+       // DB Operation
+       t, err = GetDBUtils().UpdateObject(c, m, t)
+
+       return t, err
+}
+
+func (c *DeviceSiteObjectManager) DeleteObject(m map[string]string) error {
+       overlay_name := m[OverlayResource]
+       t, err := c.GetObject(m)
+       if err != nil {
+               log.Println(err)
+               return nil
+       }
+       to := t.(*module.SiteObject)
+       site_name := to.Metadata.Name
+
+       dev_manager := GetManagerset().Device
+       dev, err := dev_manager.GetObject(m)
+
+       // Undeploy HubSite resource to device
+       resutil := NewResUtil()
+       resutil.AddResource(dev, "delete", &resource.EmptyResource{format_resource_name(site_name, ""), "HubSite"})
+       err = resutil.Undeploy(overlay_name)
+       if err != nil {
+               log.Println(err)
+       }
+
+       // DB Operation
+       err = GetDBUtils().DeleteObject(c, m)
+
+       return err
+}
+
+func (c *DeviceSiteObjectManager) TryDeleteSite(overlay string, hub string, device string) error {
+       m := make(map[string]string)
+       m[OverlayResource] = overlay
+       m[DeviceResource] = device
+
+       // get all sites and delete site which uses hub as proxy
+       ts, _ := c.GetObjects(m)
+       for _, t := range ts {
+               to := t.(*module.SiteObject)
+               if len(to.Specification.Hubs) > 0 && hub == to.Specification.Hubs[0] {
+                       m[SiteResource] = to.Metadata.Name
+                       c.DeleteObject(m)
+               }
+       }
+
+       return nil
+}
index bdd66a6..39355ab 100644 (file)
@@ -24,8 +24,8 @@ import (
        "strings"
 
        "github.com/akraino-edge-stack/icn-sdwan/central-controller/src/scc/pkg/module"
-       "github.com/open-ness/EMCO/src/orchestrator/pkg/infra/db"
        pkgerrors "github.com/pkg/errors"
+       "gitlab.com/project-emco/core/emco-base/src/orchestrator/pkg/infra/db"
 )
 
 const DEFAULTPORT = "6443"
@@ -209,6 +209,10 @@ func (c *HubObjectManager) DeleteObject(m map[string]string) error {
 
        // DB Operation
        err = GetDBUtils().DeleteObject(c, m)
+       err = GetDBUtils().UnregisterDevice(m[HubResource])
+       if err != nil {
+               log.Println(err)
+       }
 
        return err
 }
index 13569fc..63a34d1 100644 (file)
@@ -19,8 +19,8 @@ package manager
 import (
        "encoding/json"
        "github.com/akraino-edge-stack/icn-sdwan/central-controller/src/scc/pkg/module"
-       "github.com/open-ness/EMCO/src/orchestrator/pkg/infra/db"
        pkgerrors "github.com/pkg/errors"
+       "gitlab.com/project-emco/core/emco-base/src/orchestrator/pkg/infra/db"
        "io"
 )
 
@@ -142,7 +142,7 @@ func (c *HubConnObjectManager) GetConnectedDevices(overlay_name string, hub_name
                // get peer end's type and name
                t, n, ip := co.GetPeer("Hub", hub_name)
                if t == "Device" {
-                       device_names = append(device_names, n + ".." + ip)
+                       device_names = append(device_names, n+".."+ip)
                }
        }
        return device_names, nil
index cbcf70b..d85afbe 100644 (file)
@@ -22,8 +22,8 @@ import (
        "log"
 
        "github.com/akraino-edge-stack/icn-sdwan/central-controller/src/scc/pkg/module"
-       "github.com/open-ness/EMCO/src/orchestrator/pkg/infra/db"
        pkgerrors "github.com/pkg/errors"
+       "gitlab.com/project-emco/core/emco-base/src/orchestrator/pkg/infra/db"
 )
 
 type HubDeviceObjectKey struct {
@@ -137,7 +137,7 @@ func (c *HubDeviceObjectManager) CreateObject(m map[string]string, t module.Cont
 
                device.Status.DelegatedHub = hub_name
                dev_manager.UpdateObject(m, device)
-        }
+       }
 
        return c.CreateEmptyObject(), nil
 }
index 1398cb8..a4aac42 100644 (file)
@@ -21,8 +21,8 @@ import (
        "github.com/akraino-edge-stack/icn-sdwan/central-controller/src/scc/pkg/infra/validation"
        "github.com/akraino-edge-stack/icn-sdwan/central-controller/src/scc/pkg/module"
        "github.com/go-playground/validator/v10"
-       "github.com/open-ness/EMCO/src/orchestrator/pkg/infra/db"
        pkgerrors "github.com/pkg/errors"
+       "gitlab.com/project-emco/core/emco-base/src/orchestrator/pkg/infra/db"
        "io"
 )
 
index fb0c09a..f143adf 100644 (file)
@@ -29,7 +29,9 @@ type Managerset struct {
        ProviderIPRange *IPRangeObjectManager
        IPRange         *IPRangeObjectManager
        Cert            *CertificateObjectManager
-       Resource        *ResourceObjectManager
+       ClusterSync     *ClusterSyncObjectManager
+       Resource        *ResourceObjectManager
+       DeviceSite      *DeviceSiteObjectManager
 }
 
 var mgrset = Managerset{}
index e259025..8845ac4 100644 (file)
@@ -21,36 +21,36 @@ import (
        "encoding/json"
        "github.com/akraino-edge-stack/icn-sdwan/central-controller/src/scc/pkg/module"
        "github.com/akraino-edge-stack/icn-sdwan/central-controller/src/scc/pkg/resource"
-       "github.com/open-ness/EMCO/src/orchestrator/pkg/infra/db"
        pkgerrors "github.com/pkg/errors"
+       "gitlab.com/project-emco/core/emco-base/src/orchestrator/pkg/infra/db"
        "io"
        "log"
        "strings"
 )
 
 const (
DEFAULT_MARK = "30"
VTI_MODE = "VTI-based"
POLICY_MODE = "policy-based"
PUBKEY_AUTH = "pubkey"
FORCECRYPTOPROPOSAL = "0"
DEFAULT_CONN = "Conn"
DEFAULT_UPDOWN = "/etc/updown"
IPTABLES_UPDOWN = "/usr/lib/ipsec/_updown iptables"
OIP_UPDOWN = "/etc/updown_oip"
CONN_TYPE = "tunnel"
START_MODE = "start"
ADD_MODE = "add"
OVERLAYIP = "overlayip"
HUBTOHUB = "hub-to-hub"
HUBTODEVICE = "hub-to-device"
DEVICETODEVICE = "device-to-device"
BYCONFIG = "%config"
ANY = "%any"
BASE_PROTOCOL = "TCP"
- DEFAULT_K8S_API_SERVER_PORT = "6443"
ACCEPT = "ACCEPT"
WILDCARD_SUBNET="0.0.0.0"
      DEFAULT_MARK                = "30"
      VTI_MODE                    = "VTI-based"
      POLICY_MODE                 = "policy-based"
      PUBKEY_AUTH                 = "pubkey"
      FORCECRYPTOPROPOSAL         = "0"
      DEFAULT_CONN                = "Conn"
      DEFAULT_UPDOWN              = "/etc/updown"
      IPTABLES_UPDOWN             = "/usr/lib/ipsec/_updown iptables"
      OIP_UPDOWN                  = "/etc/updown_oip"
      CONN_TYPE                   = "tunnel"
      START_MODE                  = "start"
      ADD_MODE                    = "add"
      OVERLAYIP                   = "overlayip"
      HUBTOHUB                    = "hub-to-hub"
      HUBTODEVICE                 = "hub-to-device"
      DEVICETODEVICE              = "device-to-device"
      BYCONFIG                    = "%config"
      ANY                         = "%any"
      BASE_PROTOCOL               = "TCP"
      DEFAULT_K8S_API_SERVER_PORT = "6443"
      ACCEPT                      = "ACCEPT"
      WILDCARD_SUBNET             = "0.0.0.0"
 )
 
 type OverlayObjectKey struct {
@@ -265,12 +265,12 @@ func (c *OverlayObjectManager) SetupConnection(m map[string]string, m1 module.Co
                return pkgerrors.New("Error in getting proposals")
        }
        var all_proposals []string
-//     var proposalresources []*resource.ProposalResource
+       //      var proposalresources []*resource.ProposalResource
        for i := 0; i < len(proposals); i++ {
                proposal_obj := proposals[i].(*module.ProposalObject)
                all_proposals = append(all_proposals, proposal_obj.Metadata.Name)
                pr := proposal_obj.ToResource()
-//             proposalresources = append(proposalresources, pr)
+               //              proposalresources = append(proposalresources, pr)
 
                // Add proposal resources
                resutil.AddResource(m1, "create", pr)
@@ -308,22 +308,22 @@ func (c *OverlayObjectManager) SetupConnection(m map[string]string, m1 module.Co
 
                //IpsecResources
                conn1 := resource.Connection{
-                       Name:           DEFAULT_CONN + format_resource_name(obj1.Metadata.Name, obj2.Metadata.Name),
+                       Name:           DEFAULT_CONN + format_resource_name(obj1.Metadata.Name, obj2.Metadata.Name) + format_ip_as_suffix(obj1_ip),
                        ConnectionType: CONN_TYPE,
                        Mode:           ADD_MODE,
                        Mark:           DEFAULT_MARK,
-                       LocalSubnet:    WILDCARD_SUBNET+"/0",
-                       RemoteSubnet:   WILDCARD_SUBNET+"/0",
+                       LocalSubnet:    WILDCARD_SUBNET + "/0",
+                       RemoteSubnet:   WILDCARD_SUBNET + "/0",
                        LocalUpDown:    DEFAULT_UPDOWN,
                        CryptoProposal: all_proposals,
                }
                conn2 := resource.Connection{
-                       Name:           DEFAULT_CONN + format_resource_name(obj1.Metadata.Name, obj2.Metadata.Name),
+                       Name:           DEFAULT_CONN + format_resource_name(obj1.Metadata.Name, obj2.Metadata.Name) + format_ip_as_suffix(obj2_ip),
                        Mark:           DEFAULT_MARK,
                        Mode:           START_MODE,
                        ConnectionType: CONN_TYPE,
-                       LocalSubnet:    WILDCARD_SUBNET+"/0",
-                       RemoteSubnet:   WILDCARD_SUBNET+"/0",
+                       LocalSubnet:    WILDCARD_SUBNET + "/0",
+                       RemoteSubnet:   WILDCARD_SUBNET + "/0",
                        LocalUpDown:    DEFAULT_UPDOWN,
                        CryptoProposal: all_proposals,
                }
@@ -357,18 +357,18 @@ func (c *OverlayObjectManager) SetupConnection(m map[string]string, m1 module.Co
                }
 
                // for each edge connect to hub2(obj2), add Route in hub1(obj1)
-               // Todo: handle the error the route rule may fail if the vti interface is not exist 
+               // Todo: handle the error the route rule may fail if the vti interface is not exist
                dev_names, _ := hubConn.GetConnectedDevices(overlay_name, obj2.Metadata.Name)
                for _, dev_name := range dev_names {
                        log.Println(dev_name)
                        strs := strings.SplitN(dev_name, "..", 2)
                        if len(strs) == 2 {
                                log.Println("Route Rule in " + obj1.Metadata.Name + " : " + strs[1] + " via " + obj2.Metadata.Name)
-                               resutil.AddResource(m1, "create", &resource.RouteResource {
-                                       Name: strs[1] + "-" + obj2_ip,
+                               resutil.AddResource(m1, "create", &resource.RouteResource{
+                                       Name:        strs[1] + "-" + obj2_ip,
                                        Destination: strs[1],
-                                       Device: "vti_" + obj2_ip, // Todo: use the right ifname
-                                       Table: "default", // Todo: need check
+                                       Device:      "vti_" + obj2_ip, // Todo: use the right ifname
+                                       Table:       "default",        // Todo: need check
                                })
                        }
                }
@@ -386,13 +386,13 @@ func (c *OverlayObjectManager) SetupConnection(m map[string]string, m1 module.Co
                }
 
                obj1_conn := resource.Connection{
-                       Name:           DEFAULT_CONN + format_resource_name(obj2.Metadata.Name, ""),
+                       Name:           DEFAULT_CONN + format_resource_name(obj2.Metadata.Name, "") + format_ip_as_suffix(obj2_ip),
                        ConnectionType: CONN_TYPE,
                        Mode:           START_MODE,
                        Mark:           DEFAULT_MARK,
                        RemoteSourceIp: obj2_ip,
                        LocalUpDown:    DEFAULT_UPDOWN,
-                       LocalSubnet:    WILDCARD_SUBNET+"/0",
+                       LocalSubnet:    WILDCARD_SUBNET + "/0",
                        CryptoProposal: all_proposals,
                }
 
@@ -418,12 +418,12 @@ func (c *OverlayObjectManager) SetupConnection(m map[string]string, m1 module.Co
 
                //IpsecResources
                obj2_conn := resource.Connection{
-                       Name:           DEFAULT_CONN + format_resource_name(obj1.Metadata.Name, ""),
+                       Name:           DEFAULT_CONN + format_resource_name(obj1.Metadata.Name, "") + format_ip_as_suffix(obj1_ip),
                        Mode:           START_MODE,
                        LocalUpDown:    OIP_UPDOWN,
                        ConnectionType: CONN_TYPE,
                        LocalSourceIp:  BYCONFIG,
-                       RemoteSubnet:   WILDCARD_SUBNET+"/0",
+                       RemoteSubnet:   WILDCARD_SUBNET + "/0",
                        CryptoProposal: all_proposals,
                }
                obj2_ipsec_resource = resource.IpsecResource{
@@ -447,15 +447,15 @@ func (c *OverlayObjectManager) SetupConnection(m map[string]string, m1 module.Co
                hubs, _ := hub_manager.GetObjects(m)
                for _, hub_obj := range hubs {
                        if hub_obj.GetMetadata().Name != obj1.GetMetadata().Name {
-                               resutil.AddResource(hub_obj, "create", &resource.RouteResource {
-                                       Name: obj2_ip + "-" + obj1_ip,
+                               resutil.AddResource(hub_obj, "create", &resource.RouteResource{
+                                       Name:        obj2_ip + "-" + obj1_ip,
                                        Destination: obj2_ip,
-                                       Device: "vti_" + obj1_ip, // Todo: use the right ifname
-                                       Table: "default", // Todo: need check
+                                       Device:      "vti_" + obj1_ip, // Todo: use the right ifname
+                                       Table:       "default",        // Todo: need check
                                })
                        }
                }
-               // for each edge connect to obj1 (1) add route( e.g. to obj2 via obj1) (2) add SNAT (e.g. to obj2 --to-source edge ip) 
+               // for each edge connect to obj1 (1) add route( e.g. to obj2 via obj1) (2) add SNAT (e.g. to obj2 --to-source edge ip)
                dev_names, _ := hubConn.GetConnectedDevices(overlay_name, obj1.Metadata.Name)
                mm := make(map[string]string)
                mm[OverlayResource] = overlay_name
@@ -468,39 +468,39 @@ func (c *OverlayObjectManager) SetupConnection(m map[string]string, m1 module.Co
                                dev := dev_obj.(*module.DeviceObject)
                                if err == nil {
                                        log.Println("Route Rule in " + strs[0] + " : " + obj2_ip + " via " + obj1.Metadata.Name)
-                                       resutil.AddResource(dev_obj, "create", &resource.RouteResource {
-                                               Name: obj2_ip + "-" + obj1_ip,
+                                       resutil.AddResource(dev_obj, "create", &resource.RouteResource{
+                                               Name:        obj2_ip + "-" + obj1_ip,
                                                Destination: obj2_ip,
-                                               Device: "#" + dev.Status.Ip, // Todo: how to get net1
-                                               Table: "cnf", // Todo: need check
+                                               Device:      "#" + dev.Status.Ip, // Todo: how to get net1
+                                               Table:       "cnf",               // Todo: need check
                                        })
 
-                                       log.Println("NAT Rule in " + strs[0] + " to " + obj2.Metadata.Name )
-                                       resutil.AddResource(dev_obj, "create", &resource.FirewallNatResource {
-                                               Name: obj2_ip + "-" + dev.Metadata.Name,
+                                       log.Println("NAT Rule in " + strs[0] + " to " + obj2.Metadata.Name)
+                                       resutil.AddResource(dev_obj, "create", &resource.FirewallNatResource{
+                                               Name:          obj2_ip + "-" + dev.Metadata.Name,
                                                DestinationIP: obj2_ip,
-                                               Dest: "#source",
-                                               SourceDestIP: dev.Status.DataIps[hubName],
-                                               Index: "1",
-                                               Target: "SNAT",
+                                               Dest:          "#source",
+                                               SourceDestIP:  dev.Status.DataIps[hubName],
+                                               Index:         "1",
+                                               Target:        "SNAT",
                                        })
 
                                        log.Println("Route Rule in " + obj2_ip + " to " + dev.Metadata.Name)
-                                       resutil.AddResource(obj2, "create", &resource.RouteResource {
-                                               Name: dev.Status.DataIps[hubName] + "-" + obj1_ip,
+                                       resutil.AddResource(obj2, "create", &resource.RouteResource{
+                                               Name:        dev.Status.DataIps[hubName] + "-" + obj1_ip,
                                                Destination: dev.Status.DataIps[hubName],
-                                               Device: "#" + obj2.Status.Ip,
-                                               Table: "cnf",
+                                               Device:      "#" + obj2.Status.Ip,
+                                               Table:       "cnf",
                                        })
 
-                                       log.Println("NAT Rule in " + obj2_ip + " to " + dev.Metadata.Name )
-                                       resutil.AddResource(obj2, "create", &resource.FirewallNatResource {
-                                               Name: dev.Status.DataIps[hubName] + "-" + obj2.Metadata.Name,
+                                       log.Println("NAT Rule in " + obj2_ip + " to " + dev.Metadata.Name)
+                                       resutil.AddResource(obj2, "create", &resource.FirewallNatResource{
+                                               Name:          dev.Status.DataIps[hubName] + "-" + obj2.Metadata.Name,
                                                DestinationIP: dev.Status.DataIps[hubName],
-                                               Dest: "#source",
-                                               SourceDestIP: obj2_ip,
-                                               Index: "1",
-                                               Target: "SNAT",
+                                               Dest:          "#source",
+                                               SourceDestIP:  obj2_ip,
+                                               Index:         "1",
+                                               Target:        "SNAT",
                                        })
 
                                } else {
@@ -512,19 +512,19 @@ func (c *OverlayObjectManager) SetupConnection(m map[string]string, m1 module.Co
 
                if is_delegated {
                        log.Println("adding rules for delegate connections")
-                       resutil.AddResource(m2, "create", &resource.RouteResource {
-                               Name: "default4" + obj2.Metadata.Name,
+                       resutil.AddResource(m2, "create", &resource.RouteResource{
+                               Name:        "default4" + obj2.Metadata.Name,
                                Destination: "default",
-                               Gateway: obj1_ip,
-                               Device: "#" + obj2_ip,
-                               Table: "cnf",
+                               Gateway:     obj1_ip,
+                               Device:      "#" + obj2_ip,
+                               Table:       "cnf",
                        })
-                       resutil.AddResource(m2, "create", &resource.FirewallNatResource {
-                               Name: "default4" + obj2.Metadata.Name,
+                       resutil.AddResource(m2, "create", &resource.FirewallNatResource{
+                               Name:         "default4" + obj2.Metadata.Name,
                                SourceDestIP: obj2_ip,
-                               Dest: "#source",
-                               Index: "0",
-                               Target: "SNAT",
+                               Dest:         "#source",
+                               Index:        "0",
+                               Target:       "SNAT",
                        })
                }
        case DEVICETODEVICE:
index 8104ea7..fcb8241 100644 (file)
@@ -19,8 +19,8 @@ package manager
 import (
        "encoding/json"
        "github.com/akraino-edge-stack/icn-sdwan/central-controller/src/scc/pkg/module"
-       "github.com/open-ness/EMCO/src/orchestrator/pkg/infra/db"
        pkgerrors "github.com/pkg/errors"
+       "gitlab.com/project-emco/core/emco-base/src/orchestrator/pkg/infra/db"
        "io"
 )
 
index 2debe0a..1aae0d1 100644 (file)
@@ -21,14 +21,14 @@ import (
        "io"
 
        "github.com/akraino-edge-stack/icn-sdwan/central-controller/src/scc/pkg/module"
-       "github.com/open-ness/EMCO/src/orchestrator/pkg/infra/db"
        pkgerrors "github.com/pkg/errors"
+       "gitlab.com/project-emco/core/emco-base/src/orchestrator/pkg/infra/db"
 )
 
 type ResourceObjectKey struct {
        Cluster string `json:"cluster-info"`
-       Type    string `json:"type"`
-       Name    string `json:"name"`
+       Type    string `json:"type"`
+       Name    string `json:"name"`
 }
 
 // ResourceObjectManager implements the ControllerObjectManager
@@ -63,8 +63,8 @@ func (c *ResourceObjectManager) GetStoreKey(m map[string]string, t module.Contro
        // Currently no collections fetching supported
        return ResourceObjectKey{
                Cluster: m[OverlayResource] + "-" + m[DeviceResource],
-               Type:  m["Type"],
-               Name:  m["Name"],
+               Type:    m["Type"],
+               Name:    m["Name"],
        }, nil
 }
 
index 887fe65..625aefc 100644 (file)
@@ -22,11 +22,11 @@ import (
        rsyncclient "github.com/akraino-edge-stack/icn-sdwan/central-controller/src/scc/pkg/client"
        "github.com/akraino-edge-stack/icn-sdwan/central-controller/src/scc/pkg/module"
        "github.com/akraino-edge-stack/icn-sdwan/central-controller/src/scc/pkg/resource"
-       "github.com/open-ness/EMCO/src/orchestrator/pkg/resourcestatus"
+       "gitlab.com/project-emco/core/emco-base/src/orchestrator/pkg/resourcestatus"
 
-       "github.com/open-ness/EMCO/src/orchestrator/pkg/appcontext"
-       "github.com/open-ness/EMCO/src/orchestrator/pkg/infra/rpc"
-       controller "github.com/open-ness/EMCO/src/orchestrator/pkg/module/controller"
+       "gitlab.com/project-emco/core/emco-base/src/orchestrator/pkg/appcontext"
+       "gitlab.com/project-emco/core/emco-base/src/orchestrator/pkg/infra/rpc"
+       controller "gitlab.com/project-emco/core/emco-base/src/orchestrator/pkg/module/controller"
 
        "k8s.io/apimachinery/pkg/runtime/schema"
        "k8s.io/apimachinery/pkg/util/wait"
@@ -42,7 +42,7 @@ import (
 var rsync_initialized = false
 var provider_name = "akraino_scc"
 var project_name = "akraino_scc"
-var Resource_mux  = sync.Mutex{}
+var Resource_mux = sync.Mutex{}
 
 // sdewan definition
 type DeployResource struct {
@@ -130,15 +130,15 @@ func addResourcesToCluster(ct appcontext.AppContext, ch interface{}, target stri
        }
 
        var resDepInstr struct {
-               Resdep map[string]string `json:"resdependency"`
+               Resdep map[string][]string `json:"resdependency"`
        }
-       resdep := make(map[string]string)
+       resdep := make(map[string][]string)
 
        for _, resource := range resources {
                resource_name := getResourceName(resource)
                resource_data := resource.Resource.ToYaml(target)
                resOrderInstr.Resorder = append(resOrderInstr.Resorder, resource_name)
-               resdep[resource_name] = "go"
+               resdep[resource_name] = []string{}
 
                rh, err := ct.AddResource(ch, resource_name, resource_data)
                if isDeploy == false {
@@ -170,7 +170,7 @@ func addResourcesToCluster(ct appcontext.AppContext, ch interface{}, target stri
 }
 
 func InitRsyncClient() bool {
-       client := controller.NewControllerClient()
+       client := controller.NewControllerClient("resources", "data", "orchestrator")
 
        vals, _ := client.GetControllers()
        found := false
@@ -258,7 +258,7 @@ func (d *ResUtil) DeployOneResource(app_name string, format string, device modul
        appdep := make(map[string]string)
        device_app_name := d.getDeviceAppName(device)
        appOrderInstr.Apporder = append(appOrderInstr.Apporder, device_app_name)
-       appdep[device_app_name] = "go"
+       appdep[device_app_name] = ""
 
        apphandle, _ := context.AddApp(compositeHandle, device_app_name)
 
@@ -309,6 +309,10 @@ func (d *ResUtil) UpdateOneResource(cid string, device module.ControllerObject,
 }
 
 func (d *ResUtil) Deploy(overlay string, app_name string, format string) error {
+       return d.DeployUpdate(overlay, app_name, format, false)
+}
+
+func (d *ResUtil) DeployUpdate(overlay string, app_name string, format string, update bool) error {
        isErr := false
        errMessage := "Failed:"
        res_manager := GetManagerset().Resource
@@ -349,7 +353,7 @@ func (d *ResUtil) Deploy(overlay string, app_name string, format string) error {
                                if resource.Status != 1 {
                                        // resource is not deployed or failed to deploy
                                        if resobj.Specification.Ref == 0 {
-                                               // resource needs to be deployed        
+                                               // resource needs to be deployed
                                                cid, err := d.DeployOneResource(app_name, format, device, resource)
 
                                                if err != nil {
@@ -367,7 +371,9 @@ func (d *ResUtil) Deploy(overlay string, app_name string, format string) error {
                                                }
                                        } else {
                                                // add ref
-                                               resobj.Specification.Ref += 1
+                                               if !update {
+                                                       resobj.Specification.Ref += 1
+                                               }
                                                resource.Status = 1
                                                res_manager.UpdateObject(m, resobj)
                                        }
@@ -385,7 +391,9 @@ func (d *ResUtil) Deploy(overlay string, app_name string, format string) error {
                                                resource.Status = 1
                                                // add ref
                                                resobj.Specification.Hash = resource_data_hash
-                                               resobj.Specification.Ref += 1
+                                               if !update {
+                                                       resobj.Specification.Ref += 1
+                                               }
 
                                                res_manager.UpdateObject(m, resobj)
                                        }
@@ -416,8 +424,8 @@ func (d *ResUtil) Undeploy(overlay string) error {
                m[DeviceResource] = device.GetType() + "." + device.GetMetadata().Name
 
                // Use reversed order to do undeploy
-               for i:=len(res.Resources)-1; i>=0; i-- {
-               // for _, resource := range res.Resources {
+               for i := len(res.Resources) - 1; i >= 0; i-- {
+                       // for _, resource := range res.Resources {
                        resource := res.Resources[i]
                        m["Name"] = resource.Resource.GetName()
                        m["Type"] = resource.Resource.GetType()
@@ -442,6 +450,19 @@ func (d *ResUtil) Undeploy(overlay string) error {
                                                // reset resource status
                                                resource.Status = 1
                                                resobj.Specification.Ref = 0
+
+                                               /*
+                                                       // delete app from context db
+                                                       context := appcontext.AppContext{}
+                                                       _, err := context.LoadAppContext(resobj.Specification.ContextId)
+                                                       if err != nil {
+                                                               err = context.DeleteCompositeApp()
+                                                       }
+
+                                                       if err != nil {
+                                                               log.Println(err)
+                                                       }
+                                               */
                                                res_manager.DeleteObject(m)
                                        }
                                } else {
index f1a8ab1..78046e4 100644 (file)
@@ -26,3 +26,7 @@ func format_resource_name(name1 string, name2 string) string {
 
        return strings.ToLower(name1 + name2)
 }
+
+func format_ip_as_suffix(ip string) string {
+       return "_" + strings.Replace(ip, ".", "", -1)
+}
diff --git a/central-controller/src/scc/pkg/module/clustersyncobject.go b/central-controller/src/scc/pkg/module/clustersyncobject.go
new file mode 100644 (file)
index 0000000..6968dfa
--- /dev/null
@@ -0,0 +1,36 @@
+/*
+ * Copyright 2020 Intel Corporation, Inc
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package module
+
+// App contains metadata for Apps
+type ClusterSyncObject struct {
+       Metadata      ObjectMetaData        `json:"metadata"`
+       Specification ClusterSyncObjectSpec `json:"spec"`
+}
+
+// ClusterSyncObjectSpec contains the parameters
+type ClusterSyncObjectSpec struct {
+       Kv []map[string]interface{} `json:"kv"`
+}
+
+func (c *ClusterSyncObject) GetMetadata() ObjectMetaData {
+       return c.Metadata
+}
+
+func (c *ClusterSyncObject) GetType() string {
+       return "ClusterSync"
+}
index e507967..8f9fa53 100644 (file)
@@ -18,6 +18,7 @@ package module
 
 import (
        "log"
+       "strings"
 )
 
 type states struct {
@@ -35,9 +36,9 @@ var StateEnum = &states{
 }
 
 type ConnectionResource struct {
-       ConnObject  string  `json:"-"`
-       Name        string  `json:"-"`
-       Type        string  `json:"-"`
+       ConnObject string `json:"-"`
+       Name       string `json:"-"`
+       Type       string `json:"-"`
 }
 
 type ConnectionObject struct {
@@ -47,18 +48,18 @@ type ConnectionObject struct {
 
 //ConnectionInfo contains the connection information
 type ConnectionInfo struct {
-       End1         ConnectionEnd `json:"end1"`
-       End2         ConnectionEnd `json:"end2"`
+       End1         ConnectionEnd        `json:"end1"`
+       End2         ConnectionEnd        `json:"end2"`
        Resources    []ConnectionResource `json:"-"`
-       State        string        `json:"state"`
-       ErrorMessage string        `json:"message"`
+       State        string               `json:"state"`
+       ErrorMessage string               `json:"message"`
 }
 
 type ConnectionEnd struct {
-       Name        string   `json:"name"`
-       Type        string   `json:"type"`
-       IP          string   `json:"ip"`
-       ConnObject  string   `json:"-"`
+       Name       string `json:"name"`
+       Type       string `json:"type"`
+       IP         string `json:"ip"`
+       ConnObject string `json:"-"`
 }
 
 func (c *ConnectionObject) GetMetadata() ObjectMetaData {
@@ -83,6 +84,15 @@ func (c *ConnectionObject) GetPeer(t string, n string) (string, string, string)
        return "", "", ""
 }
 
+func ParseEndName(name string) (string, string) {
+       s := strings.SplitN(name, ".", 2)
+       if len(s) == 2 {
+               return s[0], s[1]
+       }
+
+       return "Hub", name
+}
+
 func CreateEndName(t string, n string) string {
        return t + "." + n
 }
@@ -95,10 +105,10 @@ func NewConnectionEnd(conn_obj ControllerObject, ip string) ConnectionEnd {
        obj_str, err := GetObjectBuilder().ToString(conn_obj)
        if err == nil {
                return ConnectionEnd{
-                       Name:        CreateEndName(conn_obj.GetType(), conn_obj.GetMetadata().Name),
-                       Type:        conn_obj.GetType(),
-                       IP:          ip,
-                       ConnObject:  obj_str,
+                       Name:       CreateEndName(conn_obj.GetType(), conn_obj.GetMetadata().Name),
+                       Type:       conn_obj.GetType(),
+                       IP:         ip,
+                       ConnObject: obj_str,
                }
        } else {
                log.Println(err)
index 82fc300..daf81ab 100644 (file)
@@ -32,7 +32,7 @@ type DeviceObjectSpec struct {
        UseHub4Internet      bool     `json:"useHub4Internet"`
        DedicatedSFC         bool     `json:"dedicatedSFC"`
        CertificateId        string   `json:"certificateId"`
-       KubeConfig           string   `json:"kubeConfig"`
+       KubeConfig           string   `json:"kubeConfig" encrypted:""`
 }
 
 // DeviceObjectStatus
@@ -46,7 +46,7 @@ type DeviceObjectStatus struct {
        // DataIps saves the overlay ips assigned for different traffic tunnel
        DataIps map[string]string
        // Status Data
-       Data map[string]string
+       Data         map[string]string
        DelegatedHub string
 }
 
index 3b681bb..e8b1bf4 100644 (file)
@@ -25,7 +25,7 @@ type HubDeviceObject struct {
 //HubDeviceObjectSpec contains the parameters
 type HubDeviceObjectSpec struct {
        Device        string `json:"device"`
-       IsDelegateHub bool `json:"isDelegateHub"`
+       IsDelegateHub bool   `json:"isDelegateHub"`
 }
 
 func (c *HubDeviceObject) GetMetadata() ObjectMetaData {
index 3e44e3d..c10b16e 100644 (file)
@@ -32,7 +32,7 @@ type HubObject struct {
 type HubObjectSpec struct {
        PublicIps     []string `json:"publicIps"`
        CertificateId string   `json:"certificateId"`
-       KubeConfig    string   `json:"kubeConfig"`
+       KubeConfig    string   `json:"kubeConfig" encrypted:""`
 }
 
 //HubObjectStatus
index 0cfce7e..89a3669 100644 (file)
@@ -18,16 +18,16 @@ package module
 
 // App contains metadata for Apps
 type ResourceObject struct {
-       Metadata      ObjectMetaData    `json:"metadata"`
+       Metadata      ObjectMetaData     `json:"metadata"`
        Specification ResourceObjectSpec `json:"spec"`
 }
 
 //ResourceObjectSpec contains the parameters
 type ResourceObjectSpec struct {
-       Hash             string   `json:"hash"`
-       Ref                      int      `json:"ref"`
-       ContextId                string      `json:"cid"`
-       Status                   string      `json:"status"`
+       Hash      string `json:"hash"`
+       Ref       int    `json:"ref"`
+       ContextId string `json:"cid"`
+       Status    string `json:"status"`
 }
 
 func (c *ResourceObject) GetMetadata() ObjectMetaData {
@@ -36,4 +36,4 @@ func (c *ResourceObject) GetMetadata() ObjectMetaData {
 
 func (c *ResourceObject) GetType() string {
        return "Resource"
-}
\ No newline at end of file
+}
diff --git a/central-controller/src/scc/pkg/module/siteobject.go b/central-controller/src/scc/pkg/module/siteobject.go
new file mode 100644 (file)
index 0000000..28805a2
--- /dev/null
@@ -0,0 +1,38 @@
+/*
+ * Copyright 2020 Intel Corporation, Inc
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package module
+
+// App contains metadata for Apps
+type SiteObject struct {
+       Metadata      ObjectMetaData `json:"metadata"`
+       Specification SiteObjectSpec `json:"spec"`
+}
+
+//SiteObjectSpec contains the parameters
+type SiteObjectSpec struct {
+       Hubs   []string `json:"hubs"`
+       Url    string   `json:"url"`
+       Subnet string   `json:"subnet"`
+}
+
+func (c *SiteObject) GetMetadata() ObjectMetaData {
+       return c.Metadata
+}
+
+func (c *SiteObject) GetType() string {
+       return "site"
+}
index e6983e9..6ceb59b 100644 (file)
@@ -19,8 +19,8 @@ package resource
 import ()
 
 type EmptyResource struct {
-       Name     string
-       Type     string
+       Name string
+       Type string
 }
 
 func (c *EmptyResource) GetName() string {
index 46784d3..cc86ca2 100644 (file)
@@ -53,23 +53,23 @@ metadata:
 spec:
   target: ` + c.Target + `
   src_dip: ` + c.SourceDestIP
-        if c.DestinationIP != "" {
+       if c.DestinationIP != "" {
                basic += `
   dest_ip: ` + c.DestinationIP
-        }
+       }
 
-        if c.DestinationPort != "" {
+       if c.DestinationPort != "" {
                basic += `
   dest_port: ` + c.DestinationPort
-        }
+       }
        if c.Dest != "" {
                basic += `
   dest: "` + c.Dest + `"`
-        }
+       }
        if c.SourceDestPort != "" {
                basic += `
   src_dport: ` + c.SourceDestPort
-        }
+       }
        if c.Protocol != "" {
                basic += `
   proto: ` + c.Protocol
@@ -77,7 +77,7 @@ spec:
        if c.Source != "" {
                basic += `
   src: "` + c.Source + `"`
-        }
+       }
        if c.SourceIP != "" {
                basic += `
   src_ip: ` + c.SourceIP
@@ -85,7 +85,7 @@ spec:
        if c.Index != "" {
                basic += `
   index: "` + c.Index + `"`
-        }
+       }
 
        return basic
 }
diff --git a/central-controller/src/scc/pkg/resource/hubsite_resource.go b/central-controller/src/scc/pkg/resource/hubsite_resource.go
new file mode 100644 (file)
index 0000000..8ce4b88
--- /dev/null
@@ -0,0 +1,71 @@
+/*
+ * Copyright 2020 Intel Corporation, Inc
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES 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 ()
+
+type HubSiteResource struct {
+       Name      string
+       Type      string
+       Site      string
+       Subnet    string
+       HubIP     string
+       DevicePIP string
+}
+
+func (c *HubSiteResource) GetName() string {
+       return c.Name
+}
+
+func (c *HubSiteResource) GetType() string {
+       return "HubSite"
+}
+
+func (c *HubSiteResource) ToYaml(target string) string {
+       result := `apiVersion: ` + SdewanApiVersion + `
+kind: CNFHubSite
+metadata:
+  name: ` + c.Name + `
+  namespace: default
+  labels:
+    sdewanPurpose: ` + SdewanPurpose + `
+    targetCluster: ` + target + `
+spec:
+  type: ` + c.Type
+       if c.Site != "" {
+               result += `
+  site: '` + c.Site + `'`
+       }
+       if c.Subnet != "" {
+               result += `
+  subnet: '` + c.Subnet + `'`
+       }
+       if c.HubIP != "" {
+               result += `
+  hubip: '` + c.HubIP + `'`
+       }
+       if c.DevicePIP != "" {
+               result += `
+  devicepip: '` + c.DevicePIP + `'`
+       }
+
+       return result
+}
+
+func init() {
+       GetResourceBuilder().Register("HubSite", &HubSiteResource{})
+}
index 1ed8382..961cafb 100644 (file)
 package resource
 
 type RouteResource struct {
-       Name    string
-       Destination       string
-       Gateway string
-       Device       string
-       Table    string
+       Name        string
+       Destination string
+       Gateway     string
+       Device      string
+       Table       string
 }
 
 func (c *RouteResource) GetName() string {
@@ -46,11 +46,11 @@ spec:
   dev: "` + c.Device + `"
   table: ` + c.Table
 
-       if c.Gateway != "" {
-              basic += `
+       if c.Gateway != "" {
+               basic += `
   gw: ` + c.Gateway
-  }
-       return basic
+       }
+       return basic
 }
 
 func init() {
diff --git a/central-controller/src/scc/ref-schemas/v1.yaml b/central-controller/src/scc/ref-schemas/v1.yaml
new file mode 100644 (file)
index 0000000..a79697f
--- /dev/null
@@ -0,0 +1,129 @@
+name: emco-base
+resources:
+#emco-clm
+  - name: clusterProvider
+  - name: cluster
+    parent: clusterProvider
+  - name: clusterLabel
+    parent: cluster
+  - name: clusterKv
+    parent: cluster
+  - name: clusterSyncObject
+    parent: clusterProvider
+#emco-dcm
+  - name: logicalCloud
+    parent: project
+  - name: clusterReference
+    parent: logicalCloud
+    references:
+      - name: cluster
+  - name: clusterQuota
+    parent: logicalCloud
+  - name: logicalCloudKv
+    parent: logicalCloud
+  - name: userPermission
+    parent: logicalCloud
+#emco-dtc
+  - name: trafficGroupIntent
+    parent: deploymentIntentGroup
+  - name: inboundServerIntent
+    parent: trafficGroupIntent
+    references:
+      - name: app
+  - name: inboundClientsIntent
+    parent: inboundServerIntent
+    references:
+      - name: app
+#emco-gac
+  - name: genericK8sIntent
+    parent: deploymentIntentGroup
+  - name: genericResource
+    parent: genericK8sIntent
+    references:
+      - name: app
+  - name: customization
+    parent: genericResource
+    references:
+      - name: cluster
+#emco-hpa-plc
+  - name: hpaIntent
+    parent: deploymentIntentGroup
+    references:
+      - name: app
+  - name: hpaConsumer
+    parent: hpaIntent
+  - name: hpaResource
+    parent: hpaConsumer
+#emco-ncm
+  - name: providerNetwork
+    parent: cluster
+  - name: network
+    parent: cluster
+#emco-orchestrator
+  - name: controllerGroup.controller
+  - name: project
+  - name: compositeApp.compositeAppVersion
+    parent: project
+  - name: app
+    parent: compositeAppVersion
+  - name: compositeProfile
+    parent: compositeAppVersion
+  - name: appProfile
+    parent: compositeProfile
+    references:
+      - name: app
+  - name: deploymentIntentGroup
+    parent: compositeAppVersion
+    references:
+      - name: logicalCloud
+      - name: compositeProfile
+  - name: groupIntent
+    parent: deploymentIntentGroup
+    references:
+      - name: controller
+        type: map
+        map: intent
+        fixedKv:
+          controllerGroup: orchestrator
+        filterKeys:
+          - genericPlacementIntent
+  - name: genericPlacementIntent
+    parent: deploymentIntentGroup
+  - name: genericAppPlacementIntent
+    parent: genericPlacementIntent
+    references:
+      - name: app
+      - name: cluster
+        type: many
+  - name: appDependency
+    parent: app
+#emco-ovnaction
+  - name: netControllerIntent
+    parent: deploymentIntentGroup
+  - name: workloadIntent
+    parent: netControllerIntent
+    references:
+      - name: app
+  - name: interfaceIntent
+    parent: workloadIntent
+#emco-sfc
+  - name: sfcIntent
+    parent: deploymentIntentGroup
+  - name: sfcLink
+    parent: sfcIntent
+    references:
+      - name: app
+  - name: sfcClientSelector
+    parent: sfcIntent
+  - name: sfcProviderNetwork
+    parent: sfcIntent
+#emco-sfc-client
+  - name: sfcClientIntent
+    parent: deploymentIntentGroup
+    references:
+      - name: sfcIntent
+      - name: app
+        commonKey: compositeAppVersion
+#emco-workflowmgr
+  - name: workflowIntent
+    parent: deploymentIntentGroup
diff --git a/central-controller/src/scc/tools/ewoctl/examples/clustersyncobject.yaml b/central-controller/src/scc/tools/ewoctl/examples/clustersyncobject.yaml
new file mode 100644 (file)
index 0000000..138d4c8
--- /dev/null
@@ -0,0 +1,46 @@
+# SPDX-License-Identifier: Apache-2.0\r
+# Copyright (c) 2020 Intel Corporation\r
+\r
+# creating overlay1\r
+version: ewo/v1\r
+resourceContext:\r
+  anchor: overlays\r
+metadata:\r
+  name: overlay1\r
+  description: \r
+  userData1: \r
+  userData2: \r
+\r
+---\r
+# creating cluster-sync-obj\r
+version: ewo/v1\r
+resourceContext:\r
+  anchor: overlays/overlay1/cluster-sync-objects\r
+metadata:\r
+  name: cso1\r
+  description: \r
+  userData1: \r
+  userData2: \r
+spec:\r
+  kv:\r
+    - key1: value1\r
+    - key2: value2\r
+    - key3: value3 \r
+\r
+---\r
+# creating cluster-sync-obj\r
+version: ewo/v1\r
+resourceContext:\r
+  anchor: overlays/overlay1/cluster-sync-objects\r
+metadata:\r
+  name: cso2\r
+  description: \r
+  userData1: \r
+  userData2: \r
+spec:\r
+  kv:\r
+    - gitType: github\r
+    - user: user1\r
+    - token: xxx\r
+    - repoUrl: https://github.com/org1/myRepo\r
+    - branch: main 
\ No newline at end of file
diff --git a/central-controller/src/vendor/github.com/open-ness/EMCO/src/go.mod b/central-controller/src/vendor/github.com/open-ness/EMCO/src/go.mod
deleted file mode 100644 (file)
index 4674501..0000000
+++ /dev/null
@@ -1,11 +0,0 @@
-module github.com/open-ness/EMCO/src/orchestrator
-
-require (
-        github.com/open-ness/EMCO/src/rsync v0.0.0-00010101000000-000000000000
-)
-
-replace (
-        github.com/open-ness/EMCO/src/rsync => ../../../../../rsync
-)
-
-go 1.17
diff --git a/central-controller/src/vendor/github.com/open-ness/EMCO/src/orchestrator/go.mod b/central-controller/src/vendor/github.com/open-ness/EMCO/src/orchestrator/go.mod
deleted file mode 100644 (file)
index 0b99236..0000000
+++ /dev/null
@@ -1,11 +0,0 @@
-module github.com/open-ness/EMCO/src/orchestrator
-
-require (
-        github.com/open-ness/EMCO/src/rsync v0.0.0-00010101000000-000000000000
-)
-
-replace (
-        github.com/open-ness/EMCO/src/rsync => ../../../../../../rsync
-)
-
-go 1.17
diff --git a/central-controller/src/vendor/github.com/open-ness/EMCO/src/orchestrator/pkg/appcontext/subresources/approval.go b/central-controller/src/vendor/github.com/open-ness/EMCO/src/orchestrator/pkg/appcontext/subresources/approval.go
deleted file mode 100644 (file)
index fb5eb77..0000000
+++ /dev/null
@@ -1,14 +0,0 @@
-// SPDX-License-Identifier: Apache-2.0
-// Copyright (c) 2020 Intel Corporation
-
-package subresources
-
-// The ApprovalSubresource type defines the 4 necessary parameters
-// that the "approval" subresource of a CertificateSigningRequest in K8s
-// requires, in a forma tto be exchanged over AppContext
-type ApprovalSubresource struct {
-       LastUpdateTime string `json:"lastUpdateTime,omitempty"`
-       Message        string `json:"message,omitempty"`
-       Reason         string `json:"reason,omitempty"`
-       Type           string `json:"type,omitempty"`
-}
diff --git a/central-controller/src/vendor/github.com/open-ness/EMCO/src/orchestrator/pkg/infra/config/config_test.go b/central-controller/src/vendor/github.com/open-ness/EMCO/src/orchestrator/pkg/infra/config/config_test.go
deleted file mode 100644 (file)
index dd39318..0000000
+++ /dev/null
@@ -1,27 +0,0 @@
-// SPDX-License-Identifier: Apache-2.0
-// Copyright (c) 2020 Intel Corporation
-
-package config
-
-import (
-       "testing"
-)
-
-func TestReadConfigurationFile(t *testing.T) {
-       t.Run("Non Existent Configuration File", func(t *testing.T) {
-               _, err := readConfigFile("filedoesnotexist.json")
-               if err == nil {
-                       t.Fatal("ReadConfiguationFile: Expected Error, got nil")
-               }
-       })
-
-       t.Run("Read Configuration File", func(t *testing.T) {
-               conf, err := readConfigFile("../../../tests/configs/mock_config.json")
-               if err != nil {
-                       t.Fatal("ReadConfigurationFile: Error reading file: ", err)
-               }
-               if conf.DatabaseType != "mock_db_test" {
-                       t.Fatal("ReadConfigurationFile: Incorrect entry read from file")
-               }
-       })
-}
diff --git a/central-controller/src/vendor/github.com/open-ness/EMCO/src/orchestrator/pkg/infra/db/mongo.go b/central-controller/src/vendor/github.com/open-ness/EMCO/src/orchestrator/pkg/infra/db/mongo.go
deleted file mode 100644 (file)
index a2eeac9..0000000
+++ /dev/null
@@ -1,409 +0,0 @@
-// SPDX-License-Identifier: Apache-2.0
-// Copyright (c) 2020 Intel Corporation
-
-package db
-
-import (
-       "encoding/json"
-       "os"
-       "sort"
-
-       "golang.org/x/net/context"
-
-       "github.com/open-ness/EMCO/src/orchestrator/pkg/infra/config"
-
-       pkgerrors "github.com/pkg/errors"
-       "go.mongodb.org/mongo-driver/bson"
-       "go.mongodb.org/mongo-driver/bson/primitive"
-       "go.mongodb.org/mongo-driver/mongo"
-       "go.mongodb.org/mongo-driver/mongo/options"
-)
-
-// MongoCollection defines the a subset of MongoDB operations
-// Note: This interface is defined mainly for mock testing
-type MongoCollection interface {
-       InsertOne(ctx context.Context, document interface{},
-               opts ...*options.InsertOneOptions) (*mongo.InsertOneResult, error)
-       FindOne(ctx context.Context, filter interface{},
-               opts ...*options.FindOneOptions) *mongo.SingleResult
-       FindOneAndUpdate(ctx context.Context, filter interface{},
-               update interface{}, opts ...*options.FindOneAndUpdateOptions) *mongo.SingleResult
-       DeleteOne(ctx context.Context, filter interface{},
-               opts ...*options.DeleteOptions) (*mongo.DeleteResult, error)
-       DeleteMany(ctx context.Context, filter interface{},
-               opts ...*options.DeleteOptions) (*mongo.DeleteResult, error)
-       Find(ctx context.Context, filter interface{},
-               opts ...*options.FindOptions) (*mongo.Cursor, error)
-       UpdateOne(ctx context.Context, filter interface{}, update interface{},
-               opts ...*options.UpdateOptions) (*mongo.UpdateResult, error)
-       CountDocuments(ctx context.Context, filter interface{},
-               opts ...*options.CountOptions) (int64, error)
-}
-
-// MongoStore is an implementation of the db.Store interface
-type MongoStore struct {
-       db *mongo.Database
-}
-
-// This exists only for allowing us to mock the collection object
-// for testing purposes
-var getCollection = func(coll string, m *MongoStore) MongoCollection {
-       return m.db.Collection(coll)
-}
-
-// This exists only for allowing us to mock the DecodeBytes function
-// Mainly because we cannot construct a SingleResult struct from our
-// tests. All fields in that struct are private.
-var decodeBytes = func(sr *mongo.SingleResult) (bson.Raw, error) {
-       return sr.DecodeBytes()
-}
-
-// These exists only for allowing us to mock the cursor.Next function
-// Mainly because we cannot construct a mongo.Cursor struct from our
-// tests. All fields in that struct are private and there is no public
-// constructor method.
-var cursorNext = func(ctx context.Context, cursor *mongo.Cursor) bool {
-       return cursor.Next(ctx)
-}
-var cursorClose = func(ctx context.Context, cursor *mongo.Cursor) error {
-       return cursor.Close(ctx)
-}
-
-// NewMongoStore initializes a Mongo Database with the name provided
-// If a database with that name exists, it will be returned
-func NewMongoStore(name string, store *mongo.Database) (Store, error) {
-       if store == nil {
-               ip := "mongodb://" + config.GetConfiguration().DatabaseIP + ":27017"
-               clientOptions := options.Client()
-               clientOptions.ApplyURI(ip)
-               if len(os.Getenv("DB_EMCO_USERNAME")) > 0 && len(os.Getenv("DB_EMCO_PASSWORD")) > 0 {
-                       clientOptions.SetAuth(options.Credential{
-                               AuthMechanism: "SCRAM-SHA-256",
-                               AuthSource:    "mco",
-                               Username:      os.Getenv("DB_EMCO_USERNAME"),
-                               Password:      os.Getenv("DB_EMCO_PASSWORD")})
-               }
-               mongoClient, err := mongo.NewClient(clientOptions)
-               if err != nil {
-                       return nil, err
-               }
-
-               err = mongoClient.Connect(context.Background())
-               if err != nil {
-                       return nil, err
-               }
-               store = mongoClient.Database(name)
-       }
-
-       return &MongoStore{
-               db: store,
-       }, nil
-}
-
-// HealthCheck verifies if the database is up and running
-func (m *MongoStore) HealthCheck() error {
-
-       _, err := decodeBytes(m.db.RunCommand(context.Background(), bson.D{{"serverStatus", 1}}))
-       if err != nil {
-               return pkgerrors.Wrap(err, "Error getting server status")
-       }
-
-       return nil
-}
-
-// validateParams checks to see if any parameters are empty
-func (m *MongoStore) validateParams(args ...interface{}) bool {
-       for _, v := range args {
-               val, ok := v.(string)
-               if ok {
-                       if val == "" {
-                               return false
-                       }
-               } else {
-                       if v == nil {
-                               return false
-                       }
-               }
-       }
-
-       return true
-}
-
-// Unmarshal implements an unmarshaler for bson data that
-// is produced from the mongo database
-func (m *MongoStore) Unmarshal(inp []byte, out interface{}) error {
-       err := bson.Unmarshal(inp, out)
-       if err != nil {
-               return pkgerrors.Wrap(err, "Unmarshaling bson")
-       }
-       return nil
-}
-
-func (m *MongoStore) findFilter(key Key) (primitive.M, error) {
-
-       var bsonMap bson.M
-       st, err := json.Marshal(key)
-       if err != nil {
-               return primitive.M{}, pkgerrors.Errorf("Error Marshalling key: %s", err.Error())
-       }
-       err = json.Unmarshal([]byte(st), &bsonMap)
-       if err != nil {
-               return primitive.M{}, pkgerrors.Errorf("Error Unmarshalling key to Bson Map: %s", err.Error())
-       }
-       filter := bson.M{
-               "$and": []bson.M{bsonMap},
-       }
-       return filter, nil
-}
-
-func (m *MongoStore) findFilterWithKey(key Key) (primitive.M, error) {
-
-       var bsonMap bson.M
-       var bsonMapFinal bson.M
-       st, err := json.Marshal(key)
-       if err != nil {
-               return primitive.M{}, pkgerrors.Errorf("Error Marshalling key: %s", err.Error())
-       }
-       err = json.Unmarshal([]byte(st), &bsonMap)
-       if err != nil {
-               return primitive.M{}, pkgerrors.Errorf("Error Unmarshalling key to Bson Map: %s", err.Error())
-       }
-       bsonMapFinal = make(bson.M)
-       for k, v := range bsonMap {
-               if v == "" {
-                       if _, ok := bsonMapFinal["key"]; !ok {
-                               // add type of key to filter
-                               s, err := m.createKeyField(key)
-                               if err != nil {
-                                       return primitive.M{}, err
-                               }
-                               bsonMapFinal["key"] = s
-                       }
-               } else {
-                       bsonMapFinal[k] = v
-               }
-       }
-       filter := bson.M{
-               "$and": []bson.M{bsonMapFinal},
-       }
-       return filter, nil
-}
-
-func (m *MongoStore) updateFilter(key interface{}) (primitive.M, error) {
-
-       var n map[string]string
-       st, err := json.Marshal(key)
-       if err != nil {
-               return primitive.M{}, pkgerrors.Errorf("Error Marshalling key: %s", err.Error())
-       }
-       err = json.Unmarshal([]byte(st), &n)
-       if err != nil {
-               return primitive.M{}, pkgerrors.Errorf("Error Unmarshalling key to Bson Map: %s", err.Error())
-       }
-       p := make(bson.M, len(n))
-       for k, v := range n {
-               p[k] = v
-       }
-       filter := bson.M{
-               "$set": p,
-       }
-       return filter, nil
-}
-
-func (m *MongoStore) createKeyField(key interface{}) (string, error) {
-
-       var n map[string]string
-       st, err := json.Marshal(key)
-       if err != nil {
-               return "", pkgerrors.Errorf("Error Marshalling key: %s", err.Error())
-       }
-       err = json.Unmarshal([]byte(st), &n)
-       if err != nil {
-               return "", pkgerrors.Errorf("Error Unmarshalling key to Bson Map: %s", err.Error())
-       }
-       var keys []string
-       for k := range n {
-               keys = append(keys, k)
-       }
-       sort.Strings(keys)
-       s := "{"
-       for _, k := range keys {
-               s = s + k + ","
-       }
-       s = s + "}"
-       return s, nil
-}
-
-// Insert is used to insert/add element to a document
-func (m *MongoStore) Insert(coll string, key Key, query interface{}, tag string, data interface{}) error {
-       if data == nil || !m.validateParams(coll, key, tag) {
-               return pkgerrors.New("No Data to store")
-       }
-
-       c := getCollection(coll, m)
-       ctx := context.Background()
-
-       filter, err := m.findFilter(key)
-       if err != nil {
-               return err
-       }
-       // Create and add key tag
-       s, err := m.createKeyField(key)
-       if err != nil {
-               return err
-       }
-       _, err = decodeBytes(
-               c.FindOneAndUpdate(
-                       ctx,
-                       filter,
-                       bson.D{
-                               {"$set", bson.D{
-                                       {tag, data},
-                                       {"key", s},
-                               }},
-                       },
-                       options.FindOneAndUpdate().SetUpsert(true).SetReturnDocument(options.After)))
-
-       if err != nil {
-               return pkgerrors.Errorf("Error updating master table: %s", err.Error())
-       }
-       if query == nil {
-               return nil
-       }
-
-       // Update to add Query fields
-       update, err := m.updateFilter(query)
-       if err != nil {
-               return err
-       }
-       _, err = c.UpdateOne(
-               ctx,
-               filter,
-               update)
-
-       if err != nil {
-               return pkgerrors.Errorf("Error updating Query fields: %s", err.Error())
-       }
-       return nil
-}
-
-// Find method returns the data stored for this key and for this particular tag
-func (m *MongoStore) Find(coll string, key Key, tag string) ([][]byte, error) {
-
-       //result, err := m.findInternal(coll, key, tag, "")
-       //return result, err
-       if !m.validateParams(coll, key, tag) {
-               return nil, pkgerrors.New("Mandatory fields are missing")
-       }
-
-       c := getCollection(coll, m)
-       ctx := context.Background()
-
-       filter, err := m.findFilterWithKey(key)
-       if err != nil {
-               return nil, err
-       }
-       // Find only the field requested
-       projection := bson.D{
-               {tag, 1},
-               {"_id", 0},
-       }
-
-       cursor, err := c.Find(context.Background(), filter, options.Find().SetProjection(projection))
-       if err != nil {
-               return nil, pkgerrors.Errorf("Error finding element: %s", err.Error())
-       }
-       defer cursorClose(ctx, cursor)
-       var data []byte
-       var result [][]byte
-       for cursorNext(ctx, cursor) {
-               d := cursor.Current
-               switch d.Lookup(tag).Type {
-               case bson.TypeString:
-                       data = []byte(d.Lookup(tag).StringValue())
-               default:
-                       r, err := d.LookupErr(tag)
-                       if err != nil {
-                               // Throw error if not found
-                               pkgerrors.New("Unable to read data ")
-                       }
-                       data = r.Value
-               }
-               result = append(result, data)
-       }
-       return result, nil
-}
-
-// RemoveAll method to removes all the documet matching key
-func (m *MongoStore) RemoveAll(coll string, key Key) error {
-       if !m.validateParams(coll, key) {
-               return pkgerrors.New("Mandatory fields are missing")
-       }
-       c := getCollection(coll, m)
-       ctx := context.Background()
-       filter, err := m.findFilterWithKey(key)
-       if err != nil {
-               return err
-       }
-       _, err = c.DeleteMany(ctx, filter)
-       if err != nil {
-               return pkgerrors.Errorf("Error Deleting from database: %s", err.Error())
-       }
-       return nil
-}
-
-// Remove method to remove the documet by key if no child references
-func (m *MongoStore) Remove(coll string, key Key) error {
-       if !m.validateParams(coll, key) {
-               return pkgerrors.New("Mandatory fields are missing")
-       }
-       c := getCollection(coll, m)
-       ctx := context.Background()
-       filter, err := m.findFilter(key)
-       if err != nil {
-               return err
-       }
-       count, err := c.CountDocuments(context.Background(), filter)
-       if err != nil {
-               return pkgerrors.Errorf("Error finding: %s", err.Error())
-       }
-       if count == 0 {
-               return pkgerrors.Errorf("key not found")
-       }
-       if count > 1 {
-               return pkgerrors.Errorf("Can't delete parent without deleting child references first")
-       }
-       _, err = c.DeleteOne(ctx, filter)
-       if err != nil {
-               return pkgerrors.Errorf("Error Deleting from database: %s", err.Error())
-       }
-       return nil
-}
-
-// RemoveTag is used to remove an element from a document
-func (m *MongoStore) RemoveTag(coll string, key Key, tag string) error {
-       c := getCollection(coll, m)
-       ctx := context.Background()
-
-       filter, err := m.findFilter(key)
-       if err != nil {
-               return err
-       }
-
-       _, err = decodeBytes(
-               c.FindOneAndUpdate(
-                       ctx,
-                       filter,
-                       bson.D{
-                               {"$unset", bson.D{
-                                       {tag, ""},
-                               }},
-                       },
-                       options.FindOneAndUpdate().SetUpsert(true).SetReturnDocument(options.After)))
-
-       if err != nil {
-               return pkgerrors.Errorf("Error removing tag: %s", err.Error())
-       }
-
-       return nil
-}
diff --git a/central-controller/src/vendor/github.com/open-ness/EMCO/src/orchestrator/pkg/infra/rpc/rpc.go b/central-controller/src/vendor/github.com/open-ness/EMCO/src/orchestrator/pkg/infra/rpc/rpc.go
deleted file mode 100644 (file)
index 7824e43..0000000
+++ /dev/null
@@ -1,225 +0,0 @@
-// SPDX-License-Identifier: Apache-2.0
-// Copyright (c) 2020 Intel Corporation
-
-package rpc
-
-import (
-       "context"
-       "fmt"
-       "strconv"
-       "strings"
-       "sync"
-       "time"
-
-       "github.com/open-ness/EMCO/src/orchestrator/pkg/infra/config"
-       log "github.com/open-ness/EMCO/src/orchestrator/pkg/infra/logutils"
-       pkgerrors "github.com/pkg/errors"
-       "google.golang.org/grpc"
-       "google.golang.org/grpc/connectivity"
-       "google.golang.org/grpc/credentials"
-       "google.golang.org/grpc/testdata"
-)
-
-type ContextUpdateRequest interface {
-}
-
-type ContextUpdateResponse interface {
-}
-
-type InstallAppRequest interface {
-}
-
-type InstallAppResponse interface {
-}
-
-type rpcInfo struct {
-       conn *grpc.ClientConn
-       host string
-       port int
-}
-
-var mutex = &sync.Mutex{}
-var rpcConnections = make(map[string]rpcInfo)
-
-// GetRpcConn is used by RPC client code which needs the connection for a
-// given controller for doing RPC calls with that controller.
-func GetRpcConn(name string) *grpc.ClientConn {
-       mutex.Lock()
-       defer mutex.Unlock()
-       if val, ok := rpcConnections[name]; ok {
-               log.Info("GetRpcConn .. RPC intermediate-connection info", log.Fields{"name": name, "conn": val.conn, "host": val.host, "port": val.port, "conn-state": val.conn.GetState().String()})
-
-               if val.conn.GetState() == connectivity.TransientFailure {
-                       val.conn.ResetConnectBackoff()
-                       ctx, cancel := context.WithTimeout(context.Background(), 10*time.Millisecond)
-                       defer cancel()
-                       if !val.conn.WaitForStateChange(ctx, connectivity.TransientFailure) {
-                               log.Warn("Error re-establishing RPC connection", log.Fields{
-                                       "Server":    name,
-                                       "Host":      val.host,
-                                       "Port":      val.port,
-                                       "ConnState": val.conn.GetState().String(),
-                               })
-                               return nil
-                       }
-               }
-
-               if val.conn.GetState() == connectivity.Connecting {
-                       ctx, cancel := context.WithTimeout(context.Background(), 2000*time.Millisecond)
-                       defer cancel()
-                       if !val.conn.WaitForStateChange(ctx, connectivity.Connecting) {
-                               log.Warn("GetRpcConn .. Error establishing RPC connection .. ClientConn is still in CONNECTING", log.Fields{
-                                       "Server":    name,
-                                       "Host":      val.host,
-                                       "Port":      val.port,
-                                       "ConnState": val.conn.GetState().String(),
-                               })
-                               return nil
-                       }
-               }
-
-               if val.conn.GetState() == connectivity.TransientFailure {
-                       ctx, cancel := context.WithTimeout(context.Background(), 10*time.Millisecond)
-                       defer cancel()
-                       if !val.conn.WaitForStateChange(ctx, connectivity.TransientFailure) {
-                               log.Warn("Error establishing RPC connection", log.Fields{
-                                       "Server":    name,
-                                       "Host":      val.host,
-                                       "Port":      val.port,
-                                       "ConnState": val.conn.GetState().String(),
-                               })
-                               return nil
-                       }
-               }
-
-               log.Warn("GetRpcConn .. RPC final-connection info", log.Fields{"name": name, "conn": val.conn, "host": val.host, "port": val.port, "conn-state": val.conn.GetState().String()})
-               return val.conn
-       }
-       return nil
-}
-
-// UpdateRpcConn ... Update RPC connections
-func UpdateRpcConn(name, host string, port int) {
-       mutex.Lock()
-       defer mutex.Unlock()
-       if val, ok := rpcConnections[name]; ok {
-               // close connection if mismatch in update vs cached connect info
-               if val.host != host || val.port != port {
-                       log.Info("Closing RPC connection due to mismatch", log.Fields{
-                               "Server":   name,
-                               "Old Host": val.host,
-                               "Old Port": val.port,
-                               "New Host": host,
-                               "New Port": port,
-                       })
-                       err := val.conn.Close()
-                       if err != nil {
-                               log.Error("Error closing RPC connection", log.Fields{
-                                       "Server": name,
-                                       "Host":   val.host,
-                                       "Port":   val.port,
-                                       "Error":  err,
-                               })
-                       }
-               } else {
-                       if val.conn.GetState() == connectivity.TransientFailure {
-                               val.conn.ResetConnectBackoff()
-                       }
-                       return
-               }
-       }
-       // connect and update rpcConnection list - for new or modified connection
-       conn, err := createClientConn(host, port)
-       if err != nil {
-               log.Error("Failed to create RPC Client connection", log.Fields{
-                       "Error": err,
-               })
-               delete(rpcConnections, name)
-       } else {
-               rpcConnections[name] = rpcInfo{
-                       conn: conn,
-                       host: host,
-                       port: port,
-               }
-               log.Info("Added RPC Client connection", log.Fields{"Controller": name, "conn": conn, "rpcConnection": fmt.Sprintf("%v", rpcConnections[name])})
-       }
-       log.Info("UpdateRpcConn .. end", log.Fields{"conn": conn, "name": name, "host": host, "port": port})
-}
-
-// CloseAllRpcConn closes all connections
-func CloseAllRpcConn() {
-       mutex.Lock()
-       log.Info("CloseAllRpcConn..", nil)
-       for k, v := range rpcConnections {
-               err := v.conn.Close()
-               if err != nil {
-                       log.Warn("Error closing RPC connection", log.Fields{
-                               "Server": k,
-                               "Host":   v.host,
-                               "Port":   v.port,
-                               "Error":  err,
-                       })
-               }
-       }
-       mutex.Unlock()
-}
-
-// RemoveRpcConn closes the connection and removes from map
-func RemoveRpcConn(name string) {
-       mutex.Lock()
-       if val, ok := rpcConnections[name]; ok {
-               err := val.conn.Close()
-               if err != nil {
-                       log.Warn("Error closing RPC connection", log.Fields{
-                               "Server": name,
-                               "Host":   val.host,
-                               "Port":   val.port,
-                               "Error":  err,
-                       })
-               }
-               delete(rpcConnections, name)
-       }
-       mutex.Unlock()
-}
-
-// createConn creates the Rpc Client Connection
-func createClientConn(Host string, Port int) (*grpc.ClientConn, error) {
-       var err error
-       var tls bool
-       var opts []grpc.DialOption
-
-       serverAddr := Host + ":" + strconv.Itoa(Port)
-       serverNameOverride := config.GetConfiguration().GrpcServerNameOverride
-
-       if strings.Contains(config.GetConfiguration().GrpcEnableTLS, "enable") {
-               tls = true
-       } else {
-               tls = false
-       }
-
-       caFile := config.GetConfiguration().GrpcCAFile
-
-       if tls {
-               if caFile == "" {
-                       caFile = testdata.Path("ca.pem")
-               }
-               creds, err := credentials.NewClientTLSFromFile(caFile, serverNameOverride)
-               if err != nil {
-                       log.Error("Failed to create TLS credentials", log.Fields{
-                               "Error": err,
-                               "Host":  Host,
-                               "Port":  Port,
-                       })
-               }
-               opts = append(opts, grpc.WithTransportCredentials(creds))
-       } else {
-               opts = append(opts, grpc.WithInsecure())
-       }
-
-       conn, err := grpc.Dial(serverAddr, opts...)
-       if err != nil {
-               pkgerrors.Wrap(err, "Grpc Client Initialization failed with error")
-       }
-
-       return conn, err
-}
diff --git a/central-controller/src/vendor/gitlab.com/project-emco/core/emco-base/src/go.mod b/central-controller/src/vendor/gitlab.com/project-emco/core/emco-base/src/go.mod
new file mode 100644 (file)
index 0000000..8720475
--- /dev/null
@@ -0,0 +1,11 @@
+module gitlab.com/project-emco/core/emco-base/src/orchestrator
+
+require (
+        gitlab.com/project-emco/core/emco-base/src/rsync v0.0.0-00010101000000-000000000000
+)
+
+replace (
+        gitlab.com/project-emco/core/emco-base/src/rsync => ../../../../../../rsync
+)
+
+go 1.17
diff --git a/central-controller/src/vendor/gitlab.com/project-emco/core/emco-base/src/orchestrator/go.mod b/central-controller/src/vendor/gitlab.com/project-emco/core/emco-base/src/orchestrator/go.mod
new file mode 100644 (file)
index 0000000..229821a
--- /dev/null
@@ -0,0 +1,11 @@
+module gitlab.com/project-emco/core/emco-base/src/orchestrator
+
+require (
+        gitlab.com/project-emco/core/emco-base/src/rsync v0.0.0-00010101000000-000000000000
+)
+
+replace (
+        gitlab.com/project-emco/core/emco-base/src/rsync => ../../../../../../../rsync
+)
+
+go 1.17
@@ -7,14 +7,27 @@ import (
        "fmt"
        "strings"
 
-       log "github.com/open-ness/EMCO/src/orchestrator/pkg/infra/logutils"
-       "github.com/open-ness/EMCO/src/orchestrator/pkg/rtcontext"
        pkgerrors "github.com/pkg/errors"
+       log "gitlab.com/project-emco/core/emco-base/src/orchestrator/pkg/infra/logutils"
+       "gitlab.com/project-emco/core/emco-base/src/orchestrator/pkg/rtcontext"
 )
 
 // metaPrefix used for denoting clusterMeta level
 const metaGrpPREFIX = "!@#metaGrp"
 
+// Separator is a constant used to create concatenated names for items like cluster or resource names
+const Separator = "+"
+
+// OrderInstruction type constants
+const OrderInstruction = "order"
+
+// DependencyInstruction type constants
+const DependencyInstruction = "dependency"
+
+// Level constant names
+const ResourceLevel = "resource"
+const AppLevel = "app"
+
 type AppContext struct {
        initDone bool
        rtcObj   rtcontext.RunTimeContext
@@ -39,6 +52,10 @@ type statuses struct {
        Terminated        StatusValue
        InstantiateFailed StatusValue
        TerminateFailed   StatusValue
+       Created           StatusValue
+       Updating          StatusValue
+       Updated           StatusValue
+       UpdateFailed      StatusValue
 }
 
 var AppContextStatusEnum = &statuses{
@@ -48,11 +65,27 @@ var AppContextStatusEnum = &statuses{
        Terminated:        "Terminated",
        InstantiateFailed: "InstantiateFailed",
        TerminateFailed:   "TerminateFailed",
+       Created:           "Created",
+       Updating:          "Updating",
+       Updated:           "Updated",
+       UpdateFailed:      "UpdatedFailed",
+}
+
+type clusterStatuses struct {
+       Unknown   StatusValue
+       Available StatusValue
+       Retrying  StatusValue
+}
+
+var ClusterReadyStatusEnum = &clusterStatuses{
+       Unknown:   "Unknown",
+       Available: "Available",
+       Retrying:  "Retrying",
 }
 
-// CompositeAppMeta consists of projectName, CompositeAppName,
-// CompositeAppVersion, ReleaseName. This shall be used for
-// instantiation of a compositeApp
+// CompositeAppMeta contains all the possible attributes an
+// appcontext /meta handle of a Composite App or Logical Cloud, may have.
+// Note: only some of these fields will be used in each for each of the types above:
 type CompositeAppMeta struct {
        Project               string   `json:"Project"`
        CompositeApp          string   `json:"CompositeApp"`
@@ -62,6 +95,7 @@ type CompositeAppMeta struct {
        Namespace             string   `json:"Namespace"`
        Level                 string   `json:"Level"`
        ChildContextIDs       []string `json:"ChildContextIDs"`
+       LogicalCloud          string   `json:"LogicalCloud"`
 }
 
 // Init app context
@@ -447,7 +481,7 @@ func (ac *AppContext) GetResourceNames(appname string, clustername string) ([]st
 
 //Add instruction under given handle and type
 func (ac *AppContext) AddInstruction(handle interface{}, level string, insttype string, value interface{}) (interface{}, error) {
-       if !(insttype == "order" || insttype == "dependency") {
+       if !(insttype == OrderInstruction || insttype == DependencyInstruction) {
                log.Error("Not a valid app context instruction type", log.Fields{})
                return nil, pkgerrors.Errorf("Not a valid app context instruction type")
        }
@@ -464,6 +498,28 @@ func (ac *AppContext) AddInstruction(handle interface{}, level string, insttype
        return h, nil
 }
 
+//Returns the resource instruction for a given instruction type per app
+func (ac *AppContext) GetAppLevelInstruction(appname, insttype string) (interface{}, error) {
+       if !(insttype == DependencyInstruction) {
+               log.Error("Not a valid app context instruction type", log.Fields{})
+               return nil, pkgerrors.Errorf("Not a valid app context instruction type")
+       }
+
+       rh, err := ac.rtc.RtcGet()
+       if err != nil {
+               log.Error("ac.rtc.RtcGet()", log.Fields{"err": err})
+               return nil, err
+       }
+       s := fmt.Sprintf("%v", rh) + "app/" + appname + "/instruction/" + insttype + "/"
+       log.Info("Getting app instruction", log.Fields{"s": s})
+       var v string
+       err = ac.rtc.RtcGetValue(s, &v)
+       if err != nil {
+               return nil, err
+       }
+       return v, nil
+}
+
 //Delete instruction under given handle
 func (ac *AppContext) DeleteInstruction(handle interface{}) error {
        err := ac.rtc.RtcDeletePair(handle)
@@ -475,7 +531,7 @@ func (ac *AppContext) DeleteInstruction(handle interface{}) error {
 
 //Returns the app instruction for a given instruction type
 func (ac *AppContext) GetAppInstruction(insttype string) (interface{}, error) {
-       if !(insttype == "order" || insttype == "dependency") {
+       if !(insttype == OrderInstruction || insttype == DependencyInstruction) {
                log.Error("Not a valid app context instruction type", log.Fields{})
                return nil, pkgerrors.Errorf("Not a valid app context instruction type")
        }
@@ -502,7 +558,7 @@ func (ac *AppContext) UpdateInstructionValue(handle interface{}, value interface
 
 //Returns the resource instruction for a given instruction type
 func (ac *AppContext) GetResourceInstruction(appname string, clustername string, insttype string) (interface{}, error) {
-       if !(insttype == "order" || insttype == "dependency") {
+       if !(insttype == OrderInstruction || insttype == DependencyInstruction) {
                log.Error("Not a valid app context instruction type", log.Fields{})
                return nil, pkgerrors.Errorf("Not a valid app context instruction type")
        }
@@ -515,7 +571,6 @@ func (ac *AppContext) GetResourceInstruction(appname string, clustername string,
        var v string
        err = ac.rtc.RtcGetValue(s, &v)
        if err != nil {
-               log.Error("ac.rtc.RtcGetValue(s, &v)", log.Fields{"err": err})
                return nil, err
        }
        return v, nil
@@ -617,6 +672,7 @@ func (ac *AppContext) GetCompositeAppMeta() (CompositeAppMeta, error) {
                        childCtxs = append(childCtxs, v.(string))
                }
        }
+       lc := fmt.Sprintf("%v", datamap["LogicalCloud"])
 
-       return CompositeAppMeta{Project: p, CompositeApp: ca, Version: v, Release: rn, DeploymentIntentGroup: dig, Namespace: namespace, Level: level, ChildContextIDs: childCtxs}, nil
+       return CompositeAppMeta{Project: p, CompositeApp: ca, Version: v, Release: rn, DeploymentIntentGroup: dig, Namespace: namespace, Level: level, ChildContextIDs: childCtxs, LogicalCloud: lc}, nil
 }
diff --git a/central-controller/src/vendor/gitlab.com/project-emco/core/emco-base/src/orchestrator/pkg/appcontext/subresources/approval.go b/central-controller/src/vendor/gitlab.com/project-emco/core/emco-base/src/orchestrator/pkg/appcontext/subresources/approval.go
new file mode 100644 (file)
index 0000000..8e6c913
--- /dev/null
@@ -0,0 +1,17 @@
+// SPDX-License-Identifier: Apache-2.0
+// Copyright (c) 2020-22 Intel Corporation
+
+package subresources
+
+import k8scorev1 "k8s.io/api/core/v1"
+
+// The ApprovalSubresource type defines the 4 necessary parameters
+// that the "approval" subresource of a CertificateSigningRequest in K8s
+// requires, in a forma tto be exchanged over AppContext
+type ApprovalSubresource struct {
+       LastUpdateTime string                    `json:"lastUpdateTime,omitempty"`
+       Message        string                    `json:"message,omitempty"`
+       Reason         string                    `json:"reason,omitempty"`
+       Type           string                    `json:"type,omitempty"`
+       Status         k8scorev1.ConditionStatus `json:"status" protobuf:"bytes,6,opt,name=status,casttype=k8s.io/api/core/v1.ConditionStatus"`
+}
@@ -7,9 +7,10 @@ import (
        "context"
        "time"
 
-       contextpb "github.com/open-ness/EMCO/src/orchestrator/pkg/grpc/contextupdate"
-       log "github.com/open-ness/EMCO/src/orchestrator/pkg/infra/logutils"
-       "github.com/open-ness/EMCO/src/orchestrator/pkg/infra/rpc"
+       contextpb "gitlab.com/project-emco/core/emco-base/src/orchestrator/pkg/grpc/contextupdate"
+       log "gitlab.com/project-emco/core/emco-base/src/orchestrator/pkg/infra/logutils"
+       "gitlab.com/project-emco/core/emco-base/src/orchestrator/pkg/infra/rpc"
+       "gitlab.com/project-emco/core/emco-base/src/orchestrator/pkg/infra/config"
        pkgerrors "github.com/pkg/errors"
 )
 
@@ -20,7 +21,9 @@ func InvokeContextUpdate(controllerName, intentName, appContextId string) error
        var err error
        var rpcClient contextpb.ContextupdateClient
        var updateRes *contextpb.ContextUpdateResponse
-       ctx, cancel := context.WithTimeout(context.Background(), 600*time.Second)
+
+       timeout := time.Duration(config.GetConfiguration().GrpcCallTimeout)
+       ctx, cancel := context.WithTimeout(context.Background(), timeout*time.Millisecond)
        defer cancel()
 
        conn := rpc.GetRpcConn(controllerName)
@@ -8,9 +8,9 @@ import (
        "sync"
        "time"
 
-       log "github.com/open-ness/EMCO/src/orchestrator/pkg/infra/logutils"
-       "github.com/open-ness/EMCO/src/orchestrator/pkg/infra/rpc"
-       installpb "github.com/open-ness/EMCO/src/rsync/pkg/grpc/installapp"
+       log "gitlab.com/project-emco/core/emco-base/src/orchestrator/pkg/infra/logutils"
+       "gitlab.com/project-emco/core/emco-base/src/orchestrator/pkg/infra/rpc"
+       installpb "gitlab.com/project-emco/core/emco-base/src/rsync/pkg/grpc/installapp"
        pkgerrors "github.com/pkg/errors"
 )
 
@@ -36,7 +36,7 @@ type _testvars struct {
 var Testvars _testvars
 
 // InitRsyncClient initializes connctions to the Resource Synchronizer service
-func initRsyncClient() bool {
+func InitRsyncClient() bool {
        if (RsyncInfo{}) == rsyncInfo {
                mutex.Lock()
                defer mutex.Unlock()
@@ -88,7 +88,7 @@ func InvokeInstallApp(appContextId string) error {
 
        conn := rpc.GetRpcConn(rsyncName)
        if conn == nil {
-               initRsyncClient()
+               InitRsyncClient()
                conn = rpc.GetRpcConn(rsyncName)
        }
 
@@ -130,7 +130,7 @@ func InvokeUninstallApp(appContextId string) error {
 
        conn := rpc.GetRpcConn(rsyncName)
        if conn == nil {
-               initRsyncClient()
+               InitRsyncClient()
                conn = rpc.GetRpcConn(rsyncName)
        }
 
diff --git a/central-controller/src/vendor/gitlab.com/project-emco/core/emco-base/src/orchestrator/pkg/grpc/register.go b/central-controller/src/vendor/gitlab.com/project-emco/core/emco-base/src/orchestrator/pkg/grpc/register.go
new file mode 100644 (file)
index 0000000..3f3c94a
--- /dev/null
@@ -0,0 +1,70 @@
+// SPDX-License-Identifier: Apache-2.0
+// Copyright (c) 2021 Intel Corporation
+
+package grpc
+
+import (
+       "fmt"
+       "net"
+       "os"
+       "strconv"
+       "strings"
+
+       updatepb "gitlab.com/project-emco/core/emco-base/src/orchestrator/pkg/grpc/contextupdate"
+       "gitlab.com/project-emco/core/emco-base/src/orchestrator/pkg/grpc/statusnotify"
+       statusnotifypb "gitlab.com/project-emco/core/emco-base/src/orchestrator/pkg/grpc/statusnotify"
+       log "gitlab.com/project-emco/core/emco-base/src/orchestrator/pkg/infra/logutils"
+       "google.golang.org/grpc"
+)
+
+func RegisterStatusNotifyService(grpcServer *grpc.Server, srv interface{}) {
+       statusnotifypb.RegisterStatusNotifyServer(grpcServer, srv.(statusnotify.StatusNotifyServer))
+}
+
+func RegisterContextUpdateService(grpcServer *grpc.Server, srv interface{}) {
+       updatepb.RegisterContextupdateServer(grpcServer, srv.(updatepb.ContextupdateServer))
+}
+
+func StartGrpcServer(defaultName, envName string, defaultPort int, registerFn func(*grpc.Server, interface{}), srv interface{}) error {
+       port := getGrpcServerPort(defaultName, envName, defaultPort)
+
+       log.Info("Starting gRPC on port", log.Fields{"Port": port})
+       lis, err := net.Listen("tcp", fmt.Sprintf(":%d", port))
+       if err != nil {
+               log.Error("Could not listen to gRPC port", log.Fields{"Error": err})
+               return err
+       }
+
+       grpcServer := grpc.NewServer()
+       registerFn(grpcServer, srv)
+
+       err = grpcServer.Serve(lis)
+       if err != nil {
+               log.Error("gRPC server is not serving", log.Fields{"Error": err})
+               return err
+       }
+       return err
+}
+
+func getGrpcServerPort(defaultName, envName string, defaultPort int) int {
+
+       // expect name of this program to be in env the variable "{envName}_NAME" - e.g. ORCHESTRATOR_NAME="orchestrator"
+       serviceName := os.Getenv(envName)
+       if serviceName == "" {
+               serviceName = defaultName
+               log.Info("Using default name for service", log.Fields{
+                       "Name": serviceName,
+               })
+       }
+
+       // expect service port to be in env variable - e.g. ORCHESTRATOR_SERVICE_PORT
+       port, err := strconv.Atoi(os.Getenv(strings.ToUpper(serviceName) + "_SERVICE_PORT"))
+       if err != nil || port < 0 {
+               port = defaultPort
+               log.Info("Using default port for gRPC controller", log.Fields{
+                       "Name": serviceName,
+                       "Port": port,
+               })
+       }
+       return port
+}
diff --git a/central-controller/src/vendor/gitlab.com/project-emco/core/emco-base/src/orchestrator/pkg/grpc/statusnotify/statusnotify.pb.go b/central-controller/src/vendor/gitlab.com/project-emco/core/emco-base/src/orchestrator/pkg/grpc/statusnotify/statusnotify.pb.go
new file mode 100644 (file)
index 0000000..3694d4f
--- /dev/null
@@ -0,0 +1,1431 @@
+// SPDX-License-Identifier: Apache-2.0
+// Copyright (c) 2020 Intel Corporation
+
+// Code generated by protoc-gen-go. DO NOT EDIT.
+// versions:
+//     protoc-gen-go v1.27.1-devel
+//     protoc        v3.19.1
+// source: statusnotify.proto
+
+package statusnotify
+
+import (
+       context "context"
+       grpc "google.golang.org/grpc"
+       codes "google.golang.org/grpc/codes"
+       status "google.golang.org/grpc/status"
+       protoreflect "google.golang.org/protobuf/reflect/protoreflect"
+       protoimpl "google.golang.org/protobuf/runtime/protoimpl"
+       reflect "reflect"
+       sync "sync"
+)
+
+const (
+       // Verify that this generated code is sufficiently up-to-date.
+       _ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)
+       // Verify that runtime/protoimpl is sufficiently up-to-date.
+       _ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
+)
+
+type OutputType int32
+
+const (
+       OutputType_SUMMARY OutputType = 0
+       OutputType_ALL     OutputType = 1
+)
+
+// Enum value maps for OutputType.
+var (
+       OutputType_name = map[int32]string{
+               0: "SUMMARY",
+               1: "ALL",
+       }
+       OutputType_value = map[string]int32{
+               "SUMMARY": 0,
+               "ALL":     1,
+       }
+)
+
+func (x OutputType) Enum() *OutputType {
+       p := new(OutputType)
+       *p = x
+       return p
+}
+
+func (x OutputType) String() string {
+       return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x))
+}
+
+func (OutputType) Descriptor() protoreflect.EnumDescriptor {
+       return file_statusnotify_proto_enumTypes[0].Descriptor()
+}
+
+func (OutputType) Type() protoreflect.EnumType {
+       return &file_statusnotify_proto_enumTypes[0]
+}
+
+func (x OutputType) Number() protoreflect.EnumNumber {
+       return protoreflect.EnumNumber(x)
+}
+
+// Deprecated: Use OutputType.Descriptor instead.
+func (OutputType) EnumDescriptor() ([]byte, []int) {
+       return file_statusnotify_proto_rawDescGZIP(), []int{0}
+}
+
+type StatusValue int32
+
+const (
+       StatusValue_STATUS_ERROR StatusValue = 0
+       StatusValue_NOT_READY    StatusValue = 1
+       StatusValue_READY        StatusValue = 2
+       StatusValue_NOT_DEPLOYED StatusValue = 3
+       StatusValue_DEPLOYED     StatusValue = 4
+)
+
+// Enum value maps for StatusValue.
+var (
+       StatusValue_name = map[int32]string{
+               0: "STATUS_ERROR",
+               1: "NOT_READY",
+               2: "READY",
+               3: "NOT_DEPLOYED",
+               4: "DEPLOYED",
+       }
+       StatusValue_value = map[string]int32{
+               "STATUS_ERROR": 0,
+               "NOT_READY":    1,
+               "READY":        2,
+               "NOT_DEPLOYED": 3,
+               "DEPLOYED":     4,
+       }
+)
+
+func (x StatusValue) Enum() *StatusValue {
+       p := new(StatusValue)
+       *p = x
+       return p
+}
+
+func (x StatusValue) String() string {
+       return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x))
+}
+
+func (StatusValue) Descriptor() protoreflect.EnumDescriptor {
+       return file_statusnotify_proto_enumTypes[1].Descriptor()
+}
+
+func (StatusValue) Type() protoreflect.EnumType {
+       return &file_statusnotify_proto_enumTypes[1]
+}
+
+func (x StatusValue) Number() protoreflect.EnumNumber {
+       return protoreflect.EnumNumber(x)
+}
+
+// Deprecated: Use StatusValue.Descriptor instead.
+func (StatusValue) EnumDescriptor() ([]byte, []int) {
+       return file_statusnotify_proto_rawDescGZIP(), []int{1}
+}
+
+type DigKey struct {
+       state         protoimpl.MessageState
+       sizeCache     protoimpl.SizeCache
+       unknownFields protoimpl.UnknownFields
+
+       Project               string `protobuf:"bytes,1,opt,name=project,proto3" json:"project,omitempty"`
+       CompositeApp          string `protobuf:"bytes,2,opt,name=compositeApp,proto3" json:"compositeApp,omitempty"`
+       CompositeAppVersion   string `protobuf:"bytes,3,opt,name=compositeAppVersion,proto3" json:"compositeAppVersion,omitempty"`
+       DeploymentIntentGroup string `protobuf:"bytes,4,opt,name=deploymentIntentGroup,proto3" json:"deploymentIntentGroup,omitempty"`
+}
+
+func (x *DigKey) Reset() {
+       *x = DigKey{}
+       if protoimpl.UnsafeEnabled {
+               mi := &file_statusnotify_proto_msgTypes[0]
+               ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+               ms.StoreMessageInfo(mi)
+       }
+}
+
+func (x *DigKey) String() string {
+       return protoimpl.X.MessageStringOf(x)
+}
+
+func (*DigKey) ProtoMessage() {}
+
+func (x *DigKey) ProtoReflect() protoreflect.Message {
+       mi := &file_statusnotify_proto_msgTypes[0]
+       if protoimpl.UnsafeEnabled && x != nil {
+               ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+               if ms.LoadMessageInfo() == nil {
+                       ms.StoreMessageInfo(mi)
+               }
+               return ms
+       }
+       return mi.MessageOf(x)
+}
+
+// Deprecated: Use DigKey.ProtoReflect.Descriptor instead.
+func (*DigKey) Descriptor() ([]byte, []int) {
+       return file_statusnotify_proto_rawDescGZIP(), []int{0}
+}
+
+func (x *DigKey) GetProject() string {
+       if x != nil {
+               return x.Project
+       }
+       return ""
+}
+
+func (x *DigKey) GetCompositeApp() string {
+       if x != nil {
+               return x.CompositeApp
+       }
+       return ""
+}
+
+func (x *DigKey) GetCompositeAppVersion() string {
+       if x != nil {
+               return x.CompositeAppVersion
+       }
+       return ""
+}
+
+func (x *DigKey) GetDeploymentIntentGroup() string {
+       if x != nil {
+               return x.DeploymentIntentGroup
+       }
+       return ""
+}
+
+type LcKey struct {
+       state         protoimpl.MessageState
+       sizeCache     protoimpl.SizeCache
+       unknownFields protoimpl.UnknownFields
+
+       Project      string `protobuf:"bytes,1,opt,name=project,proto3" json:"project,omitempty"`
+       LogicalCloud string `protobuf:"bytes,2,opt,name=logicalCloud,proto3" json:"logicalCloud,omitempty"`
+}
+
+func (x *LcKey) Reset() {
+       *x = LcKey{}
+       if protoimpl.UnsafeEnabled {
+               mi := &file_statusnotify_proto_msgTypes[1]
+               ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+               ms.StoreMessageInfo(mi)
+       }
+}
+
+func (x *LcKey) String() string {
+       return protoimpl.X.MessageStringOf(x)
+}
+
+func (*LcKey) ProtoMessage() {}
+
+func (x *LcKey) ProtoReflect() protoreflect.Message {
+       mi := &file_statusnotify_proto_msgTypes[1]
+       if protoimpl.UnsafeEnabled && x != nil {
+               ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+               if ms.LoadMessageInfo() == nil {
+                       ms.StoreMessageInfo(mi)
+               }
+               return ms
+       }
+       return mi.MessageOf(x)
+}
+
+// Deprecated: Use LcKey.ProtoReflect.Descriptor instead.
+func (*LcKey) Descriptor() ([]byte, []int) {
+       return file_statusnotify_proto_rawDescGZIP(), []int{1}
+}
+
+func (x *LcKey) GetProject() string {
+       if x != nil {
+               return x.Project
+       }
+       return ""
+}
+
+func (x *LcKey) GetLogicalCloud() string {
+       if x != nil {
+               return x.LogicalCloud
+       }
+       return ""
+}
+
+type ClusterKey struct {
+       state         protoimpl.MessageState
+       sizeCache     protoimpl.SizeCache
+       unknownFields protoimpl.UnknownFields
+
+       ClusterProvider string `protobuf:"bytes,1,opt,name=clusterProvider,proto3" json:"clusterProvider,omitempty"`
+       Cluster         string `protobuf:"bytes,2,opt,name=cluster,proto3" json:"cluster,omitempty"`
+}
+
+func (x *ClusterKey) Reset() {
+       *x = ClusterKey{}
+       if protoimpl.UnsafeEnabled {
+               mi := &file_statusnotify_proto_msgTypes[2]
+               ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+               ms.StoreMessageInfo(mi)
+       }
+}
+
+func (x *ClusterKey) String() string {
+       return protoimpl.X.MessageStringOf(x)
+}
+
+func (*ClusterKey) ProtoMessage() {}
+
+func (x *ClusterKey) ProtoReflect() protoreflect.Message {
+       mi := &file_statusnotify_proto_msgTypes[2]
+       if protoimpl.UnsafeEnabled && x != nil {
+               ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+               if ms.LoadMessageInfo() == nil {
+                       ms.StoreMessageInfo(mi)
+               }
+               return ms
+       }
+       return mi.MessageOf(x)
+}
+
+// Deprecated: Use ClusterKey.ProtoReflect.Descriptor instead.
+func (*ClusterKey) Descriptor() ([]byte, []int) {
+       return file_statusnotify_proto_rawDescGZIP(), []int{2}
+}
+
+func (x *ClusterKey) GetClusterProvider() string {
+       if x != nil {
+               return x.ClusterProvider
+       }
+       return ""
+}
+
+func (x *ClusterKey) GetCluster() string {
+       if x != nil {
+               return x.Cluster
+       }
+       return ""
+}
+
+type StatusRegistration struct {
+       state         protoimpl.MessageState
+       sizeCache     protoimpl.SizeCache
+       unknownFields protoimpl.UnknownFields
+
+       ClientId string `protobuf:"bytes,1,opt,name=clientId,proto3" json:"clientId,omitempty"`
+       // Types that are assignable to Key:
+       //      *StatusRegistration_DigKey
+       //      *StatusRegistration_LcKey
+       //      *StatusRegistration_ClusterKey
+       Key        isStatusRegistration_Key `protobuf_oneof:"key"`
+       StatusType StatusValue              `protobuf:"varint,5,opt,name=statusType,proto3,enum=StatusValue" json:"statusType,omitempty"`
+       Apps       []string                 `protobuf:"bytes,6,rep,name=apps,proto3" json:"apps,omitempty"`
+       Clusters   []string                 `protobuf:"bytes,7,rep,name=clusters,proto3" json:"clusters,omitempty"`
+       Resources  []string                 `protobuf:"bytes,8,rep,name=resources,proto3" json:"resources,omitempty"`
+       Output     OutputType               `protobuf:"varint,9,opt,name=output,proto3,enum=OutputType" json:"output,omitempty"`
+}
+
+func (x *StatusRegistration) Reset() {
+       *x = StatusRegistration{}
+       if protoimpl.UnsafeEnabled {
+               mi := &file_statusnotify_proto_msgTypes[3]
+               ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+               ms.StoreMessageInfo(mi)
+       }
+}
+
+func (x *StatusRegistration) String() string {
+       return protoimpl.X.MessageStringOf(x)
+}
+
+func (*StatusRegistration) ProtoMessage() {}
+
+func (x *StatusRegistration) ProtoReflect() protoreflect.Message {
+       mi := &file_statusnotify_proto_msgTypes[3]
+       if protoimpl.UnsafeEnabled && x != nil {
+               ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+               if ms.LoadMessageInfo() == nil {
+                       ms.StoreMessageInfo(mi)
+               }
+               return ms
+       }
+       return mi.MessageOf(x)
+}
+
+// Deprecated: Use StatusRegistration.ProtoReflect.Descriptor instead.
+func (*StatusRegistration) Descriptor() ([]byte, []int) {
+       return file_statusnotify_proto_rawDescGZIP(), []int{3}
+}
+
+func (x *StatusRegistration) GetClientId() string {
+       if x != nil {
+               return x.ClientId
+       }
+       return ""
+}
+
+func (m *StatusRegistration) GetKey() isStatusRegistration_Key {
+       if m != nil {
+               return m.Key
+       }
+       return nil
+}
+
+func (x *StatusRegistration) GetDigKey() *DigKey {
+       if x, ok := x.GetKey().(*StatusRegistration_DigKey); ok {
+               return x.DigKey
+       }
+       return nil
+}
+
+func (x *StatusRegistration) GetLcKey() *LcKey {
+       if x, ok := x.GetKey().(*StatusRegistration_LcKey); ok {
+               return x.LcKey
+       }
+       return nil
+}
+
+func (x *StatusRegistration) GetClusterKey() *ClusterKey {
+       if x, ok := x.GetKey().(*StatusRegistration_ClusterKey); ok {
+               return x.ClusterKey
+       }
+       return nil
+}
+
+func (x *StatusRegistration) GetStatusType() StatusValue {
+       if x != nil {
+               return x.StatusType
+       }
+       return StatusValue_STATUS_ERROR
+}
+
+func (x *StatusRegistration) GetApps() []string {
+       if x != nil {
+               return x.Apps
+       }
+       return nil
+}
+
+func (x *StatusRegistration) GetClusters() []string {
+       if x != nil {
+               return x.Clusters
+       }
+       return nil
+}
+
+func (x *StatusRegistration) GetResources() []string {
+       if x != nil {
+               return x.Resources
+       }
+       return nil
+}
+
+func (x *StatusRegistration) GetOutput() OutputType {
+       if x != nil {
+               return x.Output
+       }
+       return OutputType_SUMMARY
+}
+
+type isStatusRegistration_Key interface {
+       isStatusRegistration_Key()
+}
+
+type StatusRegistration_DigKey struct {
+       DigKey *DigKey `protobuf:"bytes,2,opt,name=digKey,proto3,oneof"`
+}
+
+type StatusRegistration_LcKey struct {
+       LcKey *LcKey `protobuf:"bytes,3,opt,name=lcKey,proto3,oneof"`
+}
+
+type StatusRegistration_ClusterKey struct {
+       ClusterKey *ClusterKey `protobuf:"bytes,4,opt,name=clusterKey,proto3,oneof"`
+}
+
+func (*StatusRegistration_DigKey) isStatusRegistration_Key() {}
+
+func (*StatusRegistration_LcKey) isStatusRegistration_Key() {}
+
+func (*StatusRegistration_ClusterKey) isStatusRegistration_Key() {}
+
+type GVK struct {
+       state         protoimpl.MessageState
+       sizeCache     protoimpl.SizeCache
+       unknownFields protoimpl.UnknownFields
+
+       Group   string `protobuf:"bytes,1,opt,name=group,proto3" json:"group,omitempty"`
+       Version string `protobuf:"bytes,2,opt,name=version,proto3" json:"version,omitempty"`
+       Kind    string `protobuf:"bytes,3,opt,name=kind,proto3" json:"kind,omitempty"`
+}
+
+func (x *GVK) Reset() {
+       *x = GVK{}
+       if protoimpl.UnsafeEnabled {
+               mi := &file_statusnotify_proto_msgTypes[4]
+               ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+               ms.StoreMessageInfo(mi)
+       }
+}
+
+func (x *GVK) String() string {
+       return protoimpl.X.MessageStringOf(x)
+}
+
+func (*GVK) ProtoMessage() {}
+
+func (x *GVK) ProtoReflect() protoreflect.Message {
+       mi := &file_statusnotify_proto_msgTypes[4]
+       if protoimpl.UnsafeEnabled && x != nil {
+               ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+               if ms.LoadMessageInfo() == nil {
+                       ms.StoreMessageInfo(mi)
+               }
+               return ms
+       }
+       return mi.MessageOf(x)
+}
+
+// Deprecated: Use GVK.ProtoReflect.Descriptor instead.
+func (*GVK) Descriptor() ([]byte, []int) {
+       return file_statusnotify_proto_rawDescGZIP(), []int{4}
+}
+
+func (x *GVK) GetGroup() string {
+       if x != nil {
+               return x.Group
+       }
+       return ""
+}
+
+func (x *GVK) GetVersion() string {
+       if x != nil {
+               return x.Version
+       }
+       return ""
+}
+
+func (x *GVK) GetKind() string {
+       if x != nil {
+               return x.Kind
+       }
+       return ""
+}
+
+type ResourceStatus struct {
+       state         protoimpl.MessageState
+       sizeCache     protoimpl.SizeCache
+       unknownFields protoimpl.UnknownFields
+
+       Name        string      `protobuf:"bytes,1,opt,name=name,proto3" json:"name,omitempty"`
+       Gvk         *GVK        `protobuf:"bytes,2,opt,name=gvk,proto3" json:"gvk,omitempty"`
+       StatusValue StatusValue `protobuf:"varint,3,opt,name=statusValue,proto3,enum=StatusValue" json:"statusValue,omitempty"`
+}
+
+func (x *ResourceStatus) Reset() {
+       *x = ResourceStatus{}
+       if protoimpl.UnsafeEnabled {
+               mi := &file_statusnotify_proto_msgTypes[5]
+               ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+               ms.StoreMessageInfo(mi)
+       }
+}
+
+func (x *ResourceStatus) String() string {
+       return protoimpl.X.MessageStringOf(x)
+}
+
+func (*ResourceStatus) ProtoMessage() {}
+
+func (x *ResourceStatus) ProtoReflect() protoreflect.Message {
+       mi := &file_statusnotify_proto_msgTypes[5]
+       if protoimpl.UnsafeEnabled && x != nil {
+               ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+               if ms.LoadMessageInfo() == nil {
+                       ms.StoreMessageInfo(mi)
+               }
+               return ms
+       }
+       return mi.MessageOf(x)
+}
+
+// Deprecated: Use ResourceStatus.ProtoReflect.Descriptor instead.
+func (*ResourceStatus) Descriptor() ([]byte, []int) {
+       return file_statusnotify_proto_rawDescGZIP(), []int{5}
+}
+
+func (x *ResourceStatus) GetName() string {
+       if x != nil {
+               return x.Name
+       }
+       return ""
+}
+
+func (x *ResourceStatus) GetGvk() *GVK {
+       if x != nil {
+               return x.Gvk
+       }
+       return nil
+}
+
+func (x *ResourceStatus) GetStatusValue() StatusValue {
+       if x != nil {
+               return x.StatusValue
+       }
+       return StatusValue_STATUS_ERROR
+}
+
+type ClusterStatus struct {
+       state         protoimpl.MessageState
+       sizeCache     protoimpl.SizeCache
+       unknownFields protoimpl.UnknownFields
+
+       ClusterProvider string            `protobuf:"bytes,1,opt,name=clusterProvider,proto3" json:"clusterProvider,omitempty"`
+       Cluster         string            `protobuf:"bytes,2,opt,name=cluster,proto3" json:"cluster,omitempty"`
+       StatusValue     StatusValue       `protobuf:"varint,3,opt,name=statusValue,proto3,enum=StatusValue" json:"statusValue,omitempty"`
+       Resources       []*ResourceStatus `protobuf:"bytes,4,rep,name=resources,proto3" json:"resources,omitempty"`
+}
+
+func (x *ClusterStatus) Reset() {
+       *x = ClusterStatus{}
+       if protoimpl.UnsafeEnabled {
+               mi := &file_statusnotify_proto_msgTypes[6]
+               ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+               ms.StoreMessageInfo(mi)
+       }
+}
+
+func (x *ClusterStatus) String() string {
+       return protoimpl.X.MessageStringOf(x)
+}
+
+func (*ClusterStatus) ProtoMessage() {}
+
+func (x *ClusterStatus) ProtoReflect() protoreflect.Message {
+       mi := &file_statusnotify_proto_msgTypes[6]
+       if protoimpl.UnsafeEnabled && x != nil {
+               ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+               if ms.LoadMessageInfo() == nil {
+                       ms.StoreMessageInfo(mi)
+               }
+               return ms
+       }
+       return mi.MessageOf(x)
+}
+
+// Deprecated: Use ClusterStatus.ProtoReflect.Descriptor instead.
+func (*ClusterStatus) Descriptor() ([]byte, []int) {
+       return file_statusnotify_proto_rawDescGZIP(), []int{6}
+}
+
+func (x *ClusterStatus) GetClusterProvider() string {
+       if x != nil {
+               return x.ClusterProvider
+       }
+       return ""
+}
+
+func (x *ClusterStatus) GetCluster() string {
+       if x != nil {
+               return x.Cluster
+       }
+       return ""
+}
+
+func (x *ClusterStatus) GetStatusValue() StatusValue {
+       if x != nil {
+               return x.StatusValue
+       }
+       return StatusValue_STATUS_ERROR
+}
+
+func (x *ClusterStatus) GetResources() []*ResourceStatus {
+       if x != nil {
+               return x.Resources
+       }
+       return nil
+}
+
+type AppStatus struct {
+       state         protoimpl.MessageState
+       sizeCache     protoimpl.SizeCache
+       unknownFields protoimpl.UnknownFields
+
+       App         string           `protobuf:"bytes,1,opt,name=app,proto3" json:"app,omitempty"`
+       StatusValue StatusValue      `protobuf:"varint,2,opt,name=statusValue,proto3,enum=StatusValue" json:"statusValue,omitempty"`
+       Clusters    []*ClusterStatus `protobuf:"bytes,3,rep,name=clusters,proto3" json:"clusters,omitempty"`
+}
+
+func (x *AppStatus) Reset() {
+       *x = AppStatus{}
+       if protoimpl.UnsafeEnabled {
+               mi := &file_statusnotify_proto_msgTypes[7]
+               ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+               ms.StoreMessageInfo(mi)
+       }
+}
+
+func (x *AppStatus) String() string {
+       return protoimpl.X.MessageStringOf(x)
+}
+
+func (*AppStatus) ProtoMessage() {}
+
+func (x *AppStatus) ProtoReflect() protoreflect.Message {
+       mi := &file_statusnotify_proto_msgTypes[7]
+       if protoimpl.UnsafeEnabled && x != nil {
+               ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+               if ms.LoadMessageInfo() == nil {
+                       ms.StoreMessageInfo(mi)
+               }
+               return ms
+       }
+       return mi.MessageOf(x)
+}
+
+// Deprecated: Use AppStatus.ProtoReflect.Descriptor instead.
+func (*AppStatus) Descriptor() ([]byte, []int) {
+       return file_statusnotify_proto_rawDescGZIP(), []int{7}
+}
+
+func (x *AppStatus) GetApp() string {
+       if x != nil {
+               return x.App
+       }
+       return ""
+}
+
+func (x *AppStatus) GetStatusValue() StatusValue {
+       if x != nil {
+               return x.StatusValue
+       }
+       return StatusValue_STATUS_ERROR
+}
+
+func (x *AppStatus) GetClusters() []*ClusterStatus {
+       if x != nil {
+               return x.Clusters
+       }
+       return nil
+}
+
+type StatusDetail struct {
+       state         protoimpl.MessageState
+       sizeCache     protoimpl.SizeCache
+       unknownFields protoimpl.UnknownFields
+
+       // Types that are assignable to StatusDetail:
+       //      *StatusDetail_App
+       //      *StatusDetail_Cluster
+       StatusDetail isStatusDetail_StatusDetail `protobuf_oneof:"statusDetail"`
+}
+
+func (x *StatusDetail) Reset() {
+       *x = StatusDetail{}
+       if protoimpl.UnsafeEnabled {
+               mi := &file_statusnotify_proto_msgTypes[8]
+               ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+               ms.StoreMessageInfo(mi)
+       }
+}
+
+func (x *StatusDetail) String() string {
+       return protoimpl.X.MessageStringOf(x)
+}
+
+func (*StatusDetail) ProtoMessage() {}
+
+func (x *StatusDetail) ProtoReflect() protoreflect.Message {
+       mi := &file_statusnotify_proto_msgTypes[8]
+       if protoimpl.UnsafeEnabled && x != nil {
+               ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+               if ms.LoadMessageInfo() == nil {
+                       ms.StoreMessageInfo(mi)
+               }
+               return ms
+       }
+       return mi.MessageOf(x)
+}
+
+// Deprecated: Use StatusDetail.ProtoReflect.Descriptor instead.
+func (*StatusDetail) Descriptor() ([]byte, []int) {
+       return file_statusnotify_proto_rawDescGZIP(), []int{8}
+}
+
+func (m *StatusDetail) GetStatusDetail() isStatusDetail_StatusDetail {
+       if m != nil {
+               return m.StatusDetail
+       }
+       return nil
+}
+
+func (x *StatusDetail) GetApp() *AppStatus {
+       if x, ok := x.GetStatusDetail().(*StatusDetail_App); ok {
+               return x.App
+       }
+       return nil
+}
+
+func (x *StatusDetail) GetCluster() *ClusterStatus {
+       if x, ok := x.GetStatusDetail().(*StatusDetail_Cluster); ok {
+               return x.Cluster
+       }
+       return nil
+}
+
+type isStatusDetail_StatusDetail interface {
+       isStatusDetail_StatusDetail()
+}
+
+type StatusDetail_App struct {
+       App *AppStatus `protobuf:"bytes,1,opt,name=app,proto3,oneof"`
+}
+
+type StatusDetail_Cluster struct {
+       Cluster *ClusterStatus `protobuf:"bytes,2,opt,name=cluster,proto3,oneof"`
+}
+
+func (*StatusDetail_App) isStatusDetail_StatusDetail() {}
+
+func (*StatusDetail_Cluster) isStatusDetail_StatusDetail() {}
+
+type StatusNotification struct {
+       state         protoimpl.MessageState
+       sizeCache     protoimpl.SizeCache
+       unknownFields protoimpl.UnknownFields
+
+       StatusValue StatusValue     `protobuf:"varint,1,opt,name=statusValue,proto3,enum=StatusValue" json:"statusValue,omitempty"`
+       Details     []*StatusDetail `protobuf:"bytes,2,rep,name=details,proto3" json:"details,omitempty"`
+}
+
+func (x *StatusNotification) Reset() {
+       *x = StatusNotification{}
+       if protoimpl.UnsafeEnabled {
+               mi := &file_statusnotify_proto_msgTypes[9]
+               ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+               ms.StoreMessageInfo(mi)
+       }
+}
+
+func (x *StatusNotification) String() string {
+       return protoimpl.X.MessageStringOf(x)
+}
+
+func (*StatusNotification) ProtoMessage() {}
+
+func (x *StatusNotification) ProtoReflect() protoreflect.Message {
+       mi := &file_statusnotify_proto_msgTypes[9]
+       if protoimpl.UnsafeEnabled && x != nil {
+               ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+               if ms.LoadMessageInfo() == nil {
+                       ms.StoreMessageInfo(mi)
+               }
+               return ms
+       }
+       return mi.MessageOf(x)
+}
+
+// Deprecated: Use StatusNotification.ProtoReflect.Descriptor instead.
+func (*StatusNotification) Descriptor() ([]byte, []int) {
+       return file_statusnotify_proto_rawDescGZIP(), []int{9}
+}
+
+func (x *StatusNotification) GetStatusValue() StatusValue {
+       if x != nil {
+               return x.StatusValue
+       }
+       return StatusValue_STATUS_ERROR
+}
+
+func (x *StatusNotification) GetDetails() []*StatusDetail {
+       if x != nil {
+               return x.Details
+       }
+       return nil
+}
+
+type StatusDeregistration struct {
+       state         protoimpl.MessageState
+       sizeCache     protoimpl.SizeCache
+       unknownFields protoimpl.UnknownFields
+
+       ClientId string `protobuf:"bytes,1,opt,name=clientId,proto3" json:"clientId,omitempty"`
+}
+
+func (x *StatusDeregistration) Reset() {
+       *x = StatusDeregistration{}
+       if protoimpl.UnsafeEnabled {
+               mi := &file_statusnotify_proto_msgTypes[10]
+               ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+               ms.StoreMessageInfo(mi)
+       }
+}
+
+func (x *StatusDeregistration) String() string {
+       return protoimpl.X.MessageStringOf(x)
+}
+
+func (*StatusDeregistration) ProtoMessage() {}
+
+func (x *StatusDeregistration) ProtoReflect() protoreflect.Message {
+       mi := &file_statusnotify_proto_msgTypes[10]
+       if protoimpl.UnsafeEnabled && x != nil {
+               ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+               if ms.LoadMessageInfo() == nil {
+                       ms.StoreMessageInfo(mi)
+               }
+               return ms
+       }
+       return mi.MessageOf(x)
+}
+
+// Deprecated: Use StatusDeregistration.ProtoReflect.Descriptor instead.
+func (*StatusDeregistration) Descriptor() ([]byte, []int) {
+       return file_statusnotify_proto_rawDescGZIP(), []int{10}
+}
+
+func (x *StatusDeregistration) GetClientId() string {
+       if x != nil {
+               return x.ClientId
+       }
+       return ""
+}
+
+type StatusDeregistrationResponse struct {
+       state         protoimpl.MessageState
+       sizeCache     protoimpl.SizeCache
+       unknownFields protoimpl.UnknownFields
+}
+
+func (x *StatusDeregistrationResponse) Reset() {
+       *x = StatusDeregistrationResponse{}
+       if protoimpl.UnsafeEnabled {
+               mi := &file_statusnotify_proto_msgTypes[11]
+               ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+               ms.StoreMessageInfo(mi)
+       }
+}
+
+func (x *StatusDeregistrationResponse) String() string {
+       return protoimpl.X.MessageStringOf(x)
+}
+
+func (*StatusDeregistrationResponse) ProtoMessage() {}
+
+func (x *StatusDeregistrationResponse) ProtoReflect() protoreflect.Message {
+       mi := &file_statusnotify_proto_msgTypes[11]
+       if protoimpl.UnsafeEnabled && x != nil {
+               ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+               if ms.LoadMessageInfo() == nil {
+                       ms.StoreMessageInfo(mi)
+               }
+               return ms
+       }
+       return mi.MessageOf(x)
+}
+
+// Deprecated: Use StatusDeregistrationResponse.ProtoReflect.Descriptor instead.
+func (*StatusDeregistrationResponse) Descriptor() ([]byte, []int) {
+       return file_statusnotify_proto_rawDescGZIP(), []int{11}
+}
+
+var File_statusnotify_proto protoreflect.FileDescriptor
+
+var file_statusnotify_proto_rawDesc = []byte{
+       0x0a, 0x12, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x6e, 0x6f, 0x74, 0x69, 0x66, 0x79, 0x2e, 0x70,
+       0x72, 0x6f, 0x74, 0x6f, 0x22, 0xae, 0x01, 0x0a, 0x06, 0x44, 0x69, 0x67, 0x4b, 0x65, 0x79, 0x12,
+       0x18, 0x0a, 0x07, 0x70, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09,
+       0x52, 0x07, 0x70, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x12, 0x22, 0x0a, 0x0c, 0x63, 0x6f, 0x6d,
+       0x70, 0x6f, 0x73, 0x69, 0x74, 0x65, 0x41, 0x70, 0x70, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52,
+       0x0c, 0x63, 0x6f, 0x6d, 0x70, 0x6f, 0x73, 0x69, 0x74, 0x65, 0x41, 0x70, 0x70, 0x12, 0x30, 0x0a,
+       0x13, 0x63, 0x6f, 0x6d, 0x70, 0x6f, 0x73, 0x69, 0x74, 0x65, 0x41, 0x70, 0x70, 0x56, 0x65, 0x72,
+       0x73, 0x69, 0x6f, 0x6e, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x13, 0x63, 0x6f, 0x6d, 0x70,
+       0x6f, 0x73, 0x69, 0x74, 0x65, 0x41, 0x70, 0x70, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12,
+       0x34, 0x0a, 0x15, 0x64, 0x65, 0x70, 0x6c, 0x6f, 0x79, 0x6d, 0x65, 0x6e, 0x74, 0x49, 0x6e, 0x74,
+       0x65, 0x6e, 0x74, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x15,
+       0x64, 0x65, 0x70, 0x6c, 0x6f, 0x79, 0x6d, 0x65, 0x6e, 0x74, 0x49, 0x6e, 0x74, 0x65, 0x6e, 0x74,
+       0x47, 0x72, 0x6f, 0x75, 0x70, 0x22, 0x45, 0x0a, 0x05, 0x4c, 0x63, 0x4b, 0x65, 0x79, 0x12, 0x18,
+       0x0a, 0x07, 0x70, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52,
+       0x07, 0x70, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x12, 0x22, 0x0a, 0x0c, 0x6c, 0x6f, 0x67, 0x69,
+       0x63, 0x61, 0x6c, 0x43, 0x6c, 0x6f, 0x75, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0c,
+       0x6c, 0x6f, 0x67, 0x69, 0x63, 0x61, 0x6c, 0x43, 0x6c, 0x6f, 0x75, 0x64, 0x22, 0x50, 0x0a, 0x0a,
+       0x43, 0x6c, 0x75, 0x73, 0x74, 0x65, 0x72, 0x4b, 0x65, 0x79, 0x12, 0x28, 0x0a, 0x0f, 0x63, 0x6c,
+       0x75, 0x73, 0x74, 0x65, 0x72, 0x50, 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, 0x72, 0x18, 0x01, 0x20,
+       0x01, 0x28, 0x09, 0x52, 0x0f, 0x63, 0x6c, 0x75, 0x73, 0x74, 0x65, 0x72, 0x50, 0x72, 0x6f, 0x76,
+       0x69, 0x64, 0x65, 0x72, 0x12, 0x18, 0x0a, 0x07, 0x63, 0x6c, 0x75, 0x73, 0x74, 0x65, 0x72, 0x18,
+       0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x63, 0x6c, 0x75, 0x73, 0x74, 0x65, 0x72, 0x22, 0xca,
+       0x02, 0x0a, 0x12, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x52, 0x65, 0x67, 0x69, 0x73, 0x74, 0x72,
+       0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x1a, 0x0a, 0x08, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x49,
+       0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x49,
+       0x64, 0x12, 0x21, 0x0a, 0x06, 0x64, 0x69, 0x67, 0x4b, 0x65, 0x79, 0x18, 0x02, 0x20, 0x01, 0x28,
+       0x0b, 0x32, 0x07, 0x2e, 0x44, 0x69, 0x67, 0x4b, 0x65, 0x79, 0x48, 0x00, 0x52, 0x06, 0x64, 0x69,
+       0x67, 0x4b, 0x65, 0x79, 0x12, 0x1e, 0x0a, 0x05, 0x6c, 0x63, 0x4b, 0x65, 0x79, 0x18, 0x03, 0x20,
+       0x01, 0x28, 0x0b, 0x32, 0x06, 0x2e, 0x4c, 0x63, 0x4b, 0x65, 0x79, 0x48, 0x00, 0x52, 0x05, 0x6c,
+       0x63, 0x4b, 0x65, 0x79, 0x12, 0x2d, 0x0a, 0x0a, 0x63, 0x6c, 0x75, 0x73, 0x74, 0x65, 0x72, 0x4b,
+       0x65, 0x79, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0b, 0x2e, 0x43, 0x6c, 0x75, 0x73, 0x74,
+       0x65, 0x72, 0x4b, 0x65, 0x79, 0x48, 0x00, 0x52, 0x0a, 0x63, 0x6c, 0x75, 0x73, 0x74, 0x65, 0x72,
+       0x4b, 0x65, 0x79, 0x12, 0x2c, 0x0a, 0x0a, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x54, 0x79, 0x70,
+       0x65, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x0c, 0x2e, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73,
+       0x56, 0x61, 0x6c, 0x75, 0x65, 0x52, 0x0a, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x54, 0x79, 0x70,
+       0x65, 0x12, 0x12, 0x0a, 0x04, 0x61, 0x70, 0x70, 0x73, 0x18, 0x06, 0x20, 0x03, 0x28, 0x09, 0x52,
+       0x04, 0x61, 0x70, 0x70, 0x73, 0x12, 0x1a, 0x0a, 0x08, 0x63, 0x6c, 0x75, 0x73, 0x74, 0x65, 0x72,
+       0x73, 0x18, 0x07, 0x20, 0x03, 0x28, 0x09, 0x52, 0x08, 0x63, 0x6c, 0x75, 0x73, 0x74, 0x65, 0x72,
+       0x73, 0x12, 0x1c, 0x0a, 0x09, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x73, 0x18, 0x08,
+       0x20, 0x03, 0x28, 0x09, 0x52, 0x09, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x73, 0x12,
+       0x23, 0x0a, 0x06, 0x6f, 0x75, 0x74, 0x70, 0x75, 0x74, 0x18, 0x09, 0x20, 0x01, 0x28, 0x0e, 0x32,
+       0x0b, 0x2e, 0x4f, 0x75, 0x74, 0x70, 0x75, 0x74, 0x54, 0x79, 0x70, 0x65, 0x52, 0x06, 0x6f, 0x75,
+       0x74, 0x70, 0x75, 0x74, 0x42, 0x05, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x22, 0x49, 0x0a, 0x03, 0x47,
+       0x56, 0x4b, 0x12, 0x14, 0x0a, 0x05, 0x67, 0x72, 0x6f, 0x75, 0x70, 0x18, 0x01, 0x20, 0x01, 0x28,
+       0x09, 0x52, 0x05, 0x67, 0x72, 0x6f, 0x75, 0x70, 0x12, 0x18, 0x0a, 0x07, 0x76, 0x65, 0x72, 0x73,
+       0x69, 0x6f, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x76, 0x65, 0x72, 0x73, 0x69,
+       0x6f, 0x6e, 0x12, 0x12, 0x0a, 0x04, 0x6b, 0x69, 0x6e, 0x64, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09,
+       0x52, 0x04, 0x6b, 0x69, 0x6e, 0x64, 0x22, 0x6c, 0x0a, 0x0e, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72,
+       0x63, 0x65, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65,
+       0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x16, 0x0a, 0x03,
+       0x67, 0x76, 0x6b, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x04, 0x2e, 0x47, 0x56, 0x4b, 0x52,
+       0x03, 0x67, 0x76, 0x6b, 0x12, 0x2e, 0x0a, 0x0b, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x56, 0x61,
+       0x6c, 0x75, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x0c, 0x2e, 0x53, 0x74, 0x61, 0x74,
+       0x75, 0x73, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x52, 0x0b, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x56,
+       0x61, 0x6c, 0x75, 0x65, 0x22, 0xb2, 0x01, 0x0a, 0x0d, 0x43, 0x6c, 0x75, 0x73, 0x74, 0x65, 0x72,
+       0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x12, 0x28, 0x0a, 0x0f, 0x63, 0x6c, 0x75, 0x73, 0x74, 0x65,
+       0x72, 0x50, 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, 0x72, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52,
+       0x0f, 0x63, 0x6c, 0x75, 0x73, 0x74, 0x65, 0x72, 0x50, 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, 0x72,
+       0x12, 0x18, 0x0a, 0x07, 0x63, 0x6c, 0x75, 0x73, 0x74, 0x65, 0x72, 0x18, 0x02, 0x20, 0x01, 0x28,
+       0x09, 0x52, 0x07, 0x63, 0x6c, 0x75, 0x73, 0x74, 0x65, 0x72, 0x12, 0x2e, 0x0a, 0x0b, 0x73, 0x74,
+       0x61, 0x74, 0x75, 0x73, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0e, 0x32,
+       0x0c, 0x2e, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x52, 0x0b, 0x73,
+       0x74, 0x61, 0x74, 0x75, 0x73, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x12, 0x2d, 0x0a, 0x09, 0x72, 0x65,
+       0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x73, 0x18, 0x04, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x0f, 0x2e,
+       0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x52, 0x09,
+       0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x73, 0x22, 0x79, 0x0a, 0x09, 0x41, 0x70, 0x70,
+       0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x12, 0x10, 0x0a, 0x03, 0x61, 0x70, 0x70, 0x18, 0x01, 0x20,
+       0x01, 0x28, 0x09, 0x52, 0x03, 0x61, 0x70, 0x70, 0x12, 0x2e, 0x0a, 0x0b, 0x73, 0x74, 0x61, 0x74,
+       0x75, 0x73, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x0c, 0x2e,
+       0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x52, 0x0b, 0x73, 0x74, 0x61,
+       0x74, 0x75, 0x73, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x12, 0x2a, 0x0a, 0x08, 0x63, 0x6c, 0x75, 0x73,
+       0x74, 0x65, 0x72, 0x73, 0x18, 0x03, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x0e, 0x2e, 0x43, 0x6c, 0x75,
+       0x73, 0x74, 0x65, 0x72, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x52, 0x08, 0x63, 0x6c, 0x75, 0x73,
+       0x74, 0x65, 0x72, 0x73, 0x22, 0x6a, 0x0a, 0x0c, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x44, 0x65,
+       0x74, 0x61, 0x69, 0x6c, 0x12, 0x1e, 0x0a, 0x03, 0x61, 0x70, 0x70, 0x18, 0x01, 0x20, 0x01, 0x28,
+       0x0b, 0x32, 0x0a, 0x2e, 0x41, 0x70, 0x70, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x48, 0x00, 0x52,
+       0x03, 0x61, 0x70, 0x70, 0x12, 0x2a, 0x0a, 0x07, 0x63, 0x6c, 0x75, 0x73, 0x74, 0x65, 0x72, 0x18,
+       0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0e, 0x2e, 0x43, 0x6c, 0x75, 0x73, 0x74, 0x65, 0x72, 0x53,
+       0x74, 0x61, 0x74, 0x75, 0x73, 0x48, 0x00, 0x52, 0x07, 0x63, 0x6c, 0x75, 0x73, 0x74, 0x65, 0x72,
+       0x42, 0x0e, 0x0a, 0x0c, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x44, 0x65, 0x74, 0x61, 0x69, 0x6c,
+       0x22, 0x6d, 0x0a, 0x12, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x69,
+       0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x2e, 0x0a, 0x0b, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73,
+       0x56, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x0c, 0x2e, 0x53, 0x74,
+       0x61, 0x74, 0x75, 0x73, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x52, 0x0b, 0x73, 0x74, 0x61, 0x74, 0x75,
+       0x73, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x12, 0x27, 0x0a, 0x07, 0x64, 0x65, 0x74, 0x61, 0x69, 0x6c,
+       0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x0d, 0x2e, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73,
+       0x44, 0x65, 0x74, 0x61, 0x69, 0x6c, 0x52, 0x07, 0x64, 0x65, 0x74, 0x61, 0x69, 0x6c, 0x73, 0x22,
+       0x32, 0x0a, 0x14, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x44, 0x65, 0x72, 0x65, 0x67, 0x69, 0x73,
+       0x74, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x1a, 0x0a, 0x08, 0x63, 0x6c, 0x69, 0x65, 0x6e,
+       0x74, 0x49, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x63, 0x6c, 0x69, 0x65, 0x6e,
+       0x74, 0x49, 0x64, 0x22, 0x1e, 0x0a, 0x1c, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x44, 0x65, 0x72,
+       0x65, 0x67, 0x69, 0x73, 0x74, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f,
+       0x6e, 0x73, 0x65, 0x2a, 0x22, 0x0a, 0x0a, 0x4f, 0x75, 0x74, 0x70, 0x75, 0x74, 0x54, 0x79, 0x70,
+       0x65, 0x12, 0x0b, 0x0a, 0x07, 0x53, 0x55, 0x4d, 0x4d, 0x41, 0x52, 0x59, 0x10, 0x00, 0x12, 0x07,
+       0x0a, 0x03, 0x41, 0x4c, 0x4c, 0x10, 0x01, 0x2a, 0x59, 0x0a, 0x0b, 0x53, 0x74, 0x61, 0x74, 0x75,
+       0x73, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x12, 0x10, 0x0a, 0x0c, 0x53, 0x54, 0x41, 0x54, 0x55, 0x53,
+       0x5f, 0x45, 0x52, 0x52, 0x4f, 0x52, 0x10, 0x00, 0x12, 0x0d, 0x0a, 0x09, 0x4e, 0x4f, 0x54, 0x5f,
+       0x52, 0x45, 0x41, 0x44, 0x59, 0x10, 0x01, 0x12, 0x09, 0x0a, 0x05, 0x52, 0x45, 0x41, 0x44, 0x59,
+       0x10, 0x02, 0x12, 0x10, 0x0a, 0x0c, 0x4e, 0x4f, 0x54, 0x5f, 0x44, 0x45, 0x50, 0x4c, 0x4f, 0x59,
+       0x45, 0x44, 0x10, 0x03, 0x12, 0x0c, 0x0a, 0x08, 0x44, 0x45, 0x50, 0x4c, 0x4f, 0x59, 0x45, 0x44,
+       0x10, 0x04, 0x32, 0x9a, 0x01, 0x0a, 0x0c, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x4e, 0x6f, 0x74,
+       0x69, 0x66, 0x79, 0x12, 0x3e, 0x0a, 0x0e, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x52, 0x65, 0x67,
+       0x69, 0x73, 0x74, 0x65, 0x72, 0x12, 0x13, 0x2e, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x52, 0x65,
+       0x67, 0x69, 0x73, 0x74, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x1a, 0x13, 0x2e, 0x53, 0x74, 0x61,
+       0x74, 0x75, 0x73, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x22,
+       0x00, 0x30, 0x01, 0x12, 0x4a, 0x0a, 0x10, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x44, 0x65, 0x72,
+       0x65, 0x67, 0x69, 0x73, 0x74, 0x65, 0x72, 0x12, 0x15, 0x2e, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73,
+       0x44, 0x65, 0x72, 0x65, 0x67, 0x69, 0x73, 0x74, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x1a, 0x1d,
+       0x2e, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x44, 0x65, 0x72, 0x65, 0x67, 0x69, 0x73, 0x74, 0x72,
+       0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x42,
+       0x10, 0x5a, 0x0e, 0x2e, 0x2f, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x6e, 0x6f, 0x74, 0x69, 0x66,
+       0x79, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
+}
+
+var (
+       file_statusnotify_proto_rawDescOnce sync.Once
+       file_statusnotify_proto_rawDescData = file_statusnotify_proto_rawDesc
+)
+
+func file_statusnotify_proto_rawDescGZIP() []byte {
+       file_statusnotify_proto_rawDescOnce.Do(func() {
+               file_statusnotify_proto_rawDescData = protoimpl.X.CompressGZIP(file_statusnotify_proto_rawDescData)
+       })
+       return file_statusnotify_proto_rawDescData
+}
+
+var file_statusnotify_proto_enumTypes = make([]protoimpl.EnumInfo, 2)
+var file_statusnotify_proto_msgTypes = make([]protoimpl.MessageInfo, 12)
+var file_statusnotify_proto_goTypes = []interface{}{
+       (OutputType)(0),                      // 0: OutputType
+       (StatusValue)(0),                     // 1: StatusValue
+       (*DigKey)(nil),                       // 2: DigKey
+       (*LcKey)(nil),                        // 3: LcKey
+       (*ClusterKey)(nil),                   // 4: ClusterKey
+       (*StatusRegistration)(nil),           // 5: StatusRegistration
+       (*GVK)(nil),                          // 6: GVK
+       (*ResourceStatus)(nil),               // 7: ResourceStatus
+       (*ClusterStatus)(nil),                // 8: ClusterStatus
+       (*AppStatus)(nil),                    // 9: AppStatus
+       (*StatusDetail)(nil),                 // 10: StatusDetail
+       (*StatusNotification)(nil),           // 11: StatusNotification
+       (*StatusDeregistration)(nil),         // 12: StatusDeregistration
+       (*StatusDeregistrationResponse)(nil), // 13: StatusDeregistrationResponse
+}
+var file_statusnotify_proto_depIdxs = []int32{
+       2,  // 0: StatusRegistration.digKey:type_name -> DigKey
+       3,  // 1: StatusRegistration.lcKey:type_name -> LcKey
+       4,  // 2: StatusRegistration.clusterKey:type_name -> ClusterKey
+       1,  // 3: StatusRegistration.statusType:type_name -> StatusValue
+       0,  // 4: StatusRegistration.output:type_name -> OutputType
+       6,  // 5: ResourceStatus.gvk:type_name -> GVK
+       1,  // 6: ResourceStatus.statusValue:type_name -> StatusValue
+       1,  // 7: ClusterStatus.statusValue:type_name -> StatusValue
+       7,  // 8: ClusterStatus.resources:type_name -> ResourceStatus
+       1,  // 9: AppStatus.statusValue:type_name -> StatusValue
+       8,  // 10: AppStatus.clusters:type_name -> ClusterStatus
+       9,  // 11: StatusDetail.app:type_name -> AppStatus
+       8,  // 12: StatusDetail.cluster:type_name -> ClusterStatus
+       1,  // 13: StatusNotification.statusValue:type_name -> StatusValue
+       10, // 14: StatusNotification.details:type_name -> StatusDetail
+       5,  // 15: StatusNotify.StatusRegister:input_type -> StatusRegistration
+       12, // 16: StatusNotify.StatusDeregister:input_type -> StatusDeregistration
+       11, // 17: StatusNotify.StatusRegister:output_type -> StatusNotification
+       13, // 18: StatusNotify.StatusDeregister:output_type -> StatusDeregistrationResponse
+       17, // [17:19] is the sub-list for method output_type
+       15, // [15:17] is the sub-list for method input_type
+       15, // [15:15] is the sub-list for extension type_name
+       15, // [15:15] is the sub-list for extension extendee
+       0,  // [0:15] is the sub-list for field type_name
+}
+
+func init() { file_statusnotify_proto_init() }
+func file_statusnotify_proto_init() {
+       if File_statusnotify_proto != nil {
+               return
+       }
+       if !protoimpl.UnsafeEnabled {
+               file_statusnotify_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} {
+                       switch v := v.(*DigKey); i {
+                       case 0:
+                               return &v.state
+                       case 1:
+                               return &v.sizeCache
+                       case 2:
+                               return &v.unknownFields
+                       default:
+                               return nil
+                       }
+               }
+               file_statusnotify_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} {
+                       switch v := v.(*LcKey); i {
+                       case 0:
+                               return &v.state
+                       case 1:
+                               return &v.sizeCache
+                       case 2:
+                               return &v.unknownFields
+                       default:
+                               return nil
+                       }
+               }
+               file_statusnotify_proto_msgTypes[2].Exporter = func(v interface{}, i int) interface{} {
+                       switch v := v.(*ClusterKey); i {
+                       case 0:
+                               return &v.state
+                       case 1:
+                               return &v.sizeCache
+                       case 2:
+                               return &v.unknownFields
+                       default:
+                               return nil
+                       }
+               }
+               file_statusnotify_proto_msgTypes[3].Exporter = func(v interface{}, i int) interface{} {
+                       switch v := v.(*StatusRegistration); i {
+                       case 0:
+                               return &v.state
+                       case 1:
+                               return &v.sizeCache
+                       case 2:
+                               return &v.unknownFields
+                       default:
+                               return nil
+                       }
+               }
+               file_statusnotify_proto_msgTypes[4].Exporter = func(v interface{}, i int) interface{} {
+                       switch v := v.(*GVK); i {
+                       case 0:
+                               return &v.state
+                       case 1:
+                               return &v.sizeCache
+                       case 2:
+                               return &v.unknownFields
+                       default:
+                               return nil
+                       }
+               }
+               file_statusnotify_proto_msgTypes[5].Exporter = func(v interface{}, i int) interface{} {
+                       switch v := v.(*ResourceStatus); i {
+                       case 0:
+                               return &v.state
+                       case 1:
+                               return &v.sizeCache
+                       case 2:
+                               return &v.unknownFields
+                       default:
+                               return nil
+                       }
+               }
+               file_statusnotify_proto_msgTypes[6].Exporter = func(v interface{}, i int) interface{} {
+                       switch v := v.(*ClusterStatus); i {
+                       case 0:
+                               return &v.state
+                       case 1:
+                               return &v.sizeCache
+                       case 2:
+                               return &v.unknownFields
+                       default:
+                               return nil
+                       }
+               }
+               file_statusnotify_proto_msgTypes[7].Exporter = func(v interface{}, i int) interface{} {
+                       switch v := v.(*AppStatus); i {
+                       case 0:
+                               return &v.state
+                       case 1:
+                               return &v.sizeCache
+                       case 2:
+                               return &v.unknownFields
+                       default:
+                               return nil
+                       }
+               }
+               file_statusnotify_proto_msgTypes[8].Exporter = func(v interface{}, i int) interface{} {
+                       switch v := v.(*StatusDetail); i {
+                       case 0:
+                               return &v.state
+                       case 1:
+                               return &v.sizeCache
+                       case 2:
+                               return &v.unknownFields
+                       default:
+                               return nil
+                       }
+               }
+               file_statusnotify_proto_msgTypes[9].Exporter = func(v interface{}, i int) interface{} {
+                       switch v := v.(*StatusNotification); i {
+                       case 0:
+                               return &v.state
+                       case 1:
+                               return &v.sizeCache
+                       case 2:
+                               return &v.unknownFields
+                       default:
+                               return nil
+                       }
+               }
+               file_statusnotify_proto_msgTypes[10].Exporter = func(v interface{}, i int) interface{} {
+                       switch v := v.(*StatusDeregistration); i {
+                       case 0:
+                               return &v.state
+                       case 1:
+                               return &v.sizeCache
+                       case 2:
+                               return &v.unknownFields
+                       default:
+                               return nil
+                       }
+               }
+               file_statusnotify_proto_msgTypes[11].Exporter = func(v interface{}, i int) interface{} {
+                       switch v := v.(*StatusDeregistrationResponse); i {
+                       case 0:
+                               return &v.state
+                       case 1:
+                               return &v.sizeCache
+                       case 2:
+                               return &v.unknownFields
+                       default:
+                               return nil
+                       }
+               }
+       }
+       file_statusnotify_proto_msgTypes[3].OneofWrappers = []interface{}{
+               (*StatusRegistration_DigKey)(nil),
+               (*StatusRegistration_LcKey)(nil),
+               (*StatusRegistration_ClusterKey)(nil),
+       }
+       file_statusnotify_proto_msgTypes[8].OneofWrappers = []interface{}{
+               (*StatusDetail_App)(nil),
+               (*StatusDetail_Cluster)(nil),
+       }
+       type x struct{}
+       out := protoimpl.TypeBuilder{
+               File: protoimpl.DescBuilder{
+                       GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
+                       RawDescriptor: file_statusnotify_proto_rawDesc,
+                       NumEnums:      2,
+                       NumMessages:   12,
+                       NumExtensions: 0,
+                       NumServices:   1,
+               },
+               GoTypes:           file_statusnotify_proto_goTypes,
+               DependencyIndexes: file_statusnotify_proto_depIdxs,
+               EnumInfos:         file_statusnotify_proto_enumTypes,
+               MessageInfos:      file_statusnotify_proto_msgTypes,
+       }.Build()
+       File_statusnotify_proto = out.File
+       file_statusnotify_proto_rawDesc = nil
+       file_statusnotify_proto_goTypes = nil
+       file_statusnotify_proto_depIdxs = nil
+}
+
+// Reference imports to suppress errors if they are not otherwise used.
+var _ context.Context
+var _ grpc.ClientConnInterface
+
+// This is a compile-time assertion to ensure that this generated file
+// is compatible with the grpc package it is being compiled against.
+const _ = grpc.SupportPackageIsVersion6
+
+// StatusNotifyClient is the client API for StatusNotify service.
+//
+// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://godoc.org/google.golang.org/grpc#ClientConn.NewStream.
+type StatusNotifyClient interface {
+       StatusRegister(ctx context.Context, in *StatusRegistration, opts ...grpc.CallOption) (StatusNotify_StatusRegisterClient, error)
+       StatusDeregister(ctx context.Context, in *StatusDeregistration, opts ...grpc.CallOption) (*StatusDeregistrationResponse, error)
+}
+
+type statusNotifyClient struct {
+       cc grpc.ClientConnInterface
+}
+
+func NewStatusNotifyClient(cc grpc.ClientConnInterface) StatusNotifyClient {
+       return &statusNotifyClient{cc}
+}
+
+func (c *statusNotifyClient) StatusRegister(ctx context.Context, in *StatusRegistration, opts ...grpc.CallOption) (StatusNotify_StatusRegisterClient, error) {
+       stream, err := c.cc.NewStream(ctx, &_StatusNotify_serviceDesc.Streams[0], "/StatusNotify/StatusRegister", opts...)
+       if err != nil {
+               return nil, err
+       }
+       x := &statusNotifyStatusRegisterClient{stream}
+       if err := x.ClientStream.SendMsg(in); err != nil {
+               return nil, err
+       }
+       if err := x.ClientStream.CloseSend(); err != nil {
+               return nil, err
+       }
+       return x, nil
+}
+
+type StatusNotify_StatusRegisterClient interface {
+       Recv() (*StatusNotification, error)
+       grpc.ClientStream
+}
+
+type statusNotifyStatusRegisterClient struct {
+       grpc.ClientStream
+}
+
+func (x *statusNotifyStatusRegisterClient) Recv() (*StatusNotification, error) {
+       m := new(StatusNotification)
+       if err := x.ClientStream.RecvMsg(m); err != nil {
+               return nil, err
+       }
+       return m, nil
+}
+
+func (c *statusNotifyClient) StatusDeregister(ctx context.Context, in *StatusDeregistration, opts ...grpc.CallOption) (*StatusDeregistrationResponse, error) {
+       out := new(StatusDeregistrationResponse)
+       err := c.cc.Invoke(ctx, "/StatusNotify/StatusDeregister", in, out, opts...)
+       if err != nil {
+               return nil, err
+       }
+       return out, nil
+}
+
+// StatusNotifyServer is the server API for StatusNotify service.
+type StatusNotifyServer interface {
+       StatusRegister(*StatusRegistration, StatusNotify_StatusRegisterServer) error
+       StatusDeregister(context.Context, *StatusDeregistration) (*StatusDeregistrationResponse, error)
+}
+
+// UnimplementedStatusNotifyServer can be embedded to have forward compatible implementations.
+type UnimplementedStatusNotifyServer struct {
+}
+
+func (*UnimplementedStatusNotifyServer) StatusRegister(*StatusRegistration, StatusNotify_StatusRegisterServer) error {
+       return status.Errorf(codes.Unimplemented, "method StatusRegister not implemented")
+}
+func (*UnimplementedStatusNotifyServer) StatusDeregister(context.Context, *StatusDeregistration) (*StatusDeregistrationResponse, error) {
+       return nil, status.Errorf(codes.Unimplemented, "method StatusDeregister not implemented")
+}
+
+func RegisterStatusNotifyServer(s *grpc.Server, srv StatusNotifyServer) {
+       s.RegisterService(&_StatusNotify_serviceDesc, srv)
+}
+
+func _StatusNotify_StatusRegister_Handler(srv interface{}, stream grpc.ServerStream) error {
+       m := new(StatusRegistration)
+       if err := stream.RecvMsg(m); err != nil {
+               return err
+       }
+       return srv.(StatusNotifyServer).StatusRegister(m, &statusNotifyStatusRegisterServer{stream})
+}
+
+type StatusNotify_StatusRegisterServer interface {
+       Send(*StatusNotification) error
+       grpc.ServerStream
+}
+
+type statusNotifyStatusRegisterServer struct {
+       grpc.ServerStream
+}
+
+func (x *statusNotifyStatusRegisterServer) Send(m *StatusNotification) error {
+       return x.ServerStream.SendMsg(m)
+}
+
+func _StatusNotify_StatusDeregister_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
+       in := new(StatusDeregistration)
+       if err := dec(in); err != nil {
+               return nil, err
+       }
+       if interceptor == nil {
+               return srv.(StatusNotifyServer).StatusDeregister(ctx, in)
+       }
+       info := &grpc.UnaryServerInfo{
+               Server:     srv,
+               FullMethod: "/StatusNotify/StatusDeregister",
+       }
+       handler := func(ctx context.Context, req interface{}) (interface{}, error) {
+               return srv.(StatusNotifyServer).StatusDeregister(ctx, req.(*StatusDeregistration))
+       }
+       return interceptor(ctx, in, info, handler)
+}
+
+var _StatusNotify_serviceDesc = grpc.ServiceDesc{
+       ServiceName: "StatusNotify",
+       HandlerType: (*StatusNotifyServer)(nil),
+       Methods: []grpc.MethodDesc{
+               {
+                       MethodName: "StatusDeregister",
+                       Handler:    _StatusNotify_StatusDeregister_Handler,
+               },
+       },
+       Streams: []grpc.StreamDesc{
+               {
+                       StreamName:    "StatusRegister",
+                       Handler:       _StatusNotify_StatusRegister_Handler,
+                       ServerStreams: true,
+               },
+       },
+       Metadata: "statusnotify.proto",
+}
diff --git a/central-controller/src/vendor/gitlab.com/project-emco/core/emco-base/src/orchestrator/pkg/grpc/statusnotify/statusnotify.proto b/central-controller/src/vendor/gitlab.com/project-emco/core/emco-base/src/orchestrator/pkg/grpc/statusnotify/statusnotify.proto
new file mode 100644 (file)
index 0000000..cc04334
--- /dev/null
@@ -0,0 +1,104 @@
+// SPDX-License-Identifier: Apache-2.0
+// Copyright (c) 2021 Intel Corporation
+
+syntax = "proto3";
+
+option go_package="./statusnotify";
+
+service StatusNotify {
+       rpc StatusRegister (StatusRegistration) returns (stream StatusNotification){
+
+       }
+
+       rpc StatusDeregister (StatusDeregistration) returns (StatusDeregistrationResponse){
+               
+       }
+}
+
+message DigKey {
+       string project = 1;
+       string compositeApp = 2;
+       string compositeAppVersion = 3;
+       string deploymentIntentGroup = 4;
+}
+
+message LcKey {
+       string project = 1;
+       string logicalCloud = 2;
+}
+
+message ClusterKey {
+       string clusterProvider = 1;
+       string cluster = 2;
+}
+
+enum OutputType {
+       SUMMARY = 0;
+       ALL = 1;
+}
+
+message StatusRegistration {
+       string clientId = 1;
+       oneof key {
+               DigKey digKey = 2;
+               LcKey lcKey = 3;
+               ClusterKey clusterKey = 4;
+       }
+       StatusValue statusType = 5;
+       repeated string apps = 6;
+       repeated string clusters = 7;
+       repeated string resources = 8;
+       OutputType output = 9;
+}
+
+enum StatusValue {
+       STATUS_ERROR = 0;
+       NOT_READY = 1;
+       READY = 2;
+       NOT_DEPLOYED = 3;
+       DEPLOYED = 4;
+}
+
+message GVK {
+       string group = 1;
+       string version = 2;
+       string kind = 3;
+}
+
+message ResourceStatus {
+       string name = 1;
+       GVK gvk = 2;
+       StatusValue statusValue = 3;
+}
+
+message ClusterStatus {
+       string clusterProvider = 1;
+       string cluster = 2;
+       StatusValue statusValue = 3;
+       repeated ResourceStatus resources = 4;
+}
+
+message AppStatus {
+       string app = 1;
+       StatusValue statusValue = 2;
+       repeated ClusterStatus clusters = 3;
+}
+
+message StatusDetail {
+       oneof statusDetail {
+               AppStatus app = 1;
+               ClusterStatus cluster = 2;
+       }
+}
+
+message StatusNotification {
+       StatusValue statusValue = 1;
+       repeated StatusDetail details = 2;
+}
+
+message StatusDeregistration {
+       string clientId = 1;
+}
+
+message StatusDeregistrationResponse {
+}
diff --git a/central-controller/src/vendor/gitlab.com/project-emco/core/emco-base/src/orchestrator/pkg/infra/apierror/apierror.go b/central-controller/src/vendor/gitlab.com/project-emco/core/emco-base/src/orchestrator/pkg/infra/apierror/apierror.go
new file mode 100644 (file)
index 0000000..9fbfc4d
--- /dev/null
@@ -0,0 +1,89 @@
+// SPDX-License-Identifier: Apache-2.0
+// Copyright (c) 2021 Intel Corporation
+
+package apierror
+
+import (
+       "net/http"
+       "strings"
+
+       log "gitlab.com/project-emco/core/emco-base/src/orchestrator/pkg/infra/logutils"
+)
+
+type APIError struct {
+       ID      string
+       Message string
+       Status  int
+}
+
+var dbErrors = []APIError{
+       {ID: "db Find error", Message: "Error finding referencing resources", Status: http.StatusInternalServerError},
+       {ID: "db Remove error", Message: "Error removing referencing resources", Status: http.StatusInternalServerError},
+       {ID: "db Remove resource not found", Message: "The requested resource not found", Status: http.StatusNotFound},
+       {ID: "db Remove parent child constraint", Message: "Cannot delete parent without deleting child references first", Status: http.StatusConflict},
+       {ID: "db Remove referential constraint", Message: "Cannot delete without deleting or updating referencing resources first", Status: http.StatusConflict},
+       {ID: "db Insert error", Message: "Error adding or updating referencing resources", Status: http.StatusInternalServerError},
+       {ID: "db Insert parent resource not found", Message: "Cannot perform requested operation. Parent resource not found", Status: http.StatusConflict},
+       {ID: "db Insert referential schema missing", Message: "Cannot perform requested operation. The requested resource is not defined in the referential schema", Status: http.StatusConflict},
+}
+
+// shared list the errors a controller can get from a dependent controller
+// for example, DTC calls the orchestrator to check the status of a deployment intent group
+// and the orchestrator returns `DeploymentIntentGroup not found`
+var shared = []APIError{
+       {ID: "App not found", Message: "app not found", Status: http.StatusNotFound},
+       {ID: "AppDependency not found", Message: "appDependency not found", Status: http.StatusNotFound},
+       {ID: "AppIntent not found", Message: "appIntent not found", Status: http.StatusNotFound},
+       {ID: "AppProfile not found", Message: "appProfile not found", Status: http.StatusNotFound},
+       {ID: "CompositeApp not found", Message: "compositeApp not found", Status: http.StatusNotFound},
+       {ID: "CompositeProfile not found", Message: "compositeProfile not found", Status: http.StatusNotFound},
+       {ID: "Controller not found", Message: "controller not found", Status: http.StatusNotFound},
+       {ID: "Cluster not found", Message: "cluster not found", Status: http.StatusNotFound},
+       {ID: "DeploymentIntentGroup not found", Message: "deploymentIntentGroup not found", Status: http.StatusNotFound},
+       {ID: "GenericPlacementIntent not found", Message: "genericPlacementIntent not found", Status: http.StatusNotFound},
+       {ID: "Intent not found", Message: "intent not found", Status: http.StatusNotFound},
+       {ID: "LogicalCloud not found", Message: "logicalCloud not found", Status: http.StatusNotFound},
+       {ID: "Project not found", Message: "project not found", Status: http.StatusNotFound},
+}
+
+// HandleErrors handles api resources add/update/create errors
+// Returns APIError with the ID, message and the http status based on the error
+func HandleErrors(params map[string]string, err error, mod interface{}, apiErr []APIError) APIError {
+       log.Error("Error :: ", log.Fields{"Parameters": params, "Error": err, "Module": mod})
+
+       // db errors
+       for _, e := range dbErrors {
+               if strings.Contains(err.Error(), e.ID) {
+                       return e
+               }
+       }
+
+       // api specific errors
+       for _, e := range apiErr {
+               if strings.Contains(err.Error(), e.ID) {
+                       return e
+               }
+       }
+
+       // conditional errors
+       for _, e := range shared {
+               if strings.Contains(err.Error(), e.ID) {
+                       return e
+               }
+       }
+
+       // Default
+       return APIError{ID: "Internal server error", Message: "The server encountered an internal error and was unable to complete your request.", Status: http.StatusInternalServerError}
+}
+
+// HandleLogicalCloudErrors handles logical cloud errors
+// Returns APIError with the ID, message and the http status based on the error
+func HandleLogicalCloudErrors(params map[string]string, err error, lcErrors []APIError) APIError {
+       for _, e := range lcErrors {
+               if strings.Contains(err.Error(), e.ID) {
+                       log.Error("Logical cloud error :: ", log.Fields{"Parameters": params, "Error": err})
+                       return e
+               }
+       }
+       return APIError{}
+}
@@ -8,6 +8,7 @@ import (
        "log"
        "os"
        "reflect"
+       "strings"
 )
 
 // Configuration loads up all the values that are used to configure
@@ -33,6 +34,21 @@ type Configuration struct {
        KubernetesLabelName    string `json:"kubernetes-label-name"`
        LogLevel               string `json:"log-level"`
        MaxRetries             string `json:"max-retries"`
+       BackOff                int    `json:"db-schema-backoff"`
+       MaxBackOff             int    `json:"db-schema-max-backoff"`
+
+       // EMCO-internal communication
+       //    wait time for a grpc connection to become ready, in milliseconds
+       GrpcConnReadyTime int `json:"grpc-conn-ready-time"`
+       //    wait time to declare a grpc conn as failed, in milliseconds
+       GrpcConnTimeout int `json:"grpc-conn-timeout"`
+       //    RPC call timeout, in milliseconds
+       //    gRPC call deadline may vary across controllers. We could have each
+       //    controller register with orch with a timeout value, in the future.
+       //    For now, we use a fixed timeout for all.
+       GrpcCallTimeout int `json:"grpc-call-timeout"`
+
+       // TODO: EMCO-K8s communication: Create similar time/timeout params
 }
 
 // Config is the structure that stores the configuration
@@ -88,8 +104,34 @@ func defaultConfiguration() *Configuration {
                ServicePort:            "9015",
                KubernetesLabelName:    "orchestrator.io/rb-instance-id",
                LogLevel:               "warn", // default log-level of all modules
-               MaxRetries:             "",
+               MaxRetries:             "",     // rsync
+               BackOff:                5,      // default backoff time interval for ref schema
+               MaxBackOff:             60,     // max backoff time interval for ref schema
+               GrpcConnReadyTime:      1000,   // 1 second in milliseconds
+               GrpcConnTimeout:        1000,   // 1 second
+               GrpcCallTimeout:        10000,  // 10 seconds
+       }
+}
+
+func isValidConfig(cfg *Configuration) bool {
+       valid := true
+       members := reflect.ValueOf(cfg).Elem()
+
+       // If a config param has "Time" in its name, and is type int,
+       // ensure its value is positive.
+       for i := 0; i < members.NumField(); i++ {
+               varName := members.Type().Field(i).Name
+               varValue := members.Field(i).Interface()
+               if strings.Contains(varName, "Time") {
+                       intValue, ok := varValue.(int)
+                       if ok && intValue <= 0 {
+                               log.Printf("%s must be positive, not %d.\n",
+                                       varName, intValue)
+                               valid = false
+                       }
+               }
        }
+       return valid
 }
 
 // GetConfiguration returns the configuration for the app.
@@ -102,6 +144,11 @@ func GetConfiguration() *Configuration {
                        log.Println("Using defaults...")
                }
                gConfig = conf
+
+               if !isValidConfig(gConfig) {
+                       log.Fatalln("Bad data in config. Exiting.")
+                       return nil
+               }
        }
 
        return gConfig
diff --git a/central-controller/src/vendor/gitlab.com/project-emco/core/emco-base/src/orchestrator/pkg/infra/config/config_test.go b/central-controller/src/vendor/gitlab.com/project-emco/core/emco-base/src/orchestrator/pkg/infra/config/config_test.go
new file mode 100644 (file)
index 0000000..97183ce
--- /dev/null
@@ -0,0 +1,67 @@
+// SPDX-License-Identifier: Apache-2.0
+// Copyright (c) 2020 Intel Corporation
+
+package config
+
+import (
+       "bytes"
+       "log"
+       "os"
+       "strings"
+       "testing"
+)
+
+func TestReadConfigurationFile(t *testing.T) {
+       t.Run("Non Existent Configuration File", func(t *testing.T) {
+               _, err := readConfigFile("filedoesnotexist.json")
+               if err == nil {
+                       t.Fatal("ReadConfiguationFile: Expected Error, got nil")
+               }
+       })
+
+       t.Run("Read Configuration File", func(t *testing.T) {
+               conf, err := readConfigFile("../../../tests/configs/mock_config.json")
+               if err != nil {
+                       t.Fatal("ReadConfigurationFile: Error reading file: ", err)
+               }
+               if conf.DatabaseType != "mock_db_test" {
+                       t.Fatal("ReadConfigurationFile: Incorrect entry read from file")
+               }
+       })
+}
+
+func TestIsValidConfig(t *testing.T) {
+       t.Run("Validate Good Configuration File", func(t *testing.T) {
+               conf, err := readConfigFile("../../../tests/configs/mock_config.json")
+               if err != nil {
+                       t.Fatal("ReadConfigurationFile: Error reading file: ", err)
+               }
+               if conf.GrpcCallTimeout != 15 || conf.GrpcConnReadyTime != 1 {
+                       t.Fatal("Bad values read for some entries")
+               }
+               isValid := isValidConfig(conf)
+               if !isValid {
+                       t.Fatal("isValidConfig returned failure for good config")
+               }
+       })
+       t.Run("Validate Bad Configuration File", func(t *testing.T) {
+               var buf bytes.Buffer
+               conf, err := readConfigFile("../../../tests/configs/mock_bad_config.json")
+               if err != nil {
+                       t.Fatal("ReadConfigurationFile: Error reading file: ", err)
+               }
+
+               log.SetOutput(&buf) // capture output in a buffer
+               defer func() {
+                       log.SetOutput(os.Stderr)
+               }()
+               isValid := isValidConfig(conf)
+               if isValid {
+                       t.Fatal("isValidConfig returned success for bad config")
+               }
+               if !strings.Contains(buf.String(), "GrpcCallTimeout") ||
+                       !strings.Contains(buf.String(), "GrpcConnReadyTime") {
+                       t.Fatal("isValidConfig did not report all offending params")
+               }
+       })
+}
@@ -7,10 +7,14 @@ import (
        "encoding/json"
        "fmt"
        "strings"
+       "sync"
+
+       pkgerrors "github.com/pkg/errors"
 )
 
 type MockConDb struct {
-       Items []map[string][]byte
+       Items []sync.Map
+       sync.Mutex
        Err   error
 }
 
@@ -21,12 +25,16 @@ func (c *MockConDb) Put(key string, value interface{}) error {
        if vg != "" {
                c.Delete(key)
        }
-       d := make(map[string][]byte)
+//     d := make(map[string][]byte)
        v, err := json.Marshal(value)
        if err != nil {
                fmt.Println("Error during json marshal")
        }
-       d[key] = v
+//     d[key] = v
+       var d sync.Map
+       d.Store(key, v)
+       c.Lock()
+       defer c.Unlock()
        c.Items = append(c.Items, d)
        return c.Err
 }
@@ -34,24 +42,39 @@ func (c *MockConDb) HealthCheck() error {
        return c.Err
 }
 func (c *MockConDb) Get(key string, value interface{}) error {
+       c.Lock()
+       defer c.Unlock()
        for _, item := range c.Items {
-               for k, v := range item {
+               d := make(map[string][]byte)
+               item.Range(func(k, v interface{}) bool {
+                       d[fmt.Sprint(k)] = v.([]byte)
+                       return true
+               })
+               for k, v := range d {
                        if k == key {
                                err := json.Unmarshal([]byte(v), value)
                                if err != nil {
-                                       fmt.Println("Error during json unmarshal")
+                                       fmt.Println("Error during json unmarshal", err, key)
                                }
                                return c.Err
                        }
                }
        }
-       value = nil
-       return c.Err
+
+       value =  nil
+       return pkgerrors.Errorf("Key doesn't exist")
 }
 func (c *MockConDb) GetAllKeys(path string) ([]string, error) {
+       c.Lock()
+       defer c.Unlock()
        n := 0
        for _, item := range c.Items {
-               for k, _ := range item {
+               d := make(map[string][]byte)
+               item.Range(func(k, v interface{}) bool {
+                       d[fmt.Sprint(k)] = v.([]byte)
+                       return true
+               })
+               for k, _ := range d {
                        ok := strings.HasPrefix(k, path)
                        if ok {
                                n++
@@ -66,7 +89,12 @@ func (c *MockConDb) GetAllKeys(path string) ([]string, error) {
 
        i := 0
        for _, item := range c.Items {
-               for k, _ := range item {
+               d := make(map[string][]byte)
+               item.Range(func(k, v interface{}) bool {
+                       d[fmt.Sprint(k)] = v.([]byte)
+                       return true
+               })
+               for k, _ := range d {
                        ok := strings.HasPrefix(k, path)
                        if ok {
                                retk[i] = k
@@ -77,8 +105,15 @@ func (c *MockConDb) GetAllKeys(path string) ([]string, error) {
        return retk, c.Err
 }
 func (c *MockConDb) Delete(key string) error {
+       c.Lock()
+       defer c.Unlock()
        for i, item := range c.Items {
-               for k, _ := range item {
+               d := make(map[string][]byte)
+               item.Range(func(k, v interface{}) bool {
+                       d[fmt.Sprint(k)] = v.([]byte)
+                       return true
+               })
+               for k, _ := range d {
                        if k == key {
                                c.Items[i] = c.Items[len(c.Items)-1]
                                c.Items = c.Items[:len(c.Items)-1]
@@ -89,8 +124,15 @@ func (c *MockConDb) Delete(key string) error {
        return c.Err
 }
 func (c *MockConDb) DeleteAll(key string) error {
+       c.Lock()
+       defer c.Unlock()
        for i, item := range c.Items {
-               for k, _ := range item {
+               d := make(map[string][]byte)
+               item.Range(func(k, v interface{}) bool {
+                       d[fmt.Sprint(k)] = v.([]byte)
+                       return true
+               })
+               for k, _ := range d {
                        ok := strings.HasPrefix(k, key)
                        if ok {
                                c.Items[i] = c.Items[len(c.Items)-1]
@@ -11,7 +11,7 @@ type Store interface {
        // Returns nil if db health is good
        HealthCheck() error
 
-       // Unmarshal implements any unmarshaling needed for the database
+       // Unmarshal implements any unmarshalling needed for the database
        Unmarshal(inp []byte, out interface{}) error
 
        // Inserts and Updates a tag with key and also adds query fields if provided
@@ -50,15 +50,15 @@ Internally this API takes all the fields in the Key structure and adds them as f
 
 With this key the document can be quried with Mongo `Find` function for both the key fields and Query fields.
 
-This API also adds another field called "Key" field to the document. The "Key" field is concatenation of the key part of the Key parameter. Internally this is used to figure out the type of the document.
+This API also adds another field called "keyId" field to the document. The "keyId" field is concatenation of the key part of the Key parameter. Internally this is used to figure out the type of the document.
 
 Assumption is that all the elememts of the key structure are strings.
 
 #### Example of Key Structure
 ```go
 type CompositeAppKey struct {
-       CompositeAppName string `json:"compositeappname"`
-       Version          string `json:"version"`
+       CompositeAppName string `json:"compositeApp"`
+       Version          string `json:"compositeAppVersion"`
        Project          string `json:"project"`
 }
 ```
@@ -81,9 +81,9 @@ type Query struct {
 ```json
 {
    "_id":"ObjectId("   "5e54c206f53ca130893c8020"   ")",
-   "compositeappname":"ca1",
+   "compositeApp":"ca1",
    "project":"testProject",
-   "version":"v1",
+   "compositeAppVersion":"v1",
    "compositeAppmetadata":{
       "metadata":{
          "name":"ca1",
@@ -92,10 +92,10 @@ type Query struct {
          "userdata2":"Data2"
       },
       "spec":{
-         "version":"v1"
+         "compositeAppVersion":"v1"
       }
    },
-   "key":"{compositeappname,project,version,}"
+   "key":"{compositeApp,compositeAppVersion,project,}"
 }
 ```
 
diff --git a/central-controller/src/vendor/gitlab.com/project-emco/core/emco-base/src/orchestrator/pkg/infra/db/db_suite_test.go b/central-controller/src/vendor/gitlab.com/project-emco/core/emco-base/src/orchestrator/pkg/infra/db/db_suite_test.go
new file mode 100644 (file)
index 0000000..61dbe51
--- /dev/null
@@ -0,0 +1,13 @@
+package db
+
+import (
+       "testing"
+
+       . "github.com/onsi/ginkgo"
+       . "github.com/onsi/gomega"
+)
+
+func TestApi(t *testing.T) {
+       RegisterFailHandler(Fail)
+       RunSpecs(t, "Api Suite")
+}
@@ -11,8 +11,9 @@ import (
 )
 
 type MockDB struct {
-       Items []map[string]map[string][]byte
-       Err   error
+       Items      []map[string]map[string][]byte
+       Err        error
+       MarshalErr error
 }
 
 func (m *MockDB) HealthCheck() error {
@@ -23,10 +24,22 @@ func (m *MockDB) Insert(table string, key Key, query interface{}, tag string, da
 
        i := make(map[string][]byte)
        out, _ := json.Marshal(data)
+
+       // store the tag
        i[tag] = out
+
        e := make(map[string]map[string][]byte)
        jkey, _ := json.Marshal(key)
        e[string(jkey)] = i
+
+       keymap := map[string]interface{}{}
+       json.Unmarshal([]byte(jkey), &keymap)
+
+       // also store all keyvalues so they can be easily retrieved by wildcarding (not just the tags)
+       for k, v := range keymap {
+               i[k], _ = json.Marshal(v)
+       }
+
        m.Items = append(m.Items, e)
        return m.Err
 }
@@ -34,9 +47,9 @@ func (m *MockDB) Insert(table string, key Key, query interface{}, tag string, da
 func (m *MockDB) Unmarshal(inp []byte, out interface{}) error {
        err := json.Unmarshal(inp, out)
        if err != nil {
-               return pkgerrors.Wrap(err, "Unmarshaling json")
+               return pkgerrors.Wrap(err, "Unmarshalling bson")
        }
-       return nil
+       return m.MarshalErr
 }
 
 func (m *MockDB) Find(table string, key Key, tag string) ([][]byte, error) {
@@ -47,6 +60,7 @@ func (m *MockDB) Find(table string, key Key, tag string) ([][]byte, error) {
        var i int
        var r [][]byte
        i = 0
+
        for _, item := range m.Items {
                for k, _ := range item {
                        s := strings.Split(str, "\"\"}")
@@ -78,8 +92,8 @@ func (m *MockDB) Find(table string, key Key, tag string) ([][]byte, error) {
                                        i++
                                }
                        } else {
-                               if str == k {
-                                       return [][]byte{v[tag]}, m.Err
+                               if str == k && v[tag] != nil {
+                                       r = append(r, v[tag])
                                }
                        }
                }
@@ -89,13 +103,16 @@ func (m *MockDB) Find(table string, key Key, tag string) ([][]byte, error) {
        } else {
                if m.Err != nil {
                        return r, m.Err
-               } else {
-                       return r, pkgerrors.New("Record not found")
                }
+               return r, nil
        }
 }
 
 func (m *MockDB) Remove(table string, key Key) error {
+       if m.Err != nil {
+               return m.Err
+       }
+
        jkey, _ := json.Marshal(key)
        str := (string(jkey))
        for i, item := range m.Items {
@@ -103,11 +120,11 @@ func (m *MockDB) Remove(table string, key Key) error {
                        if k == str {
                                m.Items[i] = m.Items[len(m.Items)-1]
                                m.Items = m.Items[:len(m.Items)-1]
-                               return m.Err
+                               return nil
                        }
                }
        }
-       return m.Err
+       return pkgerrors.New("db Remove resource not found")
 }
 
 func (m *MockDB) RemoveAll(table string, key Key) error {
diff --git a/central-controller/src/vendor/gitlab.com/project-emco/core/emco-base/src/orchestrator/pkg/infra/db/mongo.go b/central-controller/src/vendor/gitlab.com/project-emco/core/emco-base/src/orchestrator/pkg/infra/db/mongo.go
new file mode 100644 (file)
index 0000000..b5bdfc7
--- /dev/null
@@ -0,0 +1,882 @@
+// SPDX-License-Identifier: Apache-2.0
+// Copyright (c) 2020 Intel Corporation
+
+package db
+
+import (
+       "encoding/json"
+       "fmt"
+       "os"
+       "reflect"
+       "sort"
+       "strings"
+
+       "golang.org/x/net/context"
+
+       "github.com/tidwall/gjson"
+       "gitlab.com/project-emco/core/emco-base/src/orchestrator/pkg/infra/config"
+       log "gitlab.com/project-emco/core/emco-base/src/orchestrator/pkg/infra/logutils"
+       utils "gitlab.com/project-emco/core/emco-base/src/orchestrator/pkg/infra/utils"
+
+       pkgerrors "github.com/pkg/errors"
+       "go.mongodb.org/mongo-driver/bson"
+       "go.mongodb.org/mongo-driver/bson/primitive"
+       "go.mongodb.org/mongo-driver/mongo"
+       "go.mongodb.org/mongo-driver/mongo/options"
+)
+
+// MongoCollection defines the a subset of MongoDB operations
+// Note: This interface is defined mainly for mock testing
+type MongoCollection interface {
+       InsertOne(ctx context.Context, document interface{},
+               opts ...*options.InsertOneOptions) (*mongo.InsertOneResult, error)
+       FindOne(ctx context.Context, filter interface{},
+               opts ...*options.FindOneOptions) *mongo.SingleResult
+       FindOneAndUpdate(ctx context.Context, filter interface{},
+               update interface{}, opts ...*options.FindOneAndUpdateOptions) *mongo.SingleResult
+       DeleteOne(ctx context.Context, filter interface{},
+               opts ...*options.DeleteOptions) (*mongo.DeleteResult, error)
+       DeleteMany(ctx context.Context, filter interface{},
+               opts ...*options.DeleteOptions) (*mongo.DeleteResult, error)
+       Find(ctx context.Context, filter interface{},
+               opts ...*options.FindOptions) (*mongo.Cursor, error)
+       UpdateOne(ctx context.Context, filter interface{}, update interface{},
+               opts ...*options.UpdateOptions) (*mongo.UpdateResult, error)
+       CountDocuments(ctx context.Context, filter interface{},
+               opts ...*options.CountOptions) (int64, error)
+}
+
+// MongoStore is an implementation of the db.Store interface
+type MongoStore struct {
+       db *mongo.Database
+}
+
+// This exists only for allowing us to mock the collection object
+// for testing purposes
+var getCollection = func(coll string, m *MongoStore) MongoCollection {
+       return m.db.Collection(coll)
+}
+
+// This exists only for allowing us to mock the DecodeBytes function
+// Mainly because we cannot construct a SingleResult struct from our
+// tests. All fields in that struct are private.
+var decodeBytes = func(sr *mongo.SingleResult) (bson.Raw, error) {
+       return sr.DecodeBytes()
+}
+
+// These exists only for allowing us to mock the cursor.Next function
+// Mainly because we cannot construct a mongo.Cursor struct from our
+// tests. All fields in that struct are private and there is no public
+// constructor method.
+var cursorNext = func(ctx context.Context, cursor *mongo.Cursor) bool {
+       return cursor.Next(ctx)
+}
+var cursorClose = func(ctx context.Context, cursor *mongo.Cursor) error {
+       return cursor.Close(ctx)
+}
+
+// NewMongoStore initializes a Mongo Database with the name provided
+// If a database with that name exists, it will be returned
+func NewMongoStore(name string, store *mongo.Database) (Store, error) {
+       if store == nil {
+               ip := "mongodb://" + config.GetConfiguration().DatabaseIP + ":27017"
+               clientOptions := options.Client()
+               clientOptions.ApplyURI(ip)
+               if len(os.Getenv("DB_EMCO_USERNAME")) > 0 && len(os.Getenv("DB_EMCO_PASSWORD")) > 0 {
+                       fmt.Println(os.Getenv("DB_EMCO_USERNAME"))
+                       fmt.Println(os.Getenv("DB_EMCO_PASSWORD"))
+                       clientOptions.SetAuth(options.Credential{
+                               AuthMechanism: "SCRAM-SHA-256",
+//                             AuthSource:    "emco",
+                               AuthSource:    "scc",
+                               Username:      os.Getenv("DB_EMCO_USERNAME"),
+                               Password:      os.Getenv("DB_EMCO_PASSWORD")})
+               }
+               mongoClient, err := mongo.NewClient(clientOptions)
+               if err != nil {
+                       return nil, err
+               }
+
+               err = mongoClient.Connect(context.Background())
+               if err != nil {
+                       return nil, err
+               }
+               store = mongoClient.Database(name)
+       }
+
+       // make the MongoStore struct hear and then call schema stuff here
+       mongoStore := &MongoStore{
+               db: store,
+       }
+
+       go mongoStore.ReadRefSchema()
+
+       return mongoStore, nil
+}
+
+// HealthCheck verifies if the database is up and running
+func (m *MongoStore) HealthCheck() error {
+
+       _, err := decodeBytes(m.db.RunCommand(context.Background(), bson.D{{"serverStatus", 1}}))
+       if err != nil {
+               return pkgerrors.Wrap(err, "Error getting server status")
+       }
+
+       return nil
+}
+
+// findReferencedBys will search to see if this resource (identified by the key) is
+// referenced by any other resources.
+func (m *MongoStore) findReferencedBys(c MongoCollection, key Key) (int64, error) {
+
+       // Create the key tag value for this resource (i.e. resource identifier)
+       keyId, err := m.createKeyIdField(key)
+       if err != nil {
+               return 0, err
+       }
+
+       // set up the filter to search for this resource in references arrays in other documents
+       filter, err := m.findRefByFilter(keyId, key)
+       if err != nil {
+               return 0, err
+       }
+
+       // search for documents with this resource in their resources list
+       count, err := c.CountDocuments(context.Background(), filter)
+       if err != nil {
+               return 0, err
+       }
+       if count > 0 {
+               return count, nil
+       }
+
+       return 0, nil
+}
+
+// findMapKeyValues will create a list of keys (with elements defined in "inKey") where the key elements that
+// match "resName" will be filled in with the values of the keys from the map `mapName` in the "spec" object of "data"
+func findMapKeyValues(inKey map[string]struct{}, mapName, resName string, data interface{}) ([]map[string]string, error) {
+       var iterateSpec func(key, value gjson.Result) bool
+
+       var targetMap gjson.Result
+
+       iterateSpec = func(key, value gjson.Result) bool {
+               if value.Type == gjson.JSON {
+                       if key.String() == mapName {
+                               targetMap = value
+                               return false
+                       }
+               }
+               return true
+       }
+
+       jsonData, err := json.Marshal(data)
+       if err != nil {
+               return nil, pkgerrors.Wrap(err, "Error marshalling data for key value search")
+       }
+       spec := gjson.GetBytes(jsonData, "spec")
+       spec.ForEach(iterateSpec)
+
+       results := make([]map[string]string, 0)
+       for k, _ := range targetMap.Map() {
+               m := make(map[string]string)
+               for ki, _ := range inKey {
+                       if ki == resName {
+                               m[ki] = k
+                       } else {
+                               m[ki] = ""
+                       }
+               }
+               results = append(results, m)
+       }
+       return results, nil
+}
+
+// findManyKeyValues will scan the "spec" object inside "data" and return a list of
+// keys (with elements defined in "inKey").  At each nesting level of the "spec" object,
+// all string elements which elements in "inKey" will be used to create a key instance.
+func findManyKeyValues(inKey map[string]struct{}, data interface{}) ([]map[string]string, error) {
+       var iterateSpec func(key, value gjson.Result) bool
+
+       maps := make(map[int]map[string]string)
+
+       jsonObj := 0
+       iterateSpec = func(key, value gjson.Result) bool {
+               if value.Type == gjson.String {
+                       if _, ok := inKey[key.String()]; ok {
+                               var m map[string]string
+                               if m, ok = maps[jsonObj]; !ok {
+                                       m = make(map[string]string)
+                               }
+                               m[key.String()] = value.String()
+                               maps[jsonObj] = m
+                       }
+               }
+               if value.Type == gjson.JSON {
+                       jsonObj++
+                       value.ForEach(iterateSpec)
+               }
+               return true
+       }
+
+       jsonData, err := json.Marshal(data)
+       if err != nil {
+               return nil, pkgerrors.Wrap(err, "Error marshalling data for key value search")
+       }
+       spec := gjson.GetBytes(jsonData, "spec")
+       spec.ForEach(iterateSpec)
+
+       results := make([]map[string]string, 0)
+       for _, m := range maps {
+               // fill out rest of the each result map with empty string values
+               for k, _ := range inKey {
+                       if _, ok := m[k]; !ok {
+                               m[k] = ""
+                       }
+               }
+               results = append(results, m)
+       }
+       return results, nil
+}
+
+// findKeyValues will scan the "spec" object of "data" and create a key instance.
+// Any element that matches an element in "inKey" and is also not present in "filterKey"
+// will be added to the key.
+func findKeyValues(inKey, filterKey map[string]struct{}, data interface{}) (map[string]string, error) {
+       var iterateSpec func(key, value gjson.Result) bool
+
+       result := make(map[string]string)
+
+       iterateSpec = func(key, value gjson.Result) bool {
+               if value.Type == gjson.String {
+                       if _, ok := inKey[key.String()]; ok {
+                               if _, fok := filterKey[key.String()]; !fok {
+                                       result[key.String()] = value.String()
+                               }
+                       }
+               }
+               if value.Type == gjson.JSON {
+                       value.ForEach(iterateSpec)
+               }
+               return true
+       }
+
+       jsonData, err := json.Marshal(data)
+       if err != nil {
+               return nil, pkgerrors.Wrap(err, "Error marshalling data for key value search")
+       }
+       spec := gjson.GetBytes(jsonData, "spec")
+       spec.ForEach(iterateSpec)
+
+       // fill out rest of the new result key with empty string values
+       for k, _ := range inKey {
+               if _, ok := result[k]; !ok {
+                       result[k] = ""
+               }
+       }
+       return result, nil
+}
+
+// verifyReferences checks that all references for a resource exist.
+// 1. The parent resource, as defined by the schema, is checked.
+// 2. The keys for other references, as identified for the schema, are found
+//    by searching the "spec" object of the resource "data".
+//    These references are then verified to exist.
+func (m *MongoStore) verifyReferences(coll string, key Key, keyId string, data interface{}) ([]ReferenceEntry, error) {
+
+       // make a references slice to store keys of any references found
+       refs := make([]ReferenceEntry, 0)
+
+       schemaLock.Lock()
+
+       // Check if this item is present in the referential schema
+       name, ok := refKeyMap[keyId]
+       if !ok {
+               schemaLock.Unlock()
+               log.Info("Resource key ID is not present in referential schema", log.Fields{"keyId": keyId})
+               return refs, pkgerrors.Errorf("Resource key ID is not present in referential schema. KeyID: %s, Key: %T %v", keyId, key, key)
+       }
+
+       resEntry, ok := refSchemaMap[name]
+       if !ok {
+               schemaLock.Unlock()
+               log.Info("Resource is not present in referential schema", log.Fields{"name": name})
+               return refs, pkgerrors.Errorf("Resource is not present in referential schema. Name: %s, KeyID: %s, Key: %T %v", name, keyId, key, key)
+       }
+
+       schemaLock.Unlock()
+
+       // make a map[string]string copy of the key
+       var rKey map[string]string
+       st, err := json.Marshal(key)
+       if err != nil {
+               return refs, pkgerrors.Wrapf(err, "Error Marshalling key: %T %v", key, key)
+       }
+
+       err = json.Unmarshal([]byte(st), &rKey)
+       if err != nil {
+               return refs, pkgerrors.Wrapf(err, "Error Unmarshalling key to map. Key: %T %v", key, key)
+       }
+
+       // Check parent resource reference (if the resource has a parent)
+       if len(resEntry.parent) > 0 {
+               parentKey := make(map[string]string)
+
+               // make the parent key
+               for k, v := range rKey {
+                       if k == name {
+                               continue
+                       }
+                       if resEntry.trimParent && k == resEntry.parent {
+                               continue
+                       }
+                       parentKey[k] = v
+               }
+
+               // if no parent key is left, then no need to check for parent resource
+               if len(parentKey) > 0 {
+                       // All resources should have a "data" element, so search for the parents "data"
+                       result, err := m.Find(coll, parentKey, "data")
+                       if err != nil {
+                               return refs, pkgerrors.Wrapf(err, "Error finding parent resource for %s. Parent: %T %v", name, parentKey, parentKey)
+                       }
+
+                       if len(result) == 0 {
+                               return refs, pkgerrors.Errorf("Parent resource not found for %s.  Parent: %T %v KeyID: %s, Key: %T %v", name, parentKey, parentKey, keyId, key, key)
+                       }
+               }
+       }
+
+       // Collect the list of referenced resources
+       for _, r := range resEntry.references {
+               keys := make([]Key, 0)
+               refKey := refSchemaMap[r.Name].keyMap
+
+               switch r.Type {
+               case "map":
+                       manyKeys, err := findMapKeyValues(refKey, r.Map, r.Name, data)
+                       if err != nil {
+                               return refs, err
+                       }
+                       for _, nk := range manyKeys {
+                               // fill in any fixed entries as defined by the referential schema
+                               for k, v := range r.FixedKv {
+                                       nk[k] = v
+                               }
+                               // check if this key should be filtered
+                               filter := false
+                               for _, f := range r.FilterKeys {
+                                       for k, v := range nk {
+                                               if k == r.Name && v == f {
+                                                       filter = true
+                                                       break
+                                               }
+                                       }
+                               }
+                               if !filter {
+                                       keys = append(keys, nk)
+                               }
+                       }
+               case "many":
+                       manyKeys, err := findManyKeyValues(refKey, data)
+                       if err != nil {
+                               return refs, err
+                       }
+                       for _, nk := range manyKeys {
+                               // fill in any fixed entries as defined by the referential schema
+                               for k, v := range r.FixedKv {
+                                       nk[k] = v
+                               }
+                               // fill out rest of key with this resource key
+                               // if items in key are not found, then drop this reference key
+                               // (only keep fully populated keys)
+                               fullKey := true
+                               for k, v := range nk {
+                                       if v == "" {
+                                               if _, ok := rKey[k]; !ok {
+                                                       fullKey = false
+                                               }
+                                               nk[k] = rKey[k]
+                                       }
+                               }
+                               if fullKey {
+                                       // check if nk is already in the list (prevent duplicates)
+                                       found := false
+                                       for _, m := range keys {
+                                               found = reflect.DeepEqual(m, nk)
+                                               if found {
+                                                       break
+                                               }
+                                       }
+                                       if !found {
+                                               keys = append(keys, nk)
+                                       }
+                               }
+                       }
+               default:
+                       // prepare a filter key (items to not fill out if found in the "spec" object)
+                       var filterKey map[string]struct{}
+                       if cResEntry, ok := refSchemaMap[r.CommonKey]; ok {
+                               filterKey = cResEntry.keyMap
+                       } else {
+                               filterKey = make(map[string]struct{})
+                       }
+
+                       nk, err := findKeyValues(refKey, filterKey, data)
+                       if err != nil {
+                               return refs, err
+                       }
+                       // fill in any fixed entries as defined by the referential schema
+                       for k, v := range r.FixedKv {
+                               nk[k] = v
+                       }
+                       // fill out rest of the reference key with elements from the current resource key
+                       fullKey := true
+                       for k, v := range nk {
+                               if v == "" {
+                                       if _, ok := rKey[k]; !ok {
+                                               fullKey = false
+                                               log.Info("Reference key element not found", log.Fields{"resource": name, "key": nk, "element": k})
+                                       }
+                                       nk[k] = rKey[k]
+                               }
+                       }
+                       if fullKey {
+                               keys = append(keys, nk)
+                       }
+               }
+
+               for _, k := range keys {
+                       ref := ReferenceEntry{Key: k, KeyId: refSchemaMap[r.Name].keyId}
+                       refs = append(refs, ref)
+               }
+       }
+
+       // Verify that referenced resources exist
+       for _, ref := range refs {
+               result, err := m.Find(coll, ref.Key, "data")
+               if err != nil {
+                       log.Warn("Error finding resource reference", log.Fields{"resource": name, "referenceKey": ref.Key})
+                       /* For now, just log a warning if there was an error finding the referenced resource.
+                        * return refs, pkgerrors.Errorf("Error finding referenced resource: [%v] for [%s]", ref.KeyId, name)
+                        */
+               } else if len(result) == 0 {
+                       log.Warn("Resource reference not found", log.Fields{"resource": name, "referenceKey": ref.Key})
+                       /* For now, just log a warning if the referenced resource does not exist.
+                        * return refs, pkgerrors.New("Referenced resource not found: [" + ref.KeyId + "] for [" + name + "]")
+                        */
+               }
+       }
+
+       return refs, nil
+}
+
+// validateParams checks to see if any parameters are empty
+func (m *MongoStore) validateParams(args ...interface{}) bool {
+       for _, v := range args {
+               val, ok := v.(string)
+               if ok {
+                       if val == "" {
+                               return false
+                       }
+               } else {
+                       if v == nil {
+                               return false
+                       }
+               }
+       }
+
+       return true
+}
+
+// Unmarshal implements an unmarshaler for bson data that
+// is produced from the mongo database
+func (m *MongoStore) Unmarshal(inp []byte, out interface{}) error {
+       err := bson.Unmarshal(inp, out)
+       if err != nil {
+               return pkgerrors.Wrapf(err, "Error Unmarshalling bson data to %T", out)
+       }
+
+       // Decrypt data if required
+       oe := utils.GetObjectEncryptor("emco")
+       if oe != nil {
+               _, err := oe.DecryptObject(out)
+               if err != nil {
+                       log.Warn("Error to decrypt object", log.Fields{"error": err.Error()})
+               }
+       }
+       return nil
+}
+
+func (m *MongoStore) findFilter(key Key) (primitive.M, error) {
+
+       var bsonMap bson.M
+       st, err := json.Marshal(key)
+       if err != nil {
+               return primitive.M{}, pkgerrors.Errorf("Error Marshalling key: %s", err.Error())
+       }
+       err = json.Unmarshal([]byte(st), &bsonMap)
+       if err != nil {
+               return primitive.M{}, pkgerrors.Errorf("Error Unmarshalling key to Bson Map: %s", err.Error())
+       }
+       filter := bson.M{
+               "$and": []bson.M{bsonMap},
+       }
+       return filter, nil
+}
+
+// findRefByFilter creates a filter based on the key and keyId of a resource
+// that can match an element in the "references" list.
+func (m *MongoStore) findRefByFilter(keyId string, key Key) (primitive.M, error) {
+
+       var bsonMap bson.M
+       var bsonMapFinal bson.M
+       st, err := json.Marshal(key)
+       if err != nil {
+               return primitive.M{}, pkgerrors.Errorf("Error Marshalling key: %s", err.Error())
+       }
+       err = json.Unmarshal([]byte(st), &bsonMap)
+       if err != nil {
+               return primitive.M{}, pkgerrors.Errorf("Error Unmarshalling key to Bson Map: %s", err.Error())
+       }
+       bsonMapFinal = make(bson.M)
+       for k, v := range bsonMap {
+               if v != "" {
+                       bsonMapFinal["key."+k] = v
+               }
+       }
+       bsonMapFinal["keyid"] = keyId
+       filter := bson.M{"references": bson.M{"$elemMatch": bsonMapFinal}}
+       return filter, nil
+}
+
+func (m *MongoStore) findFilterWithKey(key Key) (primitive.M, error) {
+
+       var bsonMap bson.M
+       var bsonMapFinal bson.M
+       st, err := json.Marshal(key)
+       if err != nil {
+               return primitive.M{}, pkgerrors.Errorf("Error Marshalling key: %s", err.Error())
+       }
+       err = json.Unmarshal([]byte(st), &bsonMap)
+       if err != nil {
+               return primitive.M{}, pkgerrors.Errorf("Error Unmarshalling key to Bson Map: %s", err.Error())
+       }
+       bsonMapFinal = make(bson.M)
+       for k, v := range bsonMap {
+               if v == "" {
+                       if _, ok := bsonMapFinal["keyId"]; !ok {
+                               // add type of key to filter
+                               keyId, err := m.createKeyIdField(key)
+                               if err != nil {
+                                       return primitive.M{}, err
+                               }
+                               bsonMapFinal["keyId"] = keyId
+                       }
+               } else {
+                       bsonMapFinal[k] = v
+               }
+       }
+       filter := bson.M{
+               "$and": []bson.M{bsonMapFinal},
+       }
+       return filter, nil
+}
+
+func (m *MongoStore) updateFilter(key interface{}) (primitive.M, error) {
+
+       var n map[string]string
+
+       st, err := json.Marshal(key)
+       if err != nil {
+               return primitive.M{}, pkgerrors.Wrapf(err, "Error Marshalling key: %T %v", key, key)
+       }
+
+       err = json.Unmarshal([]byte(st), &n)
+       if err != nil {
+               return primitive.M{}, pkgerrors.Wrapf(err, "Error Unmarshalling key to Bson Map. Key: %T %v", key, key)
+       }
+
+       p := make(bson.M, len(n))
+       for k, v := range n {
+               p[k] = v
+       }
+
+       filter := bson.M{
+               "$set": p,
+       }
+       return filter, nil
+}
+
+func (m *MongoStore) createKeyIdField(key interface{}) (string, error) {
+
+       var n map[string]string
+       st, err := json.Marshal(key)
+       if err != nil {
+               return "", pkgerrors.Errorf("Error Marshalling key: %s", err.Error())
+       }
+       err = json.Unmarshal([]byte(st), &n)
+       if err != nil {
+               return "", pkgerrors.Errorf("Error Unmarshalling key to Bson Map: %s", err.Error())
+       }
+       var keys []string
+       for k := range n {
+               keys = append(keys, k)
+       }
+       sort.Strings(keys)
+
+       return fmt.Sprintf("{%s}", strings.Join(keys, ",")), nil
+}
+
+// Insert is used to insert/add element to a document
+func (m *MongoStore) Insert(coll string, key Key, query interface{}, tag string, data interface{}) error {
+
+       if data == nil {
+               return pkgerrors.Errorf("db Insert error: No data to store")
+       }
+
+       if !m.validateParams(coll, key, tag) {
+               return pkgerrors.Errorf("db Insert error: Mandatory fields are missing. Collection: %s, Key: %T %v, Tag: %s", coll, key, key, tag)
+       }
+
+       c := getCollection(coll, m)
+       ctx := context.Background()
+
+       filter, err := m.findFilter(key)
+       if err != nil {
+               return pkgerrors.Wrapf(err, "db Insert error: Error finding filter with key %T %v", key, key)
+       }
+
+       // Create and add keyId tag
+       keyId, err := m.createKeyIdField(key)
+       if err != nil {
+               return pkgerrors.Wrapf(err, "db Insert error: Error creating KeyID with key %T %v", key, key)
+       }
+
+       // Encrypt data if required
+       oe := utils.GetObjectEncryptor("emco")
+       if oe != nil {
+               var edata interface{}
+               if reflect.TypeOf(data).Kind() == reflect.Ptr {
+                       // avoid changing data's field value during encryption
+                       edata, err = oe.EncryptObject(reflect.ValueOf(data).Elem().Interface())
+               } else {
+                       edata, err = oe.EncryptObject(data)
+               }
+
+               if err == nil {
+                       data = edata
+               } else {
+                       log.Warn("Error to encrypt object", log.Fields{"collection": coll, "tag": tag})
+               }
+       }
+
+       // verify references for Inserts with the "data" tag
+       refs := make([]ReferenceEntry, 0)
+
+       if tag == "data" {
+               refs, err = m.verifyReferences(coll, key, keyId, data)
+               if err != nil {
+                       if strings.Contains(err.Error(), "Parent resource not found") {
+                               // these errors should be handled separately, not as an internal server error
+                               return pkgerrors.Wrapf(err, "db Insert parent resource not found")
+                       }
+
+                       if strings.Contains(err.Error(), "is not present in referential schema") {
+                               // these errors should be handled separately, not as an internal server error
+                               return pkgerrors.Wrapf(err, "db Insert referential schema missing")
+
+                       }
+
+                       return pkgerrors.Wrapf(err, "db Insert error: Error verifying the references. Collection: %s, Key: %T %v, KeyID: %s", coll, key, key, keyId)
+               }
+
+               _, err = decodeBytes(
+                       c.FindOneAndUpdate(
+                               ctx,
+                               filter,
+                               bson.D{
+                                       {"$set", bson.D{
+                                               {tag, data},
+                                               {"keyId", keyId},
+                                               {"references", refs},
+                                       }},
+                               },
+                               options.FindOneAndUpdate().SetUpsert(true).SetReturnDocument(options.After)))
+       } else {
+               _, err = decodeBytes(
+                       c.FindOneAndUpdate(
+                               ctx,
+                               filter,
+                               bson.D{
+                                       {"$set", bson.D{
+                                               {tag, data},
+                                               {"keyId", keyId},
+                                       }},
+                               },
+                               options.FindOneAndUpdate().SetUpsert(true).SetReturnDocument(options.After)))
+       }
+
+       if err != nil {
+               return pkgerrors.Wrapf(err, "db Insert error")
+       }
+
+       if query == nil {
+               return nil
+       }
+
+       // Update to add Query fields
+       update, err := m.updateFilter(query)
+       if err != nil {
+               return pkgerrors.Wrapf(err, "db Insert error: Error updating filter with query %T %v", query, query)
+       }
+
+       _, err = c.UpdateOne(
+               ctx,
+               filter,
+               update)
+       if err != nil {
+               return pkgerrors.Wrapf(err, "db Insert error")
+       }
+
+       return nil
+}
+
+// Find method returns the data stored for this key and for this particular tag
+func (m *MongoStore) Find(coll string, key Key, tag string) ([][]byte, error) {
+
+       //result, err := m.findInternal(coll, key, tag, "")
+       //return result, err
+       if !m.validateParams(coll, key, tag) {
+               return nil, pkgerrors.Errorf("db Find error: Mandatory fields are missing. Collection: %s, Key: %T %v, Tag: %s", coll, key, key, tag)
+       }
+
+       c := getCollection(coll, m)
+       ctx := context.Background()
+
+       filter, err := m.findFilterWithKey(key)
+       if err != nil {
+               return nil, pkgerrors.Wrapf(err, "db Find error: Error finding filter with key %T %v", key, key)
+       }
+       // Find only the field requested
+       projection := bson.D{
+               {tag, 1},
+               {"_id", 0},
+       }
+
+       cursor, err := c.Find(context.Background(), filter, options.Find().SetProjection(projection))
+       if err != nil {
+               return nil, pkgerrors.Wrap(err, "db Find error")
+       }
+       defer cursorClose(ctx, cursor)
+       var data []byte
+       var result [][]byte
+       for cursorNext(ctx, cursor) {
+               d := cursor.Current
+               switch d.Lookup(tag).Type {
+               case bson.TypeString:
+                       data = []byte(d.Lookup(tag).StringValue())
+               default:
+                       r, err := d.LookupErr(tag)
+                       if err != nil {
+                               // Throw error if not found
+                               pkgerrors.New("db Find error: Unable to read data")
+                       }
+                       data = r.Value
+               }
+               result = append(result, data)
+       }
+       return result, nil
+}
+
+// RemoveAll method to removes all the documet matching key
+func (m *MongoStore) RemoveAll(coll string, key Key) error {
+       if !m.validateParams(coll, key) {
+               return pkgerrors.Errorf("db Remove error: Mandatory fields are missing. Collection: %s, Key: %T %v", coll, key, key)
+       }
+       c := getCollection(coll, m)
+       ctx := context.Background()
+       filter, err := m.findFilterWithKey(key)
+       if err != nil {
+               return pkgerrors.Wrapf(err, "db Remove error: Error finding filter with key %T %v", key, key)
+       }
+       _, err = c.DeleteMany(ctx, filter)
+       if err != nil {
+               return pkgerrors.Wrapf(err, "db Remove error: Error deleting document(s) from database. Key: %T %v, Filter: %v", key, key, filter)
+       }
+       return nil
+}
+
+// Remove method to remove the documet by key if no child references
+func (m *MongoStore) Remove(coll string, key Key) error {
+       if !m.validateParams(coll, key) {
+               return pkgerrors.Errorf("db Remove error: Mandatory fields are missing. Collection: %s, Key: %T %v", coll, key, key)
+       }
+
+       // search for child references - assumes all children are part of the
+       // same collection
+       c := getCollection(coll, m)
+       ctx := context.Background()
+       filter, err := m.findFilter(key)
+       if err != nil {
+               return pkgerrors.Wrapf(err, "db Remove error: Error finding filter with key %T %v", key, key)
+       }
+
+       count, err := c.CountDocuments(context.Background(), filter)
+       if err != nil {
+               return pkgerrors.Wrap(err, "db Remove error")
+       }
+
+       if count == 0 {
+               return pkgerrors.Errorf("db Remove resource not found: The requested resource not found. Key: %T %v", key, key)
+       }
+
+       if count > 1 {
+               return pkgerrors.Errorf("db Remove parent child constraint: Cannot delete parent without deleting child references first. Key: %T %v", key, key)
+       }
+
+       // search to see if this document is referenced by any other document
+       count, err = m.findReferencedBys(c, key)
+       if err != nil {
+               return pkgerrors.Wrapf(err, "db Remove error: Error finding referencing resources for key %T %v", key, key)
+       }
+
+       if count > 0 {
+               return pkgerrors.Errorf("db Remove referential constraint: Cannot delete without deleting or updating referencing resources first. Key: %T %v", key, key)
+       }
+
+       // ok to delete the document
+       _, err = c.DeleteOne(ctx, filter)
+       if err != nil {
+               return pkgerrors.Wrapf(err, "db Remove error: Error deleting document from database. Key: %T %v, Filter: %v", key, key, filter)
+       }
+       return nil
+}
+
+// RemoveTag is used to remove an element from a document
+func (m *MongoStore) RemoveTag(coll string, key Key, tag string) error {
+       c := getCollection(coll, m)
+       ctx := context.Background()
+
+       filter, err := m.findFilter(key)
+       if err != nil {
+               return err
+       }
+
+       _, err = decodeBytes(
+               c.FindOneAndUpdate(
+                       ctx,
+                       filter,
+                       bson.D{
+                               {"$unset", bson.D{
+                                       {tag, ""},
+                               }},
+                       },
+                       options.FindOneAndUpdate().SetUpsert(true).SetReturnDocument(options.After)))
+
+       if err != nil {
+               return pkgerrors.Errorf("Error removing tag: %s", err.Error())
+       }
+
+       return nil
+}
diff --git a/central-controller/src/vendor/gitlab.com/project-emco/core/emco-base/src/orchestrator/pkg/infra/db/newmock.go b/central-controller/src/vendor/gitlab.com/project-emco/core/emco-base/src/orchestrator/pkg/infra/db/newmock.go
new file mode 100644 (file)
index 0000000..6e0be3a
--- /dev/null
@@ -0,0 +1,177 @@
+// SPDX-License-Identifier: Apache-2.0
+// Copyright (c) 2020 Intel Corporation
+
+package db
+
+import (
+       "encoding/json"
+       "sort"
+
+       pkgerrors "github.com/pkg/errors"
+)
+
+type NewMockDB struct {
+       Items      []map[string]map[string][]byte
+       Err        error
+       MarshalErr error
+}
+
+func (m *NewMockDB) HealthCheck() error {
+       return m.Err
+}
+
+func createKeyField(key interface{}) (string, error) {
+
+       var n map[string]string
+       st, err := json.Marshal(key)
+       if err != nil {
+               return "", pkgerrors.Errorf("Error Marshalling key: %s", err.Error())
+       }
+       err = json.Unmarshal([]byte(st), &n)
+       if err != nil {
+               return "", pkgerrors.Errorf("Error Unmarshalling key to Bson Map: %s", err.Error())
+       }
+       var keys []string
+       for k := range n {
+               keys = append(keys, k)
+       }
+       sort.Strings(keys)
+       s := "{"
+       for _, k := range keys {
+               s = s + k + ","
+       }
+       s = s + "}"
+       return s, nil
+}
+
+func (m *NewMockDB) Insert(table string, key Key, query interface{}, tag string, data interface{}) error {
+
+       i := make(map[string][]byte)
+       out, _ := json.Marshal(data)
+
+       // store the tag
+       i[tag] = out
+
+       e := make(map[string]map[string][]byte)
+       jkey, _ := json.Marshal(key)
+       e[string(jkey)] = i
+
+       keymap := map[string]interface{}{}
+       json.Unmarshal([]byte(jkey), &keymap)
+
+       // also store all keyvalues so they can be easily retrieved by wildcarding (not just the tags)
+       for k, v := range keymap {
+               i[k], _ = json.Marshal(v)
+       }
+       // add the "type" key
+       tkey, _ := createKeyField(key)
+       i["key"], _ = json.Marshal(tkey)
+
+       // add any extra query key/pair values if supplied
+       if query != nil {
+               qkey, _ := json.Marshal(query)
+               qkeymap := map[string]interface{}{}
+               json.Unmarshal([]byte(qkey), &qkeymap)
+               for k, v := range qkeymap {
+                       i[k], _ = json.Marshal(v)
+               }
+       }
+
+       m.Items = append(m.Items, e)
+       return m.Err
+}
+
+func (m *NewMockDB) Unmarshal(inp []byte, out interface{}) error {
+       err := json.Unmarshal(inp, out)
+       if err != nil {
+               return pkgerrors.Wrapf(err, "Error Unmarshalling bson data to %T", out)
+       }
+       return m.MarshalErr
+}
+
+func (m *NewMockDB) Find(table string, key Key, tag string) ([][]byte, error) {
+
+       tkey, _ := createKeyField(key)
+
+       newr := make([][]byte, 0)
+
+       // Make match key
+       matchkey := make(map[string]string)
+       var n map[string]string
+       st, _ := json.Marshal(key)
+       json.Unmarshal([]byte(st), &n)
+       wildmatch := 0
+       for k, v := range n {
+               if v == "" {
+                       wildmatch++
+               } else {
+                       matchkey[k] = v
+               }
+       }
+       if wildmatch > 0 {
+               matchkey["key"] = tkey
+       }
+
+       cnt := 0
+       for _, item := range m.Items {
+               for _, v := range item {
+                       // check if matchkey matches this item
+                       notfound := false
+                       for mk, mv := range matchkey {
+                               var iv []byte
+                               var ok bool
+                               if iv, ok = v[mk]; !ok {
+                                       notfound = true
+                                       break
+                               }
+                               var siv string
+                               json.Unmarshal(iv, &siv)
+                               if mv != siv {
+                                       notfound = true
+                                       break
+                               }
+                       }
+                       if notfound {
+                               break
+                       }
+
+                       // this items key matches - add to the return list if tag is present
+                       if _, ok := v[tag]; ok {
+                               newr = append(newr, v[tag])
+                               cnt++
+                       }
+               }
+       }
+       if cnt > 0 {
+               return newr, m.Err
+       } else {
+               if m.Err != nil {
+                       return newr, m.Err
+               } else {
+                       return newr, nil
+               }
+       }
+}
+
+func (m *NewMockDB) Remove(table string, key Key) error {
+       jkey, _ := json.Marshal(key)
+       str := (string(jkey))
+       for i, item := range m.Items {
+               for k, _ := range item {
+                       if k == str {
+                               m.Items[i] = m.Items[len(m.Items)-1]
+                               m.Items = m.Items[:len(m.Items)-1]
+                               return m.Err
+                       }
+               }
+       }
+       return m.Err
+}
+
+func (m *NewMockDB) RemoveAll(table string, key Key) error {
+       return m.Err
+}
+
+func (m *NewMockDB) RemoveTag(table string, key Key, tag string) error {
+       return m.Err
+}
diff --git a/central-controller/src/vendor/gitlab.com/project-emco/core/emco-base/src/orchestrator/pkg/infra/db/schema.go b/central-controller/src/vendor/gitlab.com/project-emco/core/emco-base/src/orchestrator/pkg/infra/db/schema.go
new file mode 100644 (file)
index 0000000..ed188cf
--- /dev/null
@@ -0,0 +1,562 @@
+// SPDX-License-Identifier: Apache-2.0
+// Copyright (c) 2021 Intel Corporation
+
+package db
+
+import (
+       "crypto/sha256"
+       "encoding/json"
+       "fmt"
+       "io/ioutil"
+       "os"
+       "regexp"
+       "sort"
+       "strings"
+       "sync"
+       "time"
+
+       pkgerrors "github.com/pkg/errors"
+       "gitlab.com/project-emco/core/emco-base/src/orchestrator/pkg/infra/config"
+       log "gitlab.com/project-emco/core/emco-base/src/orchestrator/pkg/infra/logutils"
+       "gopkg.in/yaml.v3"
+)
+
+var (
+       // refKeyMap maps the keyId to the name of a resource
+       // keyId represents the name of the Keyspace the referential constraint belongs.
+       refKeyMap map[string]string
+
+       // refSchemaMap is a map of the schema setup for convenient reference
+       // by the DB interface functions to identify and manage dependencies.
+       refSchemaMap map[string]ReferentialSchema
+
+       refSchemaFile string = "ref-schemas/v1.yaml"
+       schemaLock           = &sync.Mutex{}
+)
+
+type ReferenceEntry struct {
+       Key   Key
+       KeyId string
+}
+
+// ReferenceSchema defines the structure of a reference entry in the referential schema.
+type ReferenceSchema struct {
+       Name       string            `yaml:"name"`
+       Type       string            `yaml:"type"`       // can be not present or "map" or "many"
+       CommonKey  string            `yaml:"commonKey"`  // optional to disambiguate - part of reference key that is common
+       Map        string            `yaml:"map"`        // if Type is "map", this is JSON tag of the Map object
+       FixedKv    map[string]string `yaml:"fixedKv"`    // Key/Values of referenced resource that are known at compile time
+       FilterKeys []string          `yaml:"filterKeys"` // if "map" type, list of keys to filter (not count as references)
+}
+
+// ResourceSchema defines the structure of a data resource in the referential schema.
+type ResourceSchema struct {
+       Name       string            `yaml:"name"`
+       Parent     string            `yaml:"parent"`
+       References []ReferenceSchema `yaml:"references"` // if present, overrides default resource id
+}
+
+// DbSchema is the top level structure for the referential schema.
+type DbSchema struct {
+       Name      string           `json:"name"`
+       Resources []ResourceSchema `json:"resources"`
+       SegmentId string
+}
+
+type DbSchemaKey struct {
+       SegmentId string
+}
+
+// ReferentialSchema defines the structure that will be prepared
+// for each element of the referential schema map.
+type ReferentialSchema struct {
+       parent       string              // Name of the parent resource
+       trimParent   bool                // Special case for combined key resource - e.g. compositeApp.compositeAppVersion
+       keyId        string              // the keyId string identifier for this resource
+       children     map[string]struct{} // list of children
+       keyMap       map[string]struct{} // map structure for looking up this item
+       references   []ReferenceSchema   // list of references
+       referencedBy map[string]struct{} // list of resource that may reference this resource
+}
+
+func (key DbSchemaKey) String() string {
+       out, err := json.Marshal(key)
+       if err != nil {
+               return ""
+       }
+       return string(out)
+}
+
+// ReadRefSchema reads the Referential Schema Segment file and creates the refSchemaMap.
+func (m *MongoStore) ReadRefSchema() {
+       schema, err := readSchema()
+       if err != nil {
+               return
+       }
+
+       m.verifyReferentialIntegrity(schema)
+}
+
+// verifyReferentialIntegrity verifies the referential integrity of the resources
+// defined by the controller(s) schema.
+// Wait for controllers to register schema in scenarios where
+// multiple controllers start simultaneously.
+func (m *MongoStore) verifyReferentialIntegrity(serviceSchema DbSchema) {
+       var (
+               backOff       int   = config.GetConfiguration().BackOff
+               maxBackOff    int   = config.GetConfiguration().MaxBackOff
+               err           error = nil
+               waitForSchema bool  = true
+       )
+
+       for waitForSchema {
+               waitForSchema, err = m.processSchema(serviceSchema)
+               if err != nil {
+                       return
+               }
+               if !waitForSchema {
+                       log.Info("DatabaseReferentialSchema: successfully processed the referential schema.",
+                               log.Fields{})
+                       break
+               }
+
+               log.Info(fmt.Sprintf("DatabaseReferentialSchema: some resources are missing in the schema, retry after %d seconds.", backOff),
+                       log.Fields{
+                               "Interval": backOff})
+               // Instead of retrying immediately, waits some amount of time between tries.
+               time.Sleep(time.Duration(backOff) * time.Second)
+
+               if backOff*2 < maxBackOff {
+                       backOff *= 2
+               } else {
+                       backOff = maxBackOff
+               }
+       }
+}
+
+// processSchema process each schema segment in the db.
+func (m *MongoStore) processSchema(serviceSchema DbSchema) (bool, error) {
+       var (
+               emcoRefSchema    DbSchema
+               schemaExists     bool
+               baseSchemaExists bool
+       )
+
+       const baseSchemaName string = "emco-base"
+
+       schemaLock.Lock()
+       defer schemaLock.Unlock()
+
+       // Retrieve all the schema segments.
+       segments, err := m.Find("resources", DbSchemaKey{}, "segment")
+       if err != nil {
+               log.Error("DatabaseReferentialSchema: failed to retrieve schema segments from db.",
+                       log.Fields{
+                               "Error": err})
+               return false, err
+       }
+       if len(segments) == 0 &&
+               len(serviceSchema.Resources) == 0 {
+               log.Info("DatabaseReferentialSchema: there are no schema(s) registered in the db.",
+                       log.Fields{})
+               // Wait for the schema.
+               return true, nil
+       }
+
+       // Put together a complete schema using the schema segments.
+       for _, s := range segments {
+               schema := DbSchema{}
+               err := m.Unmarshal(s, &schema)
+               if err != nil {
+                       log.Error("DatabaseReferentialSchema: failed to unmarshal schema segment.",
+                               log.Fields{
+                                       "Error": err})
+                       return false, err
+               }
+
+               if schema.SegmentId == serviceSchema.SegmentId {
+                       schemaExists = true
+               }
+
+               // Do not register multiple schema segments with the same name.
+               if serviceSchema.Name == schema.Name &&
+                       serviceSchema.SegmentId != schema.SegmentId {
+                       log.Error("DatabaseReferentialSchema: failed to validate referential schema integrity due to duplicate schema names.",
+                               log.Fields{
+                                       "Name":             serviceSchema.Name,
+                                       "ExistingSchemaId": schema.SegmentId})
+                       return false,
+                               pkgerrors.New("A schema with the name already exists.")
+               }
+
+               if schema.Name == baseSchemaName {
+                       baseSchemaExists = true
+               }
+
+               emcoRefSchema.Resources = append(emcoRefSchema.Resources, schema.Resources...)
+       }
+
+       if !baseSchemaExists && serviceSchema.Name != baseSchemaName {
+               log.Warn("DatabaseReferentialSchema: the emco-base schema is not available.",
+                       log.Fields{})
+               // Wait for the base schema.
+               return true, nil
+       }
+
+       if !schemaExists {
+               emcoRefSchema.Resources = append(emcoRefSchema.Resources, serviceSchema.Resources...)
+       }
+
+       // Create a consolidated referential schemamap.
+       err = populateReferentialMap(emcoRefSchema)
+       if err != nil {
+               resetSchema()
+               return false, err
+       }
+
+       // Create a referential keymap.
+       waitForSchema, err := populateReferentialKeyMap()
+       if err != nil {
+               resetSchema()
+               return false, err
+
+       }
+       if waitForSchema {
+               resetSchema()
+       }
+
+       if !schemaExists &&
+               serviceSchema.SegmentId != "" {
+               // Register the controller schema in the db.
+               err := m.Insert("resources", DbSchemaKey{SegmentId: serviceSchema.SegmentId}, nil, "segment", serviceSchema)
+               if err != nil {
+                       log.Error("DatabaseReferentialSchema: failed to insert service schema into the db.",
+                               log.Fields{
+                                       "Error": err})
+                       resetSchema()
+                       return false, err
+               }
+       }
+
+       return waitForSchema, nil
+}
+
+// readSchema reads schema definitions from the given schema file.
+func readSchema() (DbSchema, error) {
+       var schema DbSchema
+
+       if _, err := os.Stat(refSchemaFile); err != nil {
+               if os.IsNotExist(err) {
+                       log.Warn("DatabaseReferentialSchema: database schema file does not exist.",
+                               log.Fields{
+                                       "File":  refSchemaFile,
+                                       "Error": err})
+                       // Continue without a schema
+                       return schema, nil
+               }
+               log.Error("DatabaseReferentialSchema: database schema file path error.",
+                       log.Fields{
+                               "File":  refSchemaFile,
+                               "Error": err})
+               return schema, err
+       }
+
+       rawBytes, err := ioutil.ReadFile(refSchemaFile)
+       if err != nil {
+               log.Error("DatabaseReferentialSchema: failed to read the database schema file.",
+                       log.Fields{
+                               "Error": err,
+                               "File":  refSchemaFile})
+               return schema, err
+       }
+
+       err = yaml.Unmarshal(rawBytes, &schema)
+       if err != nil {
+               log.Error("DatabaseReferentialSchema: failed to unmarshal referential schema.",
+                       log.Fields{
+                               "Error": err,
+                               "File":  refSchemaFile})
+               return schema, err
+       }
+
+       err = validateSchema(schema)
+       if err != nil {
+               log.Error("DatabaseReferentialSchema: schema validation failed.",
+                       log.Fields{
+                               "Error": err,
+                               "File":  refSchemaFile})
+               return schema, err
+       }
+
+       schema.SegmentId = segmentId(rawBytes)
+
+       return schema, nil
+}
+
+// populateReferentialMap create a referential schemamap from the schema.
+func populateReferentialMap(emcoRefSchema DbSchema) error {
+       refSchemaMap = make(map[string]ReferentialSchema)
+
+       for _, resource := range emcoRefSchema.Resources {
+               // The name can be of with two elements.
+               // eg : compositeApp.compositeAppVersion
+               names := strings.Split(resource.Name, ".")
+               if len(names) == 0 || len(names) > 2 {
+                       log.Error("DatabaseReferentialSchema: invalid schema resource name.",
+                               log.Fields{
+                                       "Resource": resource.Name})
+                       return pkgerrors.New("Invalid schema resource name.")
+               }
+
+               schema := ReferentialSchema{
+                       children:     make(map[string]struct{}), //default
+                       keyMap:       make(map[string]struct{}), //default
+                       referencedBy: make(map[string]struct{}), //default
+               }
+
+               if len(names) == 1 { // Resource with only one element - eg: project
+                       if _, exists := refSchemaMap[names[0]]; !exists {
+                               schema.parent = resource.Parent
+                               schema.references = resource.References
+                               refSchemaMap[names[0]] = schema
+                               continue
+                       }
+                       log.Error("DatabaseReferentialSchema: resource already exists.",
+                               log.Fields{
+                                       "Resource": names[0]})
+                       return pkgerrors.New("Resource already exists.")
+               }
+
+               // Resource with two elements - eg : compositeApp.compositeAppVersion
+               // Handle these two elemets as two separate resource.
+               for i, name := range names {
+                       if _, exists := refSchemaMap[name]; !exists {
+                               // We take the resource parent as the parent for the first element.
+                               if i == 0 {
+                                       schema.parent = resource.Parent
+                                       refSchemaMap[name] = schema
+                                       continue
+                               }
+                               // We take the name of the first element as the parent of the second element.
+                               schema.parent = names[0]
+                               schema.trimParent = true
+                               schema.references = resource.References
+                               refSchemaMap[name] = schema
+                               continue
+                       }
+                       log.Error("DatabaseReferentialSchema: resource already exists.",
+                               log.Fields{
+                                       "Resource": name})
+                       return pkgerrors.New("Resource already exists.")
+               }
+       }
+
+       return nil
+}
+
+// populateReferentialKeyMap create a referential keymap from the referential schemamap.
+func populateReferentialKeyMap() (bool, error) {
+       refKeyMap = make(map[string]string)
+
+       for resource, schema := range refSchemaMap {
+               if schema.parent != "" {
+                       p, exists := refSchemaMap[schema.parent]
+                       if !exists {
+                               log.Warn("DatabaseReferentialSchema: parent resource is missing in the referential schema map.",
+                                       log.Fields{
+                                               "Resource": resource,
+                                               "Parent":   schema.parent})
+                               // Wait for the missing schema.
+                               return true, nil
+                       }
+                       // Add to parents child list.
+                       p.children[resource] = struct{}{}
+                       refSchemaMap[schema.parent] = p
+               }
+
+               // Check if "referenced by" and update referencedBy list of references.
+               for _, reference := range schema.references {
+                       r, exists := refSchemaMap[reference.Name]
+                       if !exists {
+                               log.Warn("DatabaseReferentialSchema: referenced resource is missing in the referential schema map.",
+                                       log.Fields{
+                                               "Resource":           resource,
+                                               "ReferencedResource": reference.Name})
+                               // Wait for the missing schema.
+                               return true, nil
+                       }
+                       // Add to referencedBy list
+                       r.referencedBy[resource] = struct{}{}
+                       refSchemaMap[reference.Name] = r
+               }
+
+               keyMap, keyId, waitForSchema, err := createKeyMapAndId(resource)
+               if err != nil {
+                       return false, err
+               }
+               if waitForSchema {
+                       return waitForSchema, err
+               }
+
+               schema.keyMap = keyMap
+               schema.keyId = keyId
+               refSchemaMap[resource] = schema
+               refKeyMap[keyId] = resource
+       }
+
+       return false, nil
+}
+
+// createKeyMapAndId returns key structure (map) and keyId for a given resource.
+// KeyId indicates the referential integrity keys for the resource.
+func createKeyMapAndId(resource string) (map[string]struct{}, string, bool, error) {
+       schema, exists := refSchemaMap[resource]
+       if !exists {
+               log.Warn("DatabaseReferentialSchema: resource is missing in the referential schema map.",
+                       log.Fields{
+                               "Resource": resource})
+               // Wait for the missing schema.
+               return nil, "", true, nil
+       }
+
+       var keys []string
+       key := resource
+       keyMap := make(map[string]struct{})
+
+       // Generate the keyMap.
+       for {
+               if _, exists = keyMap[key]; exists {
+                       log.Error("DatabaseReferentialSchema: circular schema dependency for resource.",
+                               log.Fields{
+                                       "Resource": key})
+                       return nil, "", false, pkgerrors.New("Circular schema dependency for resources.")
+               }
+
+               keys = append(keys, key)
+               keyMap[key] = struct{}{}
+
+               key = schema.parent
+               if len(key) == 0 {
+                       break
+               }
+
+               if schema, exists = refSchemaMap[key]; !exists {
+                       log.Warn("DatabaseReferentialSchema: parent resource is missing in the referential schema map.",
+                               log.Fields{
+                                       "Resource": resource,
+                                       "Parent":   key})
+                       // Wait for the missing schema.
+                       return nil, "", true, nil
+               }
+       }
+
+       sort.Strings(keys)
+
+       // Generate the keyId
+       keyId := fmt.Sprintf("{%s}", strings.Join(keys, ","))
+
+       return keyMap, keyId, false, nil
+}
+
+// segmentId returns a unique id for the segment.
+func segmentId(p []byte) string {
+       h := sha256.New()
+       h.Write(p)
+       return fmt.Sprintf("%x", h.Sum(nil))
+}
+
+// validateSchema validate the provided data with the schema definition
+func validateSchema(schema DbSchema) error {
+       var err error
+
+       // Schema Name is required.
+       if err = match(schema.Name, true); err != nil {
+               return err
+       }
+
+       // Resource(s) are required.
+       if len(schema.Resources) == 0 {
+               log.Error("DatabaseReferentialSchema: invalid Input:: Invalid type. Expected: array, given: null",
+                       log.Fields{
+                               "Schema": schema.Name,
+                               "Field":  "Resources"})
+               return pkgerrors.New("Invalid Input.")
+       }
+
+       for _, res := range schema.Resources {
+               // Resource Name is required.
+               if err = match(res.Name, true); err != nil {
+                       return err
+               }
+
+               if err = match(res.Parent, false); err != nil {
+                       return err
+               }
+
+               for _, ref := range res.References {
+                       // Reference Name is required.
+                       if err = match(ref.Name, true); err != nil {
+                               return err
+                       }
+
+                       if err = match(ref.Map, false); err != nil {
+                               return err
+                       }
+
+                       if err = match(ref.CommonKey, false); err != nil {
+                               return err
+                       }
+
+                       // Allowed Types are 'map', 'many', if present
+                       if len(ref.Type) != 0 &&
+                               ref.Type != "map" &&
+                               ref.Type != "many" {
+                               log.Error("DatabaseReferentialSchema: invalid Input:: Invalid value. Expected: map or many",
+                                       log.Fields{
+                                               "Schema": schema.Name,
+                                               "Field":  "Reference Type",
+                                               "Value":  ref.Type})
+                               return pkgerrors.New("Invalid Input.")
+                       }
+
+                       for _, kv := range ref.FixedKv {
+                               if err = match(kv, false); err != nil {
+                                       return err
+                               }
+                       }
+
+                       for _, k := range ref.FilterKeys {
+                               if err = match(k, false); err != nil {
+                                       return err
+                               }
+                       }
+               }
+       }
+
+       return nil
+}
+
+// match matches the given string with a pattern
+func match(s string, isRequired bool) error {
+       r, err := regexp.Compile("^([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9]$")
+       if err != nil {
+               return err
+       }
+
+       m := r.MatchString(s)
+       if (isRequired && len(s) == 0) ||
+               (len(s) != 0 && !m) {
+               log.Error("DatabaseReferentialSchema: invalid Input:: Does not match pattern '^([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9]$'",
+                       log.Fields{
+                               "Value": s})
+               return pkgerrors.New("Invalid Input.")
+       }
+
+       return nil
+}
+
+// reset clears the ref map
+func resetSchema() {
+       refSchemaMap = nil
+       refKeyMap = nil
+}
diff --git a/central-controller/src/vendor/gitlab.com/project-emco/core/emco-base/src/orchestrator/pkg/infra/db/schema_mock.go b/central-controller/src/vendor/gitlab.com/project-emco/core/emco-base/src/orchestrator/pkg/infra/db/schema_mock.go
new file mode 100644 (file)
index 0000000..3f10b41
--- /dev/null
@@ -0,0 +1,118 @@
+package db
+
+import (
+       pkgerrors "github.com/pkg/errors"
+)
+
+type MockMongoStore struct {
+       db *MockDB
+}
+
+// ReadRefSchema reads the Referential Schema Segment file and creates the refSchemaMap.
+func (m *MockMongoStore) ReadRefSchema() error {
+       schema, err := readSchema()
+       if err != nil {
+               return err
+       }
+
+       return m.verifyReferentialIntegrity(schema)
+}
+
+// verifyReferentialIntegrity verifies the referential integrity of the resources
+// defined by the controller(s) schema.
+// Wait for controllers to register schema in scenarios where
+// multiple controllers start simultaneously.
+func (m *MockMongoStore) verifyReferentialIntegrity(serviceSchema DbSchema) error {
+       refSchemaMap = nil
+       refKeyMap = nil
+
+       waitForSchema, err := m.processSchema(serviceSchema)
+       if err != nil {
+               return err
+       }
+       if waitForSchema {
+               return pkgerrors.New("Resource schema not found.")
+       }
+
+       return nil
+}
+
+// processSchema process each schema segment in the db.
+func (m *MockMongoStore) processSchema(serviceSchema DbSchema) (bool, error) {
+       var (
+               emcoRefSchema    DbSchema
+               schemaExists     bool
+               baseSchemaExists bool
+       )
+
+       const baseSchemaName string = "emco-base"
+
+       // Retrieve all the schema segments.
+       segments, err := m.db.Find("resources", DbSchemaKey{}, "segment")
+       if err != nil {
+               return false, err
+       }
+
+       if len(segments) == 0 &&
+               len(serviceSchema.Resources) == 0 {
+               return true, nil
+       }
+
+       // Put together a complete schema using the schema segments.
+       for _, s := range segments {
+               schema := DbSchema{}
+
+               err := m.db.Unmarshal(s, &schema)
+               if err != nil {
+                       return false, err
+               }
+
+               if schema.SegmentId == serviceSchema.SegmentId {
+                       schemaExists = true
+               }
+
+               if serviceSchema.Name == schema.Name &&
+                       serviceSchema.SegmentId != schema.SegmentId {
+                       return false,
+                               pkgerrors.New("A schema with the name already exists.")
+               }
+
+               if schema.Name == baseSchemaName {
+                       baseSchemaExists = true
+               }
+
+               emcoRefSchema.Resources = append(emcoRefSchema.Resources, schema.Resources...)
+       }
+
+       if !baseSchemaExists && serviceSchema.Name != baseSchemaName {
+               // Wait for the base schema.
+               return true, nil
+       }
+
+       if !schemaExists {
+               emcoRefSchema.Resources = append(emcoRefSchema.Resources, serviceSchema.Resources...)
+       }
+
+       // Create a consolidated referential schemamap.
+       err = populateReferentialMap(emcoRefSchema)
+       if err != nil {
+               return false, err
+       }
+
+       // Create a referential keymap.
+       waitForSchema, err := populateReferentialKeyMap()
+       if err != nil {
+               return false, err
+       }
+
+       if !schemaExists &&
+               serviceSchema.SegmentId != "" {
+               // Register the controller schema in the db.
+               err := m.db.Insert("resources", DbSchemaKey{SegmentId: serviceSchema.SegmentId}, nil, "segment", serviceSchema)
+               if err != nil {
+                       return false, err
+               }
+       }
+
+       return waitForSchema, nil
+}
diff --git a/central-controller/src/vendor/gitlab.com/project-emco/core/emco-base/src/orchestrator/pkg/infra/db/schema_test.go b/central-controller/src/vendor/gitlab.com/project-emco/core/emco-base/src/orchestrator/pkg/infra/db/schema_test.go
new file mode 100644 (file)
index 0000000..8fda166
--- /dev/null
@@ -0,0 +1,337 @@
+// SPDX-License-Identifier: Apache-2.0
+// Copyright (c) 2021 Intel Corporation
+
+package db
+
+import (
+       "fmt"
+       "io/ioutil"
+       "os"
+       "strings"
+
+       . "github.com/onsi/ginkgo"
+       . "github.com/onsi/gomega"
+)
+
+var mockMongoStore *MockMongoStore
+var wd string
+
+func init() {
+       // make the MongoStore struct hear and then call schema stuff here
+       mockMongoStore = &MockMongoStore{
+               db: &MockDB{}}
+
+       wd, _ = os.Getwd()
+}
+
+var _ = Describe("Read schema file",
+       func() {
+               Context("when the schema file does not exists", func() {
+                       It("continue without any error", func() {
+                               refSchemaFile = "test-schemas/non-exists.yaml"
+                               mockMongoStore.db.Items = mockSchemaSegments()
+                               validate(mockMongoStore.ReadRefSchema(), "")
+                               clear()
+                       })
+               })
+
+               Context("when the schema file exists but the schema is not valid", func() {
+                       It("returns schema unmarshal error", func() {
+                               refSchemaFile = wd + "/test-schemas/invalid-schema.yaml"
+                               validate(mockMongoStore.ReadRefSchema(), "yaml: line 4: did not find expected key")
+                               clear()
+                       })
+               })
+
+               Context("when the schema file exists but the schema name is missing", func() {
+                       It("returns a JSON schema validation error", func() {
+                               refSchemaFile = wd + "/test-schemas/missing-name.yaml"
+                               validate(mockMongoStore.ReadRefSchema(), "Invalid Input.")
+                               clear()
+                       })
+               })
+
+               Context("when the schema file exists but the resources are missing", func() {
+                       It("returns a JSON schema validation error", func() {
+                               refSchemaFile = wd + "/test-schemas/missing-resource.yaml"
+                               validate(mockMongoStore.ReadRefSchema(), "Invalid Input.")
+                               clear()
+                       })
+               })
+
+               Context("when a valid schema file exists", func() {
+                       It("continue without any error", func() {
+                               refSchemaFile = wd + "/test-schemas/emco-base.yaml"
+                               validate(mockMongoStore.ReadRefSchema(), "")
+                               clear()
+                       })
+
+                       It("returns a valid schema segment", func() {
+                               refSchemaFile = wd + "/test-schemas/emco-base.yaml"
+                               schema, err := readSchema()
+                               validate(err, "")
+                               Expect(schema).To(Equal(mockSchema(schema.Name)))
+                               clear()
+                       })
+
+                       It("returns a valid segmentId", func() {
+                               refSchemaFile = wd + "/test-schemas/emco-base.yaml"
+                               rawBytes, _ := ioutil.ReadFile(refSchemaFile)
+                               segmentId := segmentId(rawBytes)
+                               Expect(segmentId).To(Equal("d2291e8f0e9fe2fe94b7e440b812448abcfa89a9801d6b78d646553b8ad0a634"))
+                               clear()
+                       })
+               })
+       })
+
+var _ = Describe("Verify referential integrity",
+       func() {
+               Context("when the schema file does not exists", func() {
+                       It("create the referential schema map with the schema segments available in the database", func() {
+                               refSchemaFile = "test-schemas/non-exists.yaml"
+                               mockMongoStore.db.Items = mockSchemaSegments()
+                               refSchemaMapExpected := mockSchemaMap(false)
+                               validate(mockMongoStore.ReadRefSchema(), "")
+                               Expect(refSchemaMap).To(Equal(refSchemaMapExpected))
+                               Expect(len(mockMongoStore.db.Items)).To(Equal(2)) // no new schema segment registered in the database
+                               clear()
+                       })
+               })
+
+               Context("when the schema file exists", func() {
+                       It("create the referential schema map with the schema and the schema segments available in the database", func() {
+                               refSchemaFile = wd + "/test-schemas/new-controller.yaml"
+                               mockMongoStore.db.Items = mockSchemaSegments()
+                               refSchemaMapExpected := mockSchemaMap(true)
+                               validate(mockMongoStore.ReadRefSchema(), "")
+                               Expect(refSchemaMap).To(Equal(refSchemaMapExpected))
+                               Expect(len(mockMongoStore.db.Items)).To(Equal(3)) // register the new schema in the database
+                               clear()
+                       })
+               },
+               )
+
+               Context("when the schema file exists and the controller restarts", func() {
+                       It("create the referential schema map with the schema segments available in the database", func() {
+                               refSchemaFile = wd + "/test-schemas/emco-base.yaml"
+                               mockMongoStore.db.Items = mockSchemaSegments()
+                               refSchemaMapExpected := mockSchemaMap(false)
+                               validate(mockMongoStore.ReadRefSchema(), "")
+                               Expect(refSchemaMap).To(Equal(refSchemaMapExpected))
+                               Expect(len(mockMongoStore.db.Items)).To(Equal(2)) // no new schema segment registered in the database
+                               clear()
+                       })
+               })
+
+               Context("when the dependent schema is missing in the database", func() {
+                       It("the controller returns an error", func() {
+                               refSchemaFile = wd + "/test-schemas/missing-parent.yaml"
+                               mockMongoStore.db.Items = mockSchemaSegments()
+                               validate(mockMongoStore.ReadRefSchema(), "Resource schema not found.")
+                               clear()
+                       })
+               })
+
+               Context("when two controllers define the same resource", func() {
+                       It("the second controller returns an error", func() {
+                               refSchemaFile = wd + "/test-schemas/duplicate-resource.yaml"
+                               mockMongoStore.db.Items = mockSchemaSegments()
+                               validate(mockMongoStore.ReadRefSchema(), "Resource already exists.")
+                               clear()
+                       })
+               })
+
+               Context("when the resource name is invalid", func() {
+                       It("the controller returns an error", func() {
+                               refSchemaFile = wd + "/test-schemas/invalid-resource-name.yaml"
+                               mockMongoStore.db.Items = mockSchemaSegments()
+                               validate(mockMongoStore.ReadRefSchema(), "Invalid schema resource name.")
+                               clear()
+                       })
+               })
+
+               Context("when the resource has a circular dependency on another resource", func() {
+                       It("the controller returns an error", func() {
+                               refSchemaFile = wd + "/test-schemas/loop.yaml"
+                               validate(mockMongoStore.ReadRefSchema(), "Circular schema dependency for resources.")
+                               clear()
+                       })
+               })
+
+               Context("when two controllers define the same schema name", func() {
+                       It("the second controller returns an error", func() {
+                               refSchemaFile = wd + "/test-schemas/duplicate-schema.yaml"
+                               mockMongoStore.db.Items = mockSchemaSegments()
+                               validate(mockMongoStore.ReadRefSchema(), "A schema with the name already exists.")
+                               clear()
+                       })
+               })
+
+       })
+
+func mockSchemaSegments() []map[string]map[string][]byte {
+       return []map[string]map[string][]byte{
+               {
+                       DbSchemaKey{
+                               SegmentId: "d2291e8f0e9fe2fe94b7e440b812448abcfa89a9801d6b78d646553b8ad0a634",
+                       }.String(): {
+                               "segment": []byte(
+                                       "{" +
+                                               "\"name\": \"emco-base\"," +
+                                               "\"resources\": [" +
+                                               "{" +
+                                               "\"name\": \"clusterProvider\"," +
+                                               "\"parent\": \"\"," +
+                                               "\"references\": null" +
+                                               "}," +
+                                               "{" +
+                                               "\"name\": \"cluster\"," +
+                                               "\"parent\": \"clusterProvider\"," +
+                                               "\"references\": null" +
+                                               "}," +
+                                               "{" +
+                                               "\"name\": \"clusterLabel\"," +
+                                               "\"parent\": \"cluster\"," +
+                                               "\"references\": null" +
+                                               "}," +
+                                               "{" +
+                                               "\"name\": \"clusterKv\"," +
+                                               "\"parent\": \"cluster\"," +
+                                               "\"references\": null" +
+                                               "}" +
+                                               "]," +
+                                               "\"segmentid\": \"d2291e8f0e9fe2fe94b7e440b812448abcfa89a9801d6b78d646553b8ad0a634\"" +
+                                               "}")},
+               },
+               {
+                       DbSchemaKey{
+                               SegmentId: "e6a83b911fa8f97db7b7b75a1c1ad4c0316cf1e19a652d1326d3b425bfdad9e6",
+                       }.String(): {
+                               "segment": []byte(
+                                       "{" +
+                                               "\"name\": \"controller-1\"," +
+                                               "\"resources\": [" +
+                                               "{" +
+                                               "\"name\": \"providerNetwork\"," +
+                                               "\"parent\": \"cluster\"," +
+                                               "\"references\": null" +
+                                               "}," +
+                                               "{" +
+                                               "\"name\": \"network\"," +
+                                               "\"parent\": \"cluster\"," +
+                                               "\"references\": null" +
+                                               "}" +
+                                               "]," +
+                                               "\"segmentid\": \"e6a83b911fa8f97db7b7b75a1c1ad4c0316cf1e19a652d1326d3b425bfdad9e6\"" +
+                                               "}")},
+               }}
+}
+
+func mockSchemaMap(withSchema bool) map[string]ReferentialSchema {
+
+       refSchemaMap = make(map[string]ReferentialSchema)
+
+       refSchemaMap["clusterProvider"], _ = schemaSegment("clusterProvider", "", "cluster", "", nil, false)
+       refSchemaMap["cluster"], _ = schemaSegment("cluster", "clusterProvider", "clusterLabel,clusterKv,providerNetwork,network", "", nil, false)
+       refSchemaMap["clusterLabel"], _ = schemaSegment("clusterLabel", "cluster", "", "", nil, false)
+       refSchemaMap["clusterKv"], _ = schemaSegment("clusterKv", "cluster", "", "", nil, false)
+       refSchemaMap["providerNetwork"], _ = schemaSegment("providerNetwork", "cluster", "", "", nil, false)
+       refSchemaMap["network"], _ = schemaSegment("network", "cluster", "", "", nil, false)
+
+       if withSchema { // This is a new schema segment. Include in the ref schema map.
+               refSchemaMap["sfcIntent"], _ = schemaSegment("sfcIntent", "", "sfcProviderNetwork,sfcClientSelector,sfcLink", "", nil, false)
+               refSchemaMap["sfcClientSelector"], _ = schemaSegment("sfcClientSelector", "sfcIntent", "", "", nil, false)
+               refSchemaMap["sfcProviderNetwork"], _ = schemaSegment("sfcProviderNetwork", "sfcIntent", "", "", nil, false)
+               refSchemaMap["sfcLink"], _ = schemaSegment("sfcLink", "sfcIntent", "", "", nil, false)
+       }
+
+       for resource, schema := range refSchemaMap {
+               keyMap, keyId, _, err := createKeyMapAndId(resource)
+               if err != nil {
+                       fmt.Println(err)
+                       return refSchemaMap
+               }
+               schema.keyId = keyId
+               schema.keyMap = keyMap
+               refSchemaMap[resource] = schema
+       }
+
+       return refSchemaMap
+}
+
+func schemaSegment(resource, parent, children, referencedBy string, references []ReferenceSchema, trimParent bool) (ReferentialSchema, error) {
+       mockSchema := ReferentialSchema{
+               children:     make(map[string]struct{}), //default
+               keyMap:       make(map[string]struct{}), //default
+               referencedBy: make(map[string]struct{}), //default
+       }
+
+       mockSchema.parent = parent
+       mockSchema.trimParent = trimParent
+       if len(children) != 0 {
+               cn := strings.Split(children, ",")
+               for _, c := range cn {
+                       mockSchema.children[c] = struct{}{}
+               }
+       }
+       if len(referencedBy) != 0 {
+               rs := strings.Split(referencedBy, ",")
+               for _, r := range rs {
+                       mockSchema.referencedBy[r] = struct{}{}
+               }
+       }
+
+       mockSchema.references = references
+
+       return mockSchema, nil
+}
+
+func mockSchema(controller string) DbSchema {
+       switch controller {
+       case "emco-base":
+               return DbSchema{
+                       Name: "emco-base",
+                       Resources: []ResourceSchema{
+                               {
+                                       Name:       "clusterProvider",
+                                       Parent:     "",
+                                       References: nil,
+                               },
+                               {
+                                       Name:       "cluster",
+                                       Parent:     "clusterProvider",
+                                       References: nil,
+                               },
+                               {
+                                       Name:       "clusterLabel",
+                                       Parent:     "cluster",
+                                       References: nil,
+                               },
+                               {
+                                       Name:       "clusterKv",
+                                       Parent:     "cluster",
+                                       References: nil,
+                               },
+                       },
+                       SegmentId: "d2291e8f0e9fe2fe94b7e440b812448abcfa89a9801d6b78d646553b8ad0a634"}
+
+       default:
+               return DbSchema{}
+       }
+}
+
+func clear() {
+       refSchemaFile = ""
+       refSchemaMap = nil
+       refKeyMap = nil
+       mockMongoStore.db.Items = nil
+}
+
+func validate(err error, message string) {
+       if len(message) == 0 {
+               Expect(err).NotTo(HaveOccurred())
+               Expect(err).To(BeNil())
+               return
+       }
+       Expect(err.Error()).To(ContainSubstring(message))
+}
@@ -7,7 +7,7 @@ import (
        "encoding/json"
        "reflect"
 
-       "github.com/open-ness/EMCO/src/orchestrator/pkg/infra/config"
+       "gitlab.com/project-emco/core/emco-base/src/orchestrator/pkg/infra/config"
 
        pkgerrors "github.com/pkg/errors"
 )
@@ -26,7 +26,7 @@ type Store interface {
        // Returns nil if db health is good
        HealthCheck() error
 
-       // Unmarshal implements any unmarshaling needed for the database
+       // Unmarshal implements any unmarshalling needed for the database
        Unmarshal(inp []byte, out interface{}) error
 
        // Inserts and Updates a tag with key and also adds query fields if provided
diff --git a/central-controller/src/vendor/gitlab.com/project-emco/core/emco-base/src/orchestrator/pkg/infra/db/test-schemas/duplicate-resource.yaml b/central-controller/src/vendor/gitlab.com/project-emco/core/emco-base/src/orchestrator/pkg/infra/db/test-schemas/duplicate-resource.yaml
new file mode 100644 (file)
index 0000000..6fddcc8
--- /dev/null
@@ -0,0 +1,7 @@
+name: emco-clm-duplicate
+resources:
+  - name: clusterProvider
+  - name: cluster
+    parent: clusterProvider
+  - name: clusterLabel
+    parent: cluster
\ No newline at end of file
diff --git a/central-controller/src/vendor/gitlab.com/project-emco/core/emco-base/src/orchestrator/pkg/infra/db/test-schemas/duplicate-schema.yaml b/central-controller/src/vendor/gitlab.com/project-emco/core/emco-base/src/orchestrator/pkg/infra/db/test-schemas/duplicate-schema.yaml
new file mode 100644 (file)
index 0000000..49e91cb
--- /dev/null
@@ -0,0 +1,6 @@
+name: emco-base
+resources:
+  - name: newProviderNetwork
+    parent: cluster
+  - name: newNetwork
+    parent: cluster
\ No newline at end of file
diff --git a/central-controller/src/vendor/gitlab.com/project-emco/core/emco-base/src/orchestrator/pkg/infra/db/test-schemas/emco-base.yaml b/central-controller/src/vendor/gitlab.com/project-emco/core/emco-base/src/orchestrator/pkg/infra/db/test-schemas/emco-base.yaml
new file mode 100644 (file)
index 0000000..3149b15
--- /dev/null
@@ -0,0 +1,10 @@
+name: emco-base
+resources:
+#emco-clm
+  - name: clusterProvider
+  - name: cluster
+    parent: clusterProvider
+  - name: clusterLabel
+    parent: cluster
+  - name: clusterKv
+    parent: cluster
\ No newline at end of file
diff --git a/central-controller/src/vendor/gitlab.com/project-emco/core/emco-base/src/orchestrator/pkg/infra/db/test-schemas/invalid-resource-name.yaml b/central-controller/src/vendor/gitlab.com/project-emco/core/emco-base/src/orchestrator/pkg/infra/db/test-schemas/invalid-resource-name.yaml
new file mode 100644 (file)
index 0000000..f0692a7
--- /dev/null
@@ -0,0 +1,5 @@
+name: emco-app
+resources:
+  - name: app.compositeApp.invalid
+  - name: clusterLabel
+    parent: cluster
diff --git a/central-controller/src/vendor/gitlab.com/project-emco/core/emco-base/src/orchestrator/pkg/infra/db/test-schemas/invalid-schema.yaml b/central-controller/src/vendor/gitlab.com/project-emco/core/emco-base/src/orchestrator/pkg/infra/db/test-schemas/invalid-schema.yaml
new file mode 100644 (file)
index 0000000..a62bdca
--- /dev/null
@@ -0,0 +1,12 @@
+resources:
+  - name: clusterProvider
+  - name: cluster
+    parent: clusterProvider
+ - name: clusterLabel
+    parent: cluster
+  - name: kvname
+    parent: cluster
+  - name: providerNetwork
+    parent: cluster
+  - name: network
+    parent: cluster
diff --git a/central-controller/src/vendor/gitlab.com/project-emco/core/emco-base/src/orchestrator/pkg/infra/db/test-schemas/loop.yaml b/central-controller/src/vendor/gitlab.com/project-emco/core/emco-base/src/orchestrator/pkg/infra/db/test-schemas/loop.yaml
new file mode 100644 (file)
index 0000000..294d30b
--- /dev/null
@@ -0,0 +1,13 @@
+name: emco-base
+resources:
+  - name: clusterProvider
+  - name: cluster
+    parent: clusterLabel
+  - name: clusterLabel
+    parent: cluster
+  - name: clusterKv
+    parent: cluster
+  - name: roviderNetwork
+    parent: cluster
+  - name: network
+    parent: cluster
diff --git a/central-controller/src/vendor/gitlab.com/project-emco/core/emco-base/src/orchestrator/pkg/infra/db/test-schemas/missing-name.yaml b/central-controller/src/vendor/gitlab.com/project-emco/core/emco-base/src/orchestrator/pkg/infra/db/test-schemas/missing-name.yaml
new file mode 100644 (file)
index 0000000..527bde8
--- /dev/null
@@ -0,0 +1,4 @@
+resources:
+  - name: provider
+  - name: clusterLabel
+    parent: cluster
diff --git a/central-controller/src/vendor/gitlab.com/project-emco/core/emco-base/src/orchestrator/pkg/infra/db/test-schemas/missing-parent.yaml b/central-controller/src/vendor/gitlab.com/project-emco/core/emco-base/src/orchestrator/pkg/infra/db/test-schemas/missing-parent.yaml
new file mode 100644 (file)
index 0000000..7fed1e8
--- /dev/null
@@ -0,0 +1,8 @@
+name: emco-sfc
+resources:
+  - name: sfcIntent
+    parent: deploymentIntentGroup
+  - name: sfcClientSelector
+    parent: sfcIntent
+  - name: sfcProviderNetwork
+    parent: sfcIntent
\ No newline at end of file
diff --git a/central-controller/src/vendor/gitlab.com/project-emco/core/emco-base/src/orchestrator/pkg/infra/db/test-schemas/missing-resource.yaml b/central-controller/src/vendor/gitlab.com/project-emco/core/emco-base/src/orchestrator/pkg/infra/db/test-schemas/missing-resource.yaml
new file mode 100644 (file)
index 0000000..e05573e
--- /dev/null
@@ -0,0 +1 @@
+name: test-schema
diff --git a/central-controller/src/vendor/gitlab.com/project-emco/core/emco-base/src/orchestrator/pkg/infra/db/test-schemas/new-controller.yaml b/central-controller/src/vendor/gitlab.com/project-emco/core/emco-base/src/orchestrator/pkg/infra/db/test-schemas/new-controller.yaml
new file mode 100644 (file)
index 0000000..216ce60
--- /dev/null
@@ -0,0 +1,9 @@
+name: emco-new-controller
+resources:
+  - name: sfcIntent
+  - name: sfcLink
+    parent: sfcIntent
+  - name: sfcClientSelector
+    parent: sfcIntent
+  - name: sfcProviderNetwork
+    parent: sfcIntent
diff --git a/central-controller/src/vendor/gitlab.com/project-emco/core/emco-base/src/orchestrator/pkg/infra/rpc/rpc.go b/central-controller/src/vendor/gitlab.com/project-emco/core/emco-base/src/orchestrator/pkg/infra/rpc/rpc.go
new file mode 100644 (file)
index 0000000..bd15d87
--- /dev/null
@@ -0,0 +1,245 @@
+// SPDX-License-Identifier: Apache-2.0
+// Copyright (c) 2020 Intel Corporation
+
+package rpc
+
+import (
+       "context"
+       "fmt"
+       "strconv"
+       "strings"
+       "sync"
+       "time"
+
+       "gitlab.com/project-emco/core/emco-base/src/orchestrator/pkg/infra/config"
+       log "gitlab.com/project-emco/core/emco-base/src/orchestrator/pkg/infra/logutils"
+       pkgerrors "github.com/pkg/errors"
+       "google.golang.org/grpc"
+       "google.golang.org/grpc/connectivity"
+       "google.golang.org/grpc/credentials"
+       "google.golang.org/grpc/keepalive"
+       "google.golang.org/grpc/testdata"
+)
+
+type ContextUpdateRequest interface {
+}
+
+type ContextUpdateResponse interface {
+}
+
+type InstallAppRequest interface {
+}
+
+type InstallAppResponse interface {
+}
+
+type rpcInfo struct {
+       conn *grpc.ClientConn
+       host string
+       port int
+}
+
+var mutex = &sync.Mutex{}
+var rpcConnections = make(map[string]rpcInfo)
+
+// https://github.com/grpc/grpc/blob/master/doc/connectivity-semantics-and-api.md
+func isGoodState(state connectivity.State) bool {
+       return state == connectivity.Ready || state == connectivity.Idle
+}
+
+func waitForReady(conn *grpc.ClientConn) (connectivity.State, bool) {
+       state := conn.GetState()
+       if isGoodState(state) {
+               return state, true
+       }
+
+       waitCfg := time.Duration(config.GetConfiguration().GrpcConnReadyTime)
+       waitTime := waitCfg * time.Millisecond
+       log.Info("Grpc conn in bad state, will wait...",
+               log.Fields{"state": state, "waitTime": waitTime})
+
+       // The wait is done under mutex. TODO This may need a revisit.
+       ctx, cancel := context.WithTimeout(context.Background(), waitTime)
+       defer cancel()
+       conn.ResetConnectBackoff() // wake up subchannels in transient failure, if any
+       changed := conn.WaitForStateChange(ctx, state)
+
+       state = conn.GetState()
+       if changed && isGoodState(state) {
+               log.Info("Grpc conn moved to good state", log.Fields{"state": state})
+               return state, true
+       }
+       return state, false
+}
+
+// GetRpcConn is used by RPC client code which needs the connection for a
+// given controller for doing RPC calls with that controller.
+func GetRpcConn(name string) *grpc.ClientConn {
+       mutex.Lock()
+       defer mutex.Unlock()
+       val, ok := rpcConnections[name]
+       if !ok {
+               log.Error("GetRpcConn: no Grpc connection available.", log.Fields{"name": name})
+               return nil
+       }
+
+       state := val.conn.GetState()
+       log.Info("GetRpcConn: RPC connection info", log.Fields{"name": name, "conn": val.conn, "host": val.host, "port": val.port, "conn-state": state.String()})
+
+       state, goodConn := waitForReady(val.conn)
+       if goodConn {
+               return val.conn
+       }
+
+       log.Error("GetRpcConn: Bad gRPC connection", log.Fields{"name": name, "conn": val.conn, "host": val.host, "port": val.port, "conn-state": state.String()})
+       return nil
+}
+
+// UpdateRpcConn initializes, reuses or updates a grpc connection.
+// It does not guarantee that the conn is in a good state.
+func UpdateRpcConn(name, host string, port int) {
+       mutex.Lock()
+       defer mutex.Unlock()
+       if val, ok := rpcConnections[name]; ok {
+               if val.host == host && val.port == port { // reuse cached conn
+                       log.Info("UpdateRpcConn: found connection", log.Fields{
+                               "name":       name,
+                               "conn":       val.conn,
+                               "host":       val.host,
+                               "port":       val.port,
+                               "conn-state": val.conn.GetState().String()})
+
+                       // No need to waitForReady(): caller is not using the conn now.
+                       return
+               }
+               // mismatch with cached connect info: close conn
+               log.Info("UpdateRpcConn: closing RPC connection due to mismatch", log.Fields{
+                       "Server":   name,
+                       "Old Host": val.host,
+                       "Old Port": val.port,
+                       "New Host": host,
+                       "New Port": port,
+               })
+               err := val.conn.Close()
+               if err != nil {
+                       log.Warn("UpdateRpcConn: error closing RPC connection", log.Fields{
+                               "Server": name,
+                               "Host":   val.host,
+                               "Port":   val.port,
+                               "Error":  err,
+                       })
+               }
+               // fallthrough to conn creation
+       }
+
+       // Either no cached conn or it is stale: create conn, update rpcConnection
+       conn, err := createClientConn(host, port)
+       if err != nil {
+               log.Error("UpdateRpcConn: failed to create grpc connection", log.Fields{
+                       "Error": err,
+                       "Host":  host,
+                       "Port":  port,
+               })
+               delete(rpcConnections, name)
+               return
+       }
+       rpcConnections[name] = rpcInfo{conn: conn, host: host, port: port}
+       log.Info("UpdateRpcConn: added RPC Client connection", log.Fields{
+               "Controller":    name,
+               "rpcConnection": fmt.Sprintf("%v", rpcConnections[name])})
+}
+
+// CloseAllRpcConn closes all connections
+func CloseAllRpcConn() {
+       mutex.Lock()
+       defer mutex.Unlock()
+       log.Info("CloseAllRpcConn..", nil)
+       for k, v := range rpcConnections {
+               err := v.conn.Close()
+               if err != nil {
+                       log.Warn("Error closing RPC connection", log.Fields{
+                               "Server": k,
+                               "Host":   v.host,
+                               "Port":   v.port,
+                               "Error":  err,
+                       })
+               }
+       }
+}
+
+// RemoveRpcConn closes the connection and removes from map
+func RemoveRpcConn(name string) {
+       mutex.Lock()
+       defer mutex.Unlock()
+       if val, ok := rpcConnections[name]; ok {
+               err := val.conn.Close()
+               if err != nil {
+                       log.Warn("Error closing RPC connection", log.Fields{
+                               "Server": name,
+                               "Host":   val.host,
+                               "Port":   val.port,
+                               "Error":  err,
+                       })
+               }
+               delete(rpcConnections, name)
+       }
+}
+
+// createConn creates the Rpc Client Connection
+func createClientConn(Host string, Port int) (*grpc.ClientConn, error) {
+       var opts []grpc.DialOption
+
+       serverAddr := Host + ":" + strconv.Itoa(Port)
+       serverNameOverride := config.GetConfiguration().GrpcServerNameOverride
+
+       tls := strings.Contains(config.GetConfiguration().GrpcEnableTLS, "enable")
+
+       caFile := config.GetConfiguration().GrpcCAFile
+
+       if tls {
+               if caFile == "" {
+                       caFile = testdata.Path("ca.pem")
+               }
+               creds, err := credentials.NewClientTLSFromFile(caFile, serverNameOverride)
+               if err != nil {
+                       log.Error("Failed to create TLS credentials", log.Fields{
+                               "Error": err,
+                               "Host":  Host,
+                               "Port":  Port,
+                       })
+               }
+               opts = append(opts, grpc.WithTransportCredentials(creds))
+       } else {
+               opts = append(opts, grpc.WithInsecure())
+       }
+
+       dialOpts := getGrpcDialOpts()
+       opts = append(opts, dialOpts...)
+       conn, err := grpc.Dial(serverAddr, opts...)
+       if err != nil {
+               pkgerrors.Wrap(err, "Grpc Connection Initialization failed with error")
+       }
+
+       return conn, err
+}
+
+func getGrpcDialOpts() []grpc.DialOption {
+       // ConnTimeout is used for both ping period and ping timeout because
+       // both relate to ready -> not-ready transition.
+       pingTime := time.Duration(config.GetConfiguration().GrpcConnTimeout)
+       pingTimeout := time.Duration(config.GetConfiguration().GrpcConnTimeout)
+
+       // Add keepalive pings with timeout
+       keepaliveParams := keepalive.ClientParameters{
+               Time:    pingTime * time.Millisecond,
+               Timeout: pingTimeout * time.Millisecond,
+               // no pings without in-flight calls
+               PermitWithoutStream: false, // default=false but we make it explicit
+       }
+
+       opts := []grpc.DialOption{
+               grpc.WithKeepaliveParams(keepaliveParams),
+       }
+
+       return opts
+}
diff --git a/central-controller/src/vendor/gitlab.com/project-emco/core/emco-base/src/orchestrator/pkg/infra/rpc/rpc_test.go b/central-controller/src/vendor/gitlab.com/project-emco/core/emco-base/src/orchestrator/pkg/infra/rpc/rpc_test.go
new file mode 100644 (file)
index 0000000..f00d74e
--- /dev/null
@@ -0,0 +1,17 @@
+// SPDX-License-Identifier: Apache-2.0
+// Copyright (c) 2020 Intel Corporation
+
+package rpc
+
+import (
+       "testing"
+)
+
+func TestGetGrpcDialOpts(t *testing.T) {
+       t.Run("Validate return values", func(t *testing.T) {
+               dialOpts := getGrpcDialOpts()
+               if len(dialOpts) == 0 {
+                       t.Fatal("getGrpcDialOpts returned nothing")
+               }
+       })
+}
diff --git a/central-controller/src/vendor/gitlab.com/project-emco/core/emco-base/src/orchestrator/pkg/infra/utils/objectencryptor.go b/central-controller/src/vendor/gitlab.com/project-emco/core/emco-base/src/orchestrator/pkg/infra/utils/objectencryptor.go
new file mode 100644 (file)
index 0000000..8e76d7a
--- /dev/null
@@ -0,0 +1,184 @@
+// SPDX-License-Identifier: Apache-2.0\r
+// Copyright (c) 2020 Intel Corporation\r
+\r
+package utils\r
+\r
+import (\r
+    "crypto/aes"\r
+    "crypto/cipher"\r
+    "encoding/hex"\r
+    log "gitlab.com/project-emco/core/emco-base/src/orchestrator/pkg/infra/logutils"\r
+    "os"\r
+    "reflect"\r
+    "strings"\r
+)\r
+\r
+type IObjectEncryptor interface {\r
+    EncryptObject(o interface{}) (interface{}, error)\r
+    EncryptString(message string) (string, error)\r
+    DecryptObject(o interface{}) (interface{}, error)\r
+    DecryptString(ciphermessage string) (string, error)\r
+}\r
+\r
+type MyObjectEncryptor struct {\r
+    gcm     cipher.AEAD\r
+    nonce   []byte\r
+}\r
+\r
+var gobjencs = make(map[string]IObjectEncryptor)\r
+\r
+func GetObjectEncryptor(provider string) IObjectEncryptor {\r
+    if gobjencs[provider] == nil {\r
+        envkey := strings.ToUpper(provider) + "_DATA_KEY"\r
+        if len(os.Getenv(envkey)) > 0 {\r
+            oe, err := createObjectEncryptor([]byte(os.Getenv(envkey)), []byte("emco nonce"))\r
+            if err != nil {\r
+                log.Error("Create Object Encryptor error :: ", log.Fields{"Error": err})\r
+                return nil\r
+            }\r
+            gobjencs[provider] = oe\r
+        } else {\r
+            log.Error("Provider Data Key is not defined", log.Fields{})\r
+            return nil\r
+        }\r
+    }\r
+\r
+    return gobjencs[provider]\r
+}\r
+\r
+func createObjectEncryptor (key []byte, nonce []byte) (IObjectEncryptor, error) {\r
+    // Format key and nonce\r
+    nkey := make([]byte, 32)\r
+    nnonce := make ([]byte, 12)\r
+    for i:=0; i<32; i++ {\r
+        if i < len(key) {\r
+            nkey[i] = key[i]\r
+        } else {\r
+            nkey[i] = 10\r
+        }\r
+    }\r
+\r
+    for i:=0; i<12; i++ {\r
+        if i < len(nonce) {\r
+            nnonce[i] = nonce[i]\r
+        } else {\r
+            nnonce[i] = 10\r
+        }\r
+    }\r
+\r
+    block, err := aes.NewCipher(nkey)\r
+    if err != nil {\r
+        return nil, err\r
+    }\r
+\r
+    aesgcm, err := cipher.NewGCM(block)\r
+    if err != nil {\r
+        return nil, err\r
+    }\r
+\r
+    return &MyObjectEncryptor{aesgcm, nnonce}, nil\r
+}\r
+\r
+func (c *MyObjectEncryptor) EncryptObject(o interface{}) (interface{}, error) {\r
+    return c.processObject(o, false, c.EncryptString)\r
+}\r
+\r
+func (c *MyObjectEncryptor) DecryptObject(o interface{}) (interface{}, error) {\r
+    return c.processObject(o, false, c.DecryptString)\r
+}\r
+\r
+func (c *MyObjectEncryptor) EncryptString(message string) (string, error) {\r
+    ciphermessage := c.gcm.Seal(nil, c.nonce, []byte(message), nil)\r
+    return hex.EncodeToString(ciphermessage), nil\r
+}\r
+\r
+func (c *MyObjectEncryptor) DecryptString(ciphermessage string) (string, error)  {\r
+    cm, err := hex.DecodeString(ciphermessage)\r
+    if err != nil {\r
+        return "", err\r
+    }\r
+\r
+    message, err := c.gcm.Open(nil, c.nonce, cm, nil)\r
+\r
+    if err != nil {\r
+        return "", err\r
+    }\r
+\r
+    return string(message), nil\r
+}\r
+\r
+func (c *MyObjectEncryptor) processObject(o interface{}, encrypt bool, oper func(string)(string, error)) (interface{}, error){\r
+    t := reflect.TypeOf(o)\r
+    switch t.Kind() {\r
+    case reflect.String:\r
+        // only support do encryption on string field\r
+        if encrypt {\r
+            val, err := oper(o.(string))\r
+            if err != nil {\r
+                return nil, err\r
+            }\r
+\r
+            return val, nil\r
+        }\r
+    case reflect.Ptr:\r
+        v := reflect.ValueOf(o)\r
+        newv, err := c.processObject(v.Elem().Interface(), encrypt, oper)\r
+        if err != nil {\r
+            return nil, err\r
+        }\r
+        v.Elem().Set(reflect.ValueOf(newv))\r
+        return o, nil\r
+    case reflect.Struct:\r
+        v := reflect.ValueOf(&o).Elem()\r
+        newv := reflect.New(v.Elem().Type()).Elem()\r
+        newv.Set(v.Elem())\r
+        for k := 0; k < t.NumField(); k++ {\r
+            _, fieldEncrypt := t.Field(k).Tag.Lookup("encrypted")\r
+            isEncrypt := fieldEncrypt || encrypt\r
+            if t.Field(k).IsExported() {\r
+                newf, err := c.processObject(newv.Field(k).Interface(), isEncrypt, oper)\r
+                if err != nil {\r
+                    return nil, err\r
+                }\r
+                newv.Field(k).Set(reflect.ValueOf(newf))\r
+            }\r
+        }\r
+        return newv.Interface(), nil\r
+    case reflect.Array:\r
+        v := reflect.ValueOf(o)\r
+        newv := reflect.New(t).Elem()\r
+        for k:=0; k<v.Len(); k++ {\r
+            newf, err := c.processObject(v.Index(k).Interface(), encrypt, oper)\r
+            if err != nil {\r
+                return nil, err\r
+            }\r
+            newv.Index(k).Set(reflect.ValueOf(newf))\r
+        }\r
+        return newv.Interface(), nil\r
+    case reflect.Slice:\r
+        v := reflect.ValueOf(o)\r
+        newv := reflect.MakeSlice(t, v.Len(), v.Len())\r
+        for  k:=0; k<v.Len(); k++ {\r
+            newf, err := c.processObject(v.Index(k).Interface(), encrypt, oper)\r
+            if err != nil {\r
+                return nil, err\r
+            }\r
+            newv.Index(k).Set(reflect.ValueOf(newf))\r
+        }\r
+        return newv.Interface(), nil\r
+    case reflect.Map:\r
+        v := reflect.ValueOf(o)\r
+        newv := reflect.MakeMap(t)\r
+        for _, k := range v.MapKeys() {\r
+            newf, err := c.processObject(v.MapIndex(k).Interface(), encrypt, oper)\r
+            if err != nil {\r
+                return nil, err\r
+            }\r
+            newv.SetMapIndex(k, reflect.ValueOf(newf))\r
+        }\r
+        return newv.Interface(), nil\r
+    default:\r
+    }\r
+\r
+    return o, nil\r
+}
\ No newline at end of file
@@ -7,6 +7,7 @@ import (
        "archive/tar"
        "compress/gzip"
        "encoding/json"
+       "errors"
        "fmt"
        "io"
        "io/ioutil"
@@ -17,7 +18,7 @@ import (
        "strconv"
        "strings"
 
-       log "github.com/open-ness/EMCO/src/orchestrator/pkg/infra/logutils"
+       log "gitlab.com/project-emco/core/emco-base/src/orchestrator/pkg/infra/logutils"
        pkgerrors "github.com/pkg/errors"
        "github.com/xeipuuv/gojsonschema"
        "k8s.io/apimachinery/pkg/util/validation"
@@ -350,14 +351,16 @@ func ValidateJsonSchemaData(jsonSchemaFile string, jsonData interface{}) (error,
                return pkgerrors.Wrap(err, "JsonSchemaValidation: Validation error"), http.StatusInternalServerError
        }
 
+       var reason string
        // Validate document against Json Schema
        if !result.Valid() {
                for _, desc := range result.Errors() {
                        log.Error("The document is not valid", log.Fields{
                                "param": desc.Field(), "reason": desc.Description(), "req": string(req),
                        })
+                       reason = reason + desc.Description()
                }
-               return pkgerrors.New("JsonSchemaValidation: Document Validation failed"), http.StatusBadRequest
+               return pkgerrors.Wrap(errors.New(reason), "Invalid Input:"), http.StatusBadRequest
        }
 
        return nil, 0
@@ -5,12 +5,11 @@ package controller
 
 import (
        "encoding/json"
-       "strings"
 
-       "github.com/open-ness/EMCO/src/orchestrator/pkg/infra/db"
-       log "github.com/open-ness/EMCO/src/orchestrator/pkg/infra/logutils"
-       rpc "github.com/open-ness/EMCO/src/orchestrator/pkg/infra/rpc"
-       mtypes "github.com/open-ness/EMCO/src/orchestrator/pkg/module/types"
+       "gitlab.com/project-emco/core/emco-base/src/orchestrator/pkg/infra/db"
+       log "gitlab.com/project-emco/core/emco-base/src/orchestrator/pkg/infra/logutils"
+       rpc "gitlab.com/project-emco/core/emco-base/src/orchestrator/pkg/infra/rpc"
+       mtypes "gitlab.com/project-emco/core/emco-base/src/orchestrator/pkg/module/types"
        pkgerrors "github.com/pkg/errors"
 )
 
@@ -37,7 +36,8 @@ var CONTROLLER_TYPES = [...]string{CONTROLLER_TYPE_ACTION, CONTROLLER_TYPE_PLACE
 
 // ControllerKey is the key structure that is used in the database
 type ControllerKey struct {
-       ControllerName string `json:"controller-name"`
+       ControllerName  string `json:"controller"`
+       ControllerGroup string `json:"controllerGroup"`
 }
 
 // We will use json marshalling to convert to string to
@@ -65,14 +65,16 @@ type ControllerManager interface {
 type ControllerClient struct {
        collectionName string
        tagMeta        string
+       tagGroup       string
 }
 
 // NewControllerClient returns an instance of the ControllerClient
 // which implements the Manager
-func NewControllerClient() *ControllerClient {
+func NewControllerClient(name, tag, group string) *ControllerClient {
        return &ControllerClient{
-               collectionName: "controller",
-               tagMeta:        "controllermetadata",
+               collectionName: name,
+               tagMeta:        tag,
+               tagGroup:       group,
        }
 }
 
@@ -83,7 +85,8 @@ func (mc *ControllerClient) CreateController(m Controller, mayExist bool) (Contr
 
        //Construct the composite key to select the entry
        key := ControllerKey{
-               ControllerName: m.Metadata.Name,
+               ControllerName:  m.Metadata.Name,
+               ControllerGroup: mc.tagGroup,
        }
 
        //Check if this Controller already exists
@@ -113,7 +116,7 @@ func (mc *ControllerClient) GetController(name string) (Controller, error) {
        }
        value, err := db.DBconn.Find(mc.collectionName, key, mc.tagMeta)
        if err != nil {
-               return Controller{}, pkgerrors.Wrap(err, "db Find error")
+               return Controller{}, err
        } else if len(value) == 0 {
                return Controller{}, pkgerrors.New("Controller not found")
        }
@@ -122,12 +125,12 @@ func (mc *ControllerClient) GetController(name string) (Controller, error) {
                microserv := Controller{}
                err = db.DBconn.Unmarshal(value[0], &microserv)
                if err != nil {
-                       return Controller{}, pkgerrors.Wrap(err, "Unmarshaling Value")
+                       return Controller{}, err
                }
                return microserv, nil
        }
 
-       return Controller{}, pkgerrors.New("Error getting Controller")
+       return Controller{}, pkgerrors.New("Unknown Error")
 }
 
 // GetControllers returns all the  Controllers that are registered
@@ -135,20 +138,21 @@ func (mc *ControllerClient) GetControllers() ([]Controller, error) {
 
        //Construct the composite key to select the entry
        key := ControllerKey{
-               ControllerName: "",
+               ControllerName:  "",
+               ControllerGroup: mc.tagGroup,
        }
 
        var resp []Controller
        values, err := db.DBconn.Find(mc.collectionName, key, mc.tagMeta)
        if err != nil {
-               return []Controller{}, pkgerrors.Wrap(err, "db Find error")
+               return []Controller{}, err
        }
 
        for _, value := range values {
                microserv := Controller{}
                err = db.DBconn.Unmarshal(value, &microserv)
                if err != nil {
-                       return []Controller{}, pkgerrors.Wrap(err, "Unmarshaling Value")
+                       return []Controller{}, err
                }
 
                resp = append(resp, microserv)
@@ -162,17 +166,12 @@ func (mc *ControllerClient) DeleteController(name string) error {
 
        //Construct the composite key to select the entry
        key := ControllerKey{
-               ControllerName: name,
+               ControllerName:  name,
+               ControllerGroup: mc.tagGroup,
        }
        err := db.DBconn.Remove(mc.collectionName, key)
        if err != nil {
-               if strings.Contains(err.Error(), "Error finding:") {
-                       return pkgerrors.Wrap(err, "db Remove error - not found")
-               } else if strings.Contains(err.Error(), "Can't delete parent without deleting child") {
-                       return pkgerrors.Wrap(err, "db Remove error - conflict")
-               } else {
-                       return pkgerrors.Wrap(err, "db Remove error - general")
-               }
+               return err
        }
 
        // send message to close rpc connection
@@ -8,8 +8,8 @@ import (
        "strings"
        "testing"
 
-       "github.com/open-ness/EMCO/src/orchestrator/pkg/infra/db"
-       "github.com/open-ness/EMCO/src/orchestrator/pkg/module/types"
+       "gitlab.com/project-emco/core/emco-base/src/orchestrator/pkg/infra/db"
+       "gitlab.com/project-emco/core/emco-base/src/orchestrator/pkg/module/types"
 
        pkgerrors "github.com/pkg/errors"
 )
@@ -57,7 +57,7 @@ func TestCreateController(t *testing.T) {
        for _, testCase := range testCases {
                t.Run(testCase.label, func(t *testing.T) {
                        db.DBconn = testCase.mockdb
-                       impl := NewControllerClient()
+                       impl := NewControllerClient("resources", "data", "orchestrator")
                        got, err := impl.CreateController(testCase.inp, false)
                        if err != nil {
                                if testCase.expectedError == "" {
@@ -102,8 +102,8 @@ func TestGetController(t *testing.T) {
                        mockdb: &db.MockDB{
                                Items: []map[string]map[string][]byte{
                                        {
-                                               ControllerKey{ControllerName: "testController"}.String(): {
-                                                       "controllermetadata": []byte(
+                                               ControllerKey{ControllerGroup: "orchestrator", ControllerName: "testController"}.String(): {
+                                                       "data": []byte(
                                                                "{\"metadata\":{" +
                                                                        "\"name\":\"testController\"" +
                                                                        "}," +
@@ -127,7 +127,7 @@ func TestGetController(t *testing.T) {
        for _, testCase := range testCases {
                t.Run(testCase.label, func(t *testing.T) {
                        db.DBconn = testCase.mockdb
-                       impl := NewControllerClient()
+                       impl := NewControllerClient("resources", "data", "orchestrator")
                        got, err := impl.GetController(testCase.name)
                        if err != nil {
                                if testCase.expectedError == "" {
@@ -155,9 +155,23 @@ func TestDeleteController(t *testing.T) {
                mockdb        *db.MockDB
        }{
                {
-                       label:  "Delete Controller",
-                       name:   "testController",
-                       mockdb: &db.MockDB{},
+                       label: "Delete Controller",
+                       name:  "testController",
+                       mockdb: &db.MockDB{
+                               Items: []map[string]map[string][]byte{
+                                       {
+                                               ControllerKey{ControllerGroup: "orchestrator", ControllerName: "testController"}.String(): {
+                                                       "data": []byte(
+                                                               "{\"metadata\":{" +
+                                                                       "\"name\":\"testController\"" +
+                                                                       "}," +
+                                                                       "\"spec\":{" +
+                                                                       "\"host\":\"132.156.0.10\"," +
+                                                                       "\"port\": 8080 }}"),
+                                               },
+                                       },
+                               },
+                       },
                },
                {
                        label:         "Delete Error",
@@ -171,7 +185,7 @@ func TestDeleteController(t *testing.T) {
        for _, testCase := range testCases {
                t.Run(testCase.label, func(t *testing.T) {
                        db.DBconn = testCase.mockdb
-                       impl := NewControllerClient()
+                       impl := NewControllerClient("resources", "data", "orchestrator")
                        err := impl.DeleteController(testCase.name)
                        if err != nil {
                                if testCase.expectedError == "" {
diff --git a/central-controller/src/vendor/gitlab.com/project-emco/core/emco-base/src/orchestrator/pkg/module/types/cluster.go b/central-controller/src/vendor/gitlab.com/project-emco/core/emco-base/src/orchestrator/pkg/module/types/cluster.go
new file mode 100644 (file)
index 0000000..e143abd
--- /dev/null
@@ -0,0 +1,29 @@
+// SPDX-License-Identifier: Apache-2.0
+// Copyright (c) 2020 Intel Corporation
+
+package types
+
+// GitOps shared objects between controllers - clm and rsync
+
+// GitOps Spec
+type GitOpsSpec struct {
+       Props GitOpsProps `json:"gitOps"`
+}
+// GitOps Properties for Reference and Resource Objects
+type GitOpsProps struct {
+       // GitOps type - example Fluxv2, AzureArc, GoogleAnthos
+       GitOpsType            string `json:"gitOpsType"`
+       // Refrence Sync object for the cloud configuration
+       GitOpsReferenceObject string `json:"gitOpsReferenceObject"`
+       // Resource Sync Object for resurces
+       GitOpsResourceObject  string `json:"gitOpsResourceObject"`
+}
+// Sync Objects
+type ClusterSyncObjects struct {
+       Metadata Metadata       `json:"metadata"`
+       Spec     ClusterSyncObjectSpec `json:"spec"`
+}
+// Key value pairs for Sync Objects
+type ClusterSyncObjectSpec struct {
+       Kv []map[string]interface{} `json:"kv" encrypted:""`
+}
\ No newline at end of file
@@ -9,8 +9,8 @@ import (
        "strings"
        "time"
 
-       "github.com/open-ness/EMCO/src/orchestrator/pkg/infra/contextdb"
-       "github.com/open-ness/EMCO/src/orchestrator/pkg/infra/logutils"
+       "gitlab.com/project-emco/core/emco-base/src/orchestrator/pkg/infra/contextdb"
+       "gitlab.com/project-emco/core/emco-base/src/orchestrator/pkg/infra/logutils"
        pkgerrors "github.com/pkg/errors"
 )
 
@@ -301,7 +301,6 @@ func (rtc *RunTimeContext) RtcGetValue(handle interface{}, value interface{}) er
 
        err := contextdb.Db.Get(str, value)
        if err != nil {
-               logutils.Error("contextdb str", logutils.Fields{"str": str})
                return pkgerrors.Errorf("Error getting run time context value: %s", err.Error())
        }
 
index f4c0d64..a4c3589 100644 (file)
@@ -1,14 +1,27 @@
---- SPDX-License-Identifier: Apache-2.0 
+--- SPDX-License-Identifier: Apache-2.0
 --- Copyright (c) 2021 Intel Corporation
 
 module("luci.controller.rest_v1.app_rest", package.seeall)
 
 local uci = require "luci.model.uci"
-
 json = require "luci.jsonc"
 io = require "io"
 sys = require "luci.sys"
 utils = require "luci.controller.rest_v1.utils"
+uci_conf = "app-cnf"
+
+application_validator = {
+    config_type="rule",
+    {name="name"},
+    {name="iplist",validator=function(value) return is_valid_ip(value) end,target="src", message="Invalid Source IP Address"},
+ }
+
+
+ application_processor = {
+    application={create="create_application", delete="delete_application", validator=application_validator},
+    configuration=uci_conf,
+}
+
 
 function index()
     ver = "v1"
@@ -16,202 +29,103 @@ function index()
     entry({"sdewan", configuration, ver, "applications"}, call("handle_request")).leaf = true
 end
 
--- Request Handler
+
+
 function handle_request()
-    local method = utils.get_req_method()
-    if method == "PUT" then
-        return update_application()
-    elseif method == "POST" then
-        return create_application()
-    elseif method == "DELETE" then
-        return delete_application()
-    elseif method == "GET" then
-        return get_application()
-    else
+    local conf = io.open("/etc/config/" .. uci_conf, "r")
+    if conf == nil then
+        conf = io.open("/etc/config/" .. uci_conf, "w")
+    end
+    conf:close()
+    local handler = utils.handles_table[utils.get_req_method()]
+    if handler == nil then
         utils.response_error(405, "Method Not Allowed")
+    else
+        return utils[handler](_M,application_processor)
     end
 end
 
--- Post
-function create_application()
-    local obj = utils.get_request_body_object()
-    if obj == nil then
-        utils.response_error(400, "No Application Data")
-        return
-    end
-    if is_duplicated(obj.name) then
-        utils.response_error(409, "Duplicated Application Configuration")
-        return
-    end
 
-    local file = io.open("/etc/app_cr.info", "a+")
-    if obj.iplist ~= nil then
-        local iplist = utils.split_and_trim(obj.iplist, ',')
-        if not is_valid_ip(iplist) then
-            utils.response_error(400, "Invalid IP Address")
-            return
-        end
-        for _, ip in ipairs(iplist) do
-            local comm = "ip rule add from "..ip.." lookup 40"
-            os.execute(comm)
-        end
+function application_command(rule, op)
+    local comm_list={}
+    local src = rule["iplist"]
 
-        iplist = array_to_string(iplist)
-        file:write(obj.name, " ", iplist, "\n")
+    if src == "" or src == nil then
+        return comm_list
+    end
+    local src_ips = split(src, ',')
+    if op == "create" then
+        for i, ip in ipairs(src_ips) do
+            comm_list[i]="ip rule add from "..ip.." lookup 40"
+        end
     else
-        file:write(obj.name, "\n")
+        for i, ip in ipairs(src_ips) do
+            comm_list[i]="ip rule del from "..ip.." lookup 40"
+        end
     end
-    file:close()
-    luci.http.prepare_content("application/json")
-    luci.http.write_json(obj)
+    return comm_list
 end
 
--- Delete
-function delete_application()
-    local uri_list = utils.get_URI_list(7)
-    if uri_list == nil then
-        return
-    end
-    local name = uri_list[#uri_list]
-    local file = io.open("/etc/app_cr.info", "r")
-    content = {}
-    for line in file:lines() do
-        local message = split(line, ' ')
-        if name ~= message[1] then
-            content[#content+1] = line
-        else
-            if #message ~= 1 then
-                local iplist = split(message[2], ',')
-                for _, ip in ipairs(iplist) do
-                    local comm = "ip rule del from "..ip.." lookup 40"
-                    os.execute(comm)
-                end
-            end
-        end
+
+function create_application(application)
+
+    local application_name =  application.name
+    local res, code, msg = utils.create_uci_section(uci_conf, application_validator, "rule", application)
+    if res == false then
+        uci:revert(uci_conf)
+        return res, code, msg
     end
-    file:close()
-    local file = io.open("/etc/app_cr.info", "w+")
-    for i = 1, #content do
-        file:write(content[i])
+    local comm_list = application_command(application, "create")
+    for _,comm in ipairs(comm_list) do
+        os.execute(comm)
+        utils.log(comm)
     end
-    file:close()
+    uci:save(uci_conf)
+    uci:commit(uci_conf)
+    return true
 end
 
--- Update
-function update_application()
-    local uri_list = utils.get_URI_list(7)
-    if uri_list == nil then
-        return
-    end
-    local name = uri_list[#uri_list]
-    local obj = utils.get_request_body_object()
-    if obj == nil then
-        utils.response_error(400, "Application CR not found")
-        return
+function delete_application(name)
+
+    -- check whether rule is defined
+    local application = utils.get_object(_M, application_processor, "application", name)
+    if application == nil then
+        return false, 404, "application " .. name .. " is not defined"
     end
-    if obj.name ~= name then
-        utils.response_error(400, "Application CR name mismatch")
-        return
+
+    -- delete  rule
+    local comm_list = application_command(application, "delete")
+    for _,comm in ipairs(comm_list) do
+        os.execute(comm)
+        utils.log(comm)
     end
 
-    local file = io.open("/etc/app_cr.info", "r")
-    if obj.iplist ~= nil then
-        local input = utils.split_and_trim(obj.iplist, ",")
-        if not is_valid_ip(input) then
-            utils.response_error(400, "Invalid IP Address")
-            return
-        end
+    utils.delete_uci_section(uci_conf, application_validator, application, "application")
+    -- commit change
+    uci:save(uci_conf)
+    uci:commit(uci_conf)
+
+    return true
 
-        content = {}
-        for line in file:lines() do
-            local message = split(line, ' ')
-            if name ~= message[1] then
-                content[#content+1] = line
-            else
-                if #message ~= 1 then
-                    local iplist = split(message[2], ',')
-                    for _, ip in ipairs(iplist) do
-                        local comm = "ip rule del from "..ip.." lookup 40"
-                        os.execute(comm)
-                    end
-                end
-                for _, ip in ipairs(input) do
-                    local comm = "ip rule add from "..ip.." lookup 40"
-                    os.execute(comm)
-                end
-                local str = array_to_string(input)
-                content[#content+1] = obj.name.." "..str.."\n"
-            end
-        end
-    else
-        for line in file:lines() do
-            local message = split(line, ' ')
-            if name ~= message[1] then
-                content[#content+1] = line
-            else
-                content[#content+1] = obj.name.."\n"
-            end
-        end
-    end
-    file:close()
-    local file = io.open("/etc/app_cr.info", "w+")
-    for i = 1, #content do
-        file:write(content[i])
-    end
-    file:close()
-    luci.http.prepare_content("application/json")
-    luci.http.write_json(obj)
 end
 
--- Get
-function get_application()
-    local uri_list = utils.get_URI_list()
-    local file = io.open("/etc/app_cr.info", "r")
-    if #uri_list == 6 then
-        local objs = {}
-        objs["applications"] = {}
-        for line in file:lines() do
-            local message = split(line, ' ')
-            local obj = {}
-            obj["name"] = message[1]
-            if #message == 1 then
-                obj["iplist"] = ""
-            else
-                obj["iplist"] = message[2]
-            end
-            table.insert(objs["applications"], obj)
-        end
-        luci.http.prepare_content("application/json")
-        luci.http.write_json(objs)
-    elseif #uri_list == 7 then
-        local name = uri_list[#uri_list]
-        local no = true
-        for line in file:lines() do
-            local message = split(line, ' ')
-            if name == message[1] then
-                no = false
-                local obj = {}
-                obj["name"] = message[1]
-                if #message == 1 then
-                    obj["iplist"] = ""
-                else
-                    obj["iplist"] = message[2]
-                end
-                luci.http.prepare_content("application/json")
-                luci.http.write_json(obj)
-                break
+function is_valid_ip(iplist)
+    if iplist ~= nil then
+        local iplist = utils.split_and_trim(iplist, ',')
+        local judge = true
+        for _, ip in ipairs(iplist) do
+            judge, _ = utils.is_valid_ip_address(ip)
+            if not judge then
+                return false
             end
         end
-        if no then
-            utils.response_error(404, "Cannot find ".."application CR ".."[".. name.."]" )
-        end
+        return true
     else
-        utils.response_error(400, "Bad request URI")
+        return false
     end
-    file:close()
 end
 
--- Sync and validate
+
 function split(str,reps)
     local arr = {}
     string.gsub(str,'[^'..reps..']+',function(w)
@@ -220,39 +134,4 @@ function split(str,reps)
     return arr
 end
 
-function is_duplicated(name)
-    local file = io.open("/etc/app_cr.info", "r")
-    local judge = false
-    for line in file:lines() do
-        local message = split(line, ' ')
-        if name == message[1] then
-            judge = true
-            break
-        end
-    end
-    file:close()
-    return judge
-end
 
-function is_valid_ip(iplist)
-    local judge = true
-    for _, ip in ipairs(iplist) do
-        judge, _ = utils.is_valid_ip_address(ip)
-        if not judge then
-            return false
-        end
-    end
-    return true
-end
-
-function array_to_string(arr)
-    local str = ""
-    for _, s in ipairs(arr) do
-        if str == "" then
-            str = s
-        else
-            str = str..","..s
-        end
-    end
-    return str
-end
diff --git a/platform/cnf-openwrt/src/rest_v1/fw_rest.lua b/platform/cnf-openwrt/src/rest_v1/fw_rest.lua
new file mode 100644 (file)
index 0000000..555ee31
--- /dev/null
@@ -0,0 +1,281 @@
+--- SPDX-License-Identifier: Apache-2.0 \r
+--- Copyright (c) 2021 Intel Corporation\r
+\r
+module("luci.controller.rest_v1.fw_rest", package.seeall)\r
+\r
+local uci = require "luci.model.uci"\r
+\r
+json = require "luci.jsonc"\r
+io = require "io"\r
+sys = require "luci.sys"\r
+utils = require "luci.controller.rest_v1.utils"\r
+ifutil = require "luci.controller.rest_v1.ifutil"\r
+\r
+uci_conf = "firewall-rule"\r
+\r
+fw_validator = {\r
+    create_section_name=false,\r
+    object_validator=function(value) return check_rule(value) end,\r
+    {name="name"},\r
+    {name="src", required=true},\r
+    {name="src_val"},\r
+    {name="src_ip", validator=function(value) return utils.is_valid_ip(value) end, message="invalid src_ip"},\r
+    {name="src_mac", validator=function(value) return utils.is_valid_mac(value) end, message="invalid src_mac"},\r
+    {name="src_port", validator=function(value) return utils.is_integer_and_in_range(value, 0) end, message="invalid src_port"},\r
+    {name="proto", validator=function(value) return utils.in_array(value, {"tcp", "udp", "tcpudp", "udplite", "icmp", "esp", "ah", "sctp", "all"}) end, message="invalid proto"},\r
+    {name="icmp_type", is_list=true, item_validator=function(value) return check_icmp_type(value) end, message="invalid icmp_type"},\r
+    {name="dest"},\r
+    {name="dest_val"},\r
+    {name="dest_ip", validator=function(value) return utils.is_valid_ip(value) end, message="invalid dest_ip"},\r
+    {name="dest_port", validator=function(value) return utils.is_integer_and_in_range(value, 0) end, message="invalid dest_port"},\r
+    {name="mark"},\r
+    {name="target", required=true, validator=function(value) return utils.in_array(value, {"ACCEPT", "REJECT", "DROP", "MARK", "NOTRACK"}) end, message="invalid target"},\r
+    {name="set_mark"},\r
+    {name="set_xmark"},\r
+    {name="family", validator=function(value) return utils.in_array(value, {"ipv4", "ipv6", "any"}) end, message="invalid family"},\r
+    {name="extra"},\r
+}\r
+\r
+fw_processor = {\r
+    rule={create="create_rule", delete="delete_rule", validator=fw_validator},\r
+    configuration=uci_conf\r
+}\r
+\r
+function index()\r
+    ver = "v1"\r
+    configuration = "networkfirewall"\r
+    entry({"sdewan", configuration, ver, "rules"}, call("handle_request")).leaf = true\r
+end\r
+\r
+function check_rule(value)\r
+    local target = value["target"]\r
+    if target == "MARK" then\r
+        if value["set_mark"] == nil and value["set_xmark"] == nil then\r
+            return false, "set_mark or set_xmark is required for MARK"\r
+        end\r
+    end\r
+\r
+    -- src\r
+    local src = value["src"]\r
+    local src_val = src\r
+    if utils.start_with(src, "#") then\r
+        local src_name = string.sub(src, 2, string.len(src))\r
+        if src_name == "default" then\r
+            src_val = ifutil.get_default_ifname()\r
+        else\r
+            src_val = ifutil.get_name_by_ip(src_name)\r
+        end\r
+    end\r
+\r
+    if src_val == nil or (not ifutil.is_interface_available(src_val)) then\r
+        return false, "428:Field[src] checked failed: Invalid interface"\r
+    end\r
+\r
+    value["src_val"] = src_val\r
+\r
+    -- dest\r
+    local dest = value["dest"]\r
+    if dest ~= nil then\r
+        local dest_val = dest\r
+        if utils.start_with(dest, "#") then\r
+            local dest_name = string.sub(dest, 2, string.len(dest))\r
+            if dest_name == "default" then\r
+                dest_val = ifutil.get_default_ifname()\r
+            else\r
+                dest_val = ifutil.get_name_by_ip(dest_name)\r
+            end\r
+        end\r
+\r
+        if dest_val == nil or (not ifutil.is_interface_available(dest_val)) then\r
+            return false, "428:Field[dest] checked failed: Invalid interface"\r
+        end\r
+\r
+        value["dest_val"] = dest_val\r
+    end\r
+\r
+    return true, value\r
+end\r
+\r
+function check_icmp_type(value)\r
+    return utils.in_array(value, {"address-mask-reply", "address-mask-request", "any", "communication-prohibited",\r
+        "destination-unreachable", "echo-reply", "echo-request", "fragmentation-needed", "host-precedence-violation",\r
+        "host-prohibited", "host-redirect", "host-unknown", "host-unreachable", "ip-header-bad", "network-prohibited",\r
+        "network-redirect", "network-unknown", "network-unreachable", "parameter-problem", "ping", "pong",\r
+        "port-unreachable", "precedence-cutoff", "protocol-unreachable", "redirect", "required-option-missing",\r
+        "router-advertisement", "router-solicitation", "source-quench", "source-route-failed", "time-exceeded",\r
+        "timestamp-reply", "timestamp-request", "TOS-host-redirect", "TOS-host-unreachable", "TOS-network-redirect",\r
+        "TOS-network-unreachable", "ttl-exceeded", "ttl-zero-during-reassembly", "ttl-zero-during-transit"})\r
+end\r
+\r
+-- Request Handler\r
+function handle_request()\r
+    local conf = io.open("/etc/config/" .. uci_conf, "r")\r
+    if conf == nil then\r
+        conf = io.open("/etc/config/" .. uci_conf, "w")\r
+    end\r
+    conf:close()\r
+\r
+    local handler = utils.handles_table[utils.get_req_method()]\r
+    if handler == nil then\r
+        utils.response_error(405, "Method Not Allowed")\r
+    else\r
+        return utils[handler](_M, fw_processor)\r
+    end\r
+end\r
+\r
+-- generate iptables command for rule\r
+function rule_commands(rule, op)\r
+    local target = rule["target"]\r
+    local proto = rule["proto"]\r
+    if proto == nil then\r
+        proto = "all"\r
+    end\r
+    local family = rule["family"]\r
+    local extra = rule["extra"]\r
+\r
+    local src_val = rule["src_val"]\r
+    local src_ip = rule["src_ip"]\r
+    local src_mac = rule["src_mac"]\r
+    local src_port = rule["src_port"]\r
+    \r
+    local icmp_type = rule["icmp_type"]\r
+\r
+    local dest_val = rule["dest_val"]\r
+    local dest_ip = rule["dest_ip"]\r
+    local dest_port = rule["dest_port"]\r
+    \r
+    local mark = rule["mark"]\r
+    local set_mark = rule["set_mark"]\r
+    local set_xmark = rule["set_xmark"]\r
+\r
+    local comms = {}\r
+\r
+    local comm = "iptables"\r
+    local chain = "INPUT"\r
+    if dest_val ~= nil then\r
+        chain = "FORWARD"\r
+    end\r
+    if target == "MARK" then\r
+        comm = comm .. " -t mangle"\r
+        chain = "PREROUTING"\r
+    end\r
+\r
+    if op == "create" then\r
+        comm = comm .. " -A " .. chain\r
+    else\r
+        comm = comm .. " -D " .. chain\r
+    end\r
+\r
+    comm = comm .. " -i " .. src_val\r
+    if dest_val ~= nil and dest_val ~= "" and target ~= "MARK" then\r
+        comm = comm .. " -o " .. dest_val\r
+    end\r
+    if src_ip ~= nil and src_ip ~= "" then\r
+        comm = comm .. " -s " .. src_ip\r
+    end\r
+    if dest_ip ~= nil and dest_ip ~= "" then\r
+        comm = comm .. " -d " .. dest_ip\r
+    end\r
+\r
+    local post_comm = ""\r
+    if src_mac ~= nil and src_mac ~= "" then\r
+        post_comm = post_comm .. " -m mac --mac-source " .. src_mac\r
+    end\r
+    if mark ~= nil and mark ~= "" then\r
+        post_comm = post_comm .. " -m mark --mark " .. mark\r
+    end\r
+    post_comm = post_comm .. " -j " .. target\r
+    if target == "MARK" then\r
+        if set_xmark ~= nil and set_xmark ~= "" then\r
+            post_comm = post_comm .. " --set-xmark " .. set_xmark\r
+        else\r
+            if set_mark ~= nil and set_mark ~= "" then\r
+                post_comm = post_comm .. " --set-mark " .. set_mark\r
+            end\r
+        end\r
+    end\r
+\r
+    local port_val = ""\r
+    if src_port ~= nil and src_port ~= "" then\r
+        port_val = port_val .. " --sport " .. src_port\r
+    end\r
+    if dest_port ~= nil and dest_port ~= "" then\r
+        port_val = port_val .. " --dport " .. dest_port\r
+    end\r
+    local proto_vals = {}\r
+    if proto == "all" then\r
+        proto_vals[1] = ""\r
+    end\r
+    if proto == "tcp" then\r
+        proto_vals[1] = " -p tcp -m tcp" .. port_val\r
+    end\r
+    if proto == "udp" then\r
+        proto_vals[1] = " -p udp -m udp" .. port_val\r
+    end\r
+    if proto == "tcpudp" then\r
+        proto_vals[1] = " -p tcp -m tcp" .. port_val\r
+        proto_vals[2] = " -p udp -m udp" .. port_val\r
+    end\r
+    if proto == "icmp" then\r
+        for j=1, #icmp_type do\r
+            proto_vals[j] = " -p icmp -m icmp --icmp-type " .. icmp_type[j]\r
+        end\r
+    end\r
+    if proto == "udplite" or proto == "esp" or proto == "ah" or proto == "sctp" then\r
+        proto_vals[1] = " -p " .. proto\r
+    end\r
+    \r
+    for j=1, #proto_vals do\r
+        comms[j] = comm .. proto_vals[j] .. post_comm\r
+    end\r
+\r
+    return comms\r
+end\r
+\r
+-- create a rule\r
+function create_rule(rule)\r
+    local name = rule.name\r
+    local res, code, msg = utils.create_uci_section(uci_conf, fw_validator, "rule", rule)\r
+\r
+    if res == false then\r
+        uci:revert(uci_conf)\r
+        return res, code, msg\r
+    end\r
+\r
+    -- create firewall rule\r
+    local comms = rule_commands(rule, "create")\r
+    for j=1, #comms do\r
+        utils.log(comms[j])\r
+        os.execute(comms[j])\r
+    end\r
+\r
+    -- commit change\r
+    uci:save(uci_conf)\r
+    uci:commit(uci_conf)\r
+\r
+    return true\r
+end\r
+\r
+-- delete a rule\r
+function delete_rule(name)\r
+    -- check whether rule is defined\r
+    local rule = utils.get_object(_M, fw_processor, "rule", name)\r
+    if rule == nil then\r
+        return false, 404, "rule " .. name .. " is not defined"\r
+    end\r
+\r
+    -- delete rule rule in iptable\r
+    local comms = rule_commands(rule, "delete")\r
+    for j=1, #comms do\r
+        utils.log(comms[j])\r
+        os.execute(comms[j])\r
+    end\r
+\r
+    utils.delete_uci_section(uci_conf, fw_validator, rule, "rule")\r
+\r
+    -- commit change\r
+    uci:save(uci_conf)\r
+    uci:commit(uci_conf)\r
+\r
+    return true\r
+end
\ No newline at end of file
index 6c1bbf3..75ae20a 100644 (file)
@@ -8,6 +8,7 @@ function index()
     entry({"sdewan", ver}, call("help")).dependent = false
     entry({"sdewan", "mwan3", ver}, call("help")).dependent = false
     entry({"sdewan", "firewall", ver}, call("help")).dependent = false
+    entry({"sdewan", "networkfirewall", ver}, call("help")).dependent = false
     entry({"sdewan", "ipsec", ver}, call("help")).dependent = false
     entry({"sdewan", "service", ver}, call("help")).dependent = false
     entry({"sdewan", "application", ver}, call("help")).dependent = false
index 42eb5e3..6cdea45 100644 (file)
@@ -66,7 +66,7 @@ func wildMatchArray(p []rune, pindex int, v []rune, vindex int) bool {
        return true
 }
 
-// +kubebuilder:webhook:path=/validate-sdewan-bucket-permission,mutating=false,failurePolicy=fail,groups="batch.sdewan.akraino.org",resources=mwan3policies;mwan3rules;firewallzones;firewallforwardings;firewallrules;firewallsnats;firewalldnats;cnfnats;cnfroutes;cnfrouterules;cnfservices;cnflocalservices;cnfstatuses;sdewanapplication;ipsecproposals;ipsechosts;ipsecsites,verbs=create;update;delete,versions=v1,name=validate-sdewan-bucket.akraino.org,admissionReviewVersions=v1,sideEffects=none
+// +kubebuilder:webhook:path=/validate-sdewan-bucket-permission,mutating=false,failurePolicy=fail,groups="batch.sdewan.akraino.org",resources=mwan3policies;mwan3rules;networkfirewallrules;firewallzones;firewallforwardings;firewallrules;firewallsnats;firewalldnats;cnfnats;cnfroutes;cnfrouterules;cnfservices;cnflocalservices;cnfhubsites;cnfstatuses;sdewanapplication;ipsecproposals;ipsechosts;ipsecsites,verbs=create;update;delete,versions=v1,name=validate-sdewan-bucket.akraino.org,admissionReviewVersions=v1,sideEffects=none
 
 // bucketPermissionValidator validates Pods
 type bucketPermissionValidator struct {
@@ -114,6 +114,8 @@ func (v *bucketPermissionValidator) Handle(ctx context.Context, req admission.Re
                obj = &FirewallZone{}
        case "FirewallRule":
                obj = &FirewallRule{}
+       case "NetworkFirewallRule":
+               obj = &NetworkFirewallRule{}
        case "CNFNAT":
                obj = &CNFNAT{}
        case "CNFRoute":
@@ -136,6 +138,8 @@ func (v *bucketPermissionValidator) Handle(ctx context.Context, req admission.Re
                obj = &CNFStatus{}
        case "CNFLocalService":
                obj = &CNFLocalService{}
+       case "CNFHubSite":
+               obj = &CNFHubSite{}
        case "SdewanApplication":
                obj = &SdewanApplication{}
        default:
diff --git a/platform/crd-ctrlr/src/api/v1alpha1/cnfhubsite_types.go b/platform/crd-ctrlr/src/api/v1alpha1/cnfhubsite_types.go
new file mode 100644 (file)
index 0000000..9499bd6
--- /dev/null
@@ -0,0 +1,83 @@
+// SPDX-License-Identifier: Apache-2.0\r
+// Copyright (c) 2021 Intel Corporation\r
+package v1alpha1\r
+\r
+import (\r
+       metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"\r
+)\r
+\r
+// EDIT THIS FILE!  THIS IS SCAFFOLDING FOR YOU TO OWN!\r
+// NOTE: json tags are required.  Any new fields you add must have json tags for the fields to be serialized.\r
+\r
+// CNFHubSiteStatus defines the observed state of CNFHubSiteStatus\r
+type CNFHubSiteStatus struct {\r
+       // INSERT ADDITIONAL STATUS FIELD - define observed state of cluster\r
+       // Important: Run "make" to regenerate code after modifying this file\r
+       // +optional\r
+       Type      string `json:"type,omitempty"`\r
+       // +optional\r
+       SiteIPs []string `json:"remoteips,omitempty"`\r
+       // +optional\r
+       Subnet    string `json:"subnet,omitempty"`\r
+       // +optional\r
+       HubIP     string `json:"hubip,omitempty"`\r
+       // +optional\r
+       DevicePIP string `json:"devicepip,omitempty"`\r
+       // +optional\r
+       Message string `json:"message,omitempty"`\r
+}\r
+\r
+func (c *CNFHubSiteStatus) IsEqual(s *CNFHubSiteStatus) bool {\r
+       if c.Type != s.Type ||\r
+           c.Subnet != s.Subnet ||\r
+               c.HubIP != s.HubIP ||\r
+               c.DevicePIP != s.DevicePIP {\r
+               return false\r
+       }\r
+\r
+       if len(c.SiteIPs) != len(s.SiteIPs) {\r
+               return false\r
+       }\r
+\r
+       for i := 0; i < len(c.SiteIPs); i++ {\r
+               if c.SiteIPs[i] != s.SiteIPs[i] {\r
+                       return false\r
+               }\r
+       }\r
+\r
+       return true\r
+}\r
+\r
+// CNFHubSiteSpec defines the desired state of CNFHubSite\r
+type CNFHubSiteSpec struct {\r
+       Type      string `json:"type,omitempty"`\r
+       Site      string `json:"site,omitempty"`\r
+       Subnet    string `json:"subnet,omitempty"`\r
+       HubIP     string `json:"hubip,omitempty"`\r
+       DevicePIP string `json:"devicepip,omitempty"`\r
+}\r
+\r
+// +kubebuilder:object:root=true\r
+// +kubebuilder:subresource:status\r
+\r
+// CNFHubSite is the Schema for the cnfhubsites API\r
+type CNFHubSite struct {\r
+       metav1.TypeMeta   `json:",inline"`\r
+       metav1.ObjectMeta `json:"metadata,omitempty"`\r
+\r
+       Spec   CNFHubSiteSpec   `json:"spec,omitempty"`\r
+       Status CNFHubSiteStatus `json:"status,omitempty"`\r
+}\r
+\r
+// +kubebuilder:object:root=true\r
+\r
+// CNFHubSiteList contains a list of CNFHubSite\r
+type CNFHubSiteList struct {\r
+       metav1.TypeMeta `json:",inline"`\r
+       metav1.ListMeta `json:"metadata,omitempty"`\r
+       Items           []CNFHubSite `json:"items"`\r
+}\r
+\r
+func init() {\r
+       SchemeBuilder.Register(&CNFHubSite{}, &CNFHubSiteList{})\r
+}
\ No newline at end of file
index 7f90bec..3bc589f 100644 (file)
@@ -16,6 +16,30 @@ type CNFServiceSpec struct {
        DPort    string `json:"dport,omitempty"`
 }
 
+func (c *CNFServiceStatus) IsEqual(s *CNFServiceStatus) bool {
+       if c.Port != s.Port ||
+               c.DPort != s.DPort ||
+               c.SIp != s.SIp {
+               return false
+       }
+
+       return true
+}
+
+// CNFServiceStatus defines the observed state of CNFLocalServiceStatus
+type CNFServiceStatus struct {
+       // INSERT ADDITIONAL STATUS FIELD - define observed state of cluster
+       // Important: Run "make" to regenerate code after modifying this file
+       // +optional
+       SIp string `json:"sip,omitempty"`
+       // +optional
+       Port string `json:"port,omitempty"`
+       // +optional
+       DPort string `json:"dport,omitempty"`
+       // +optional
+       Message string `json:"message,omitempty"`
+}
+
 // +kubebuilder:object:root=true
 // +kubebuilder:subresource:status
 
@@ -24,8 +48,8 @@ type CNFService struct {
        metav1.TypeMeta   `json:",inline"`
        metav1.ObjectMeta `json:"metadata,omitempty"`
 
-       Spec   CNFServiceSpec `json:"spec,omitempty"`
-       Status SdewanStatus   `json:"status,omitempty"`
+       Spec   CNFServiceSpec   `json:"spec,omitempty"`
+       Status CNFServiceStatus `json:"status,omitempty"`
 }
 
 // +kubebuilder:object:root=true
index 3564748..c43e2b2 100644 (file)
@@ -29,7 +29,7 @@ func SetupLabelValidateWebhookWithManager(mgr ctrl.Manager) error {
        return nil
 }
 
-// +kubebuilder:webhook:path=/validate-label,mutating=false,failurePolicy=fail,groups=apps;batch.sdewan.akraino.org,resources=deployments;mwan3policies;mwan3rules;firewallzones;firewallforwardings;firewallrules;firewallsnats;firewalldnats;cnfnats;cnfservices;cnfroutes;cnfrouterules;cnflocalservices;cnfstatuses;sdewanapplication;ipsecproposals;ipsechosts;ipsecsites,verbs=update,versions=v1,name=validate-label.akraino.org,admissionReviewVersions=v1,sideEffects=none
+// +kubebuilder:webhook:path=/validate-label,mutating=false,failurePolicy=fail,groups=apps;batch.sdewan.akraino.org,resources=mwan3policies;mwan3rules;networkfirewallrules;firewallzones;firewallforwardings;firewallrules;firewallsnats;firewalldnats;cnfnats;cnfservices;cnfroutes;cnfrouterules;cnflocalservices;cnfhubsites;cnfstatuses;sdewanapplication;ipsecproposals;ipsechosts;ipsecsites,verbs=update,versions=v1,name=validate-label.akraino.org,admissionReviewVersions=v1,sideEffects=none
 
 type labelValidator struct {
        Client  client.Client
@@ -45,6 +45,8 @@ func (v *labelValidator) Handle(ctx context.Context, req admission.Request) admi
                obj = &Mwan3Policy{}
        case "Mwan3Rule":
                obj = &Mwan3Rule{}
+       case "NetworkFirewallRule":
+               obj = &NetworkFirewallRule{}
        case "FirewallForwarding":
                obj = &FirewallForwarding{}
        case "FirewallZone":
@@ -71,6 +73,8 @@ func (v *labelValidator) Handle(ctx context.Context, req admission.Request) admi
                obj = &CNFService{}
        case "CNFLocalService":
                obj = &CNFLocalService{}
+       case "CNFHubSite":
+               obj = &CNFHubSite{}
        case "CNFStatus":
                obj = &CNFStatus{}
        case "SdewanApplication":
diff --git a/platform/crd-ctrlr/src/api/v1alpha1/networkfirewallrule_types.go b/platform/crd-ctrlr/src/api/v1alpha1/networkfirewallrule_types.go
new file mode 100644 (file)
index 0000000..563df73
--- /dev/null
@@ -0,0 +1,59 @@
+// SPDX-License-Identifier: Apache-2.0\r
+// Copyright (c) 2021 Intel Corporation\r
+package v1alpha1\r
+\r
+import (\r
+       metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"\r
+)\r
+\r
+// EDIT THIS FILE!  THIS IS SCAFFOLDING FOR YOU TO OWN!\r
+// NOTE: json tags are required.  Any new fields you add must have json tags for the fields to be serialized.\r
+\r
+// NetworkFirewallRuleSpec defines the desired state of NetworkFirewallRule\r
+type NetworkFirewallRuleSpec struct {\r
+       // INSERT ADDITIONAL SPEC FIELDS - desired state of cluster\r
+       // Important: Run "make" to regenerate code after modifying this file\r
+\r
+       // Foo is an example field of NetworkFirewallRule. Edit NetworkFirewallRule_types.go to remove/update\r
+       Name     string   `json:"name,omitempty"`\r
+       Src      string   `json:"src,omitempty"`\r
+       SrcIp    string   `json:"src_ip,omitempty"`\r
+       SrcMac   string   `json:"src_mac,omitempty"`\r
+       SrcPort  string   `json:"src_port,omitempty"`\r
+       Proto    string   `json:"proto,omitempty"`\r
+       IcmpType []string `json:"icmp_type,omitempty"`\r
+       Dest     string   `json:"dest,omitempty"`\r
+       DestIp   string   `json:"dest_ip,omitempty"`\r
+       DestPort string   `json:"dest_port,omitempty"`\r
+       Mark     string   `json:"mark,omitempty"`\r
+       Target   string   `json:"target,omitempty"`\r
+       SetMark  string   `json:"set_mark,omitempty"`\r
+       SetXmark string   `json:"set_xmark,omitempty"`\r
+       Family   string   `json:"family,omitempty"`\r
+       Extra    string   `json:"extra,omitempty"`\r
+}\r
+\r
+// +kubebuilder:object:root=true\r
+// +kubebuilder:subresource:status\r
+\r
+// NetworkFirewallRule is the Schema for the networkfirewallrules API\r
+type NetworkFirewallRule struct {\r
+       metav1.TypeMeta   `json:",inline"`\r
+       metav1.ObjectMeta `json:"metadata,omitempty"`\r
+\r
+       Spec   NetworkFirewallRuleSpec `json:"spec,omitempty"`\r
+       Status SdewanStatus     `json:"status,omitempty"`\r
+}\r
+\r
+// +kubebuilder:object:root=true\r
+\r
+// NetworkFirewallRuleList contains a list of NetworkFirewallRule\r
+type NetworkFirewallRuleList struct {\r
+       metav1.TypeMeta `json:",inline"`\r
+       metav1.ListMeta `json:"metadata,omitempty"`\r
+       Items           []NetworkFirewallRule `json:"items"`\r
+}\r
+\r
+func init() {\r
+       SchemeBuilder.Register(&NetworkFirewallRule{}, &NetworkFirewallRuleList{})\r
+}\r
index 046a318..13322eb 100644 (file)
@@ -9,56 +9,56 @@
 package v1alpha1
 
 import (
-       "k8s.io/apimachinery/pkg/apis/meta/v1"
-       "k8s.io/apimachinery/pkg/runtime"
+        "k8s.io/apimachinery/pkg/apis/meta/v1"
+        "k8s.io/apimachinery/pkg/runtime"
 )
 
 // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
 func (in *ApplicationInfo) DeepCopyInto(out *ApplicationInfo) {
-       *out = *in
+        *out = *in
 }
 
 // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ApplicationInfo.
 func (in *ApplicationInfo) DeepCopy() *ApplicationInfo {
-       if in == nil {
-               return nil
-       }
-       out := new(ApplicationInfo)
-       in.DeepCopyInto(out)
-       return out
+        if in == nil {
+                return nil
+        }
+        out := new(ApplicationInfo)
+        in.DeepCopyInto(out)
+        return out
 }
 
 // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
 func (in BucketPermission) DeepCopyInto(out *BucketPermission) {
-       {
-               in := &in
-               *out = make(BucketPermission, len(*in))
-               for key, val := range *in {
-                       var outVal []string
-                       if val == nil {
-                               (*out)[key] = nil
-                       } else {
-                               in, out := &val, &outVal
-                               *out = make([]string, len(*in))
-                               copy(*out, *in)
-                       }
-                       (*out)[key] = outVal
-               }
-       }
+        {
+                in := &in
+                *out = make(BucketPermission, len(*in))
+                for key, val := range *in {
+                        var outVal []string
+                        if val == nil {
+                                (*out)[key] = nil
+                        } else {
+                                in, out := &val, &outVal
+                                *out = make([]string, len(*in))
+                                copy(*out, *in)
+                        }
+                        (*out)[key] = outVal
+                }
+        }
 }
 
 // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new BucketPermission.
 func (in BucketPermission) DeepCopy() BucketPermission {
-       if in == nil {
-               return nil
-       }
-       out := new(BucketPermission)
-       in.DeepCopyInto(out)
-       return *out
+        if in == nil {
+                return nil
+        }
+        out := new(BucketPermission)
+        in.DeepCopyInto(out)
+        return *out
 }
 
 // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
-func (in *CNFLocalService) DeepCopyInto(out *CNFLocalService) {
+func (in *CNFHubSite) DeepCopyInto(out *CNFHubSite) {
        *out = *in
        out.TypeMeta = in.TypeMeta
        in.ObjectMeta.DeepCopyInto(&out.ObjectMeta)
@@ -66,18 +66,18 @@ func (in *CNFLocalService) DeepCopyInto(out *CNFLocalService) {
        in.Status.DeepCopyInto(&out.Status)
 }
 
-// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new CNFLocalService.
-func (in *CNFLocalService) DeepCopy() *CNFLocalService {
+// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new CNFHubSite.
+func (in *CNFHubSite) DeepCopy() *CNFHubSite {
        if in == nil {
                return nil
        }
-       out := new(CNFLocalService)
+       out := new(CNFHubSite)
        in.DeepCopyInto(out)
        return out
 }
 
 // DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object.
-func (in *CNFLocalService) DeepCopyObject() runtime.Object {
+func (in *CNFHubSite) DeepCopyObject() runtime.Object {
        if c := in.DeepCopy(); c != nil {
                return c
        }
@@ -85,31 +85,31 @@ func (in *CNFLocalService) DeepCopyObject() runtime.Object {
 }
 
 // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
-func (in *CNFLocalServiceList) DeepCopyInto(out *CNFLocalServiceList) {
+func (in *CNFHubSiteList) DeepCopyInto(out *CNFHubSiteList) {
        *out = *in
        out.TypeMeta = in.TypeMeta
        in.ListMeta.DeepCopyInto(&out.ListMeta)
        if in.Items != nil {
                in, out := &in.Items, &out.Items
-               *out = make([]CNFLocalService, len(*in))
+               *out = make([]CNFHubSite, len(*in))
                for i := range *in {
                        (*in)[i].DeepCopyInto(&(*out)[i])
                }
        }
 }
 
-// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new CNFLocalServiceList.
-func (in *CNFLocalServiceList) DeepCopy() *CNFLocalServiceList {
+// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new CNFHubSiteList.
+func (in *CNFHubSiteList) DeepCopy() *CNFHubSiteList {
        if in == nil {
                return nil
        }
-       out := new(CNFLocalServiceList)
+       out := new(CNFHubSiteList)
        in.DeepCopyInto(out)
        return out
 }
 
 // DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object.
-func (in *CNFLocalServiceList) DeepCopyObject() runtime.Object {
+func (in *CNFHubSiteList) DeepCopyObject() runtime.Object {
        if c := in.DeepCopy(); c != nil {
                return c
        }
@@ -117,1300 +117,1408 @@ func (in *CNFLocalServiceList) DeepCopyObject() runtime.Object {
 }
 
 // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
-func (in *CNFLocalServiceSpec) DeepCopyInto(out *CNFLocalServiceSpec) {
+func (in *CNFHubSiteSpec) DeepCopyInto(out *CNFHubSiteSpec) {
        *out = *in
 }
 
-// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new CNFLocalServiceSpec.
-func (in *CNFLocalServiceSpec) DeepCopy() *CNFLocalServiceSpec {
+// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new CNFHubSiteSpec.
+func (in *CNFHubSiteSpec) DeepCopy() *CNFHubSiteSpec {
        if in == nil {
                return nil
        }
-       out := new(CNFLocalServiceSpec)
+       out := new(CNFHubSiteSpec)
        in.DeepCopyInto(out)
        return out
 }
 
 // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
-func (in *CNFLocalServiceStatus) DeepCopyInto(out *CNFLocalServiceStatus) {
+func (in *CNFHubSiteStatus) DeepCopyInto(out *CNFHubSiteStatus) {
        *out = *in
-       if in.RemoteIPs != nil {
-               in, out := &in.RemoteIPs, &out.RemoteIPs
+       if in.SiteIPs != nil {
+               in, out := &in.SiteIPs, &out.SiteIPs
                *out = make([]string, len(*in))
                copy(*out, *in)
        }
 }
 
-// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new CNFLocalServiceStatus.
-func (in *CNFLocalServiceStatus) DeepCopy() *CNFLocalServiceStatus {
+// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new CNFHubSiteStatus.
+func (in *CNFHubSiteStatus) DeepCopy() *CNFHubSiteStatus {
        if in == nil {
                return nil
        }
-       out := new(CNFLocalServiceStatus)
+       out := new(CNFHubSiteStatus)
        in.DeepCopyInto(out)
        return out
 }
 
+// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
+func (in *CNFLocalService) DeepCopyInto(out *CNFLocalService) {
+        *out = *in
+        out.TypeMeta = in.TypeMeta
+        in.ObjectMeta.DeepCopyInto(&out.ObjectMeta)
+        out.Spec = in.Spec
+        in.Status.DeepCopyInto(&out.Status)
+}
+
+// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new CNFLocalService.
+func (in *CNFLocalService) DeepCopy() *CNFLocalService {
+        if in == nil {
+                return nil
+        }
+        out := new(CNFLocalService)
+        in.DeepCopyInto(out)
+        return out
+}
+
+// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object.
+func (in *CNFLocalService) 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 *CNFLocalServiceList) DeepCopyInto(out *CNFLocalServiceList) {
+        *out = *in
+        out.TypeMeta = in.TypeMeta
+        in.ListMeta.DeepCopyInto(&out.ListMeta)
+        if in.Items != nil {
+                in, out := &in.Items, &out.Items
+                *out = make([]CNFLocalService, len(*in))
+                for i := range *in {
+                        (*in)[i].DeepCopyInto(&(*out)[i])
+                }
+        }
+}
+
+// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new CNFLocalServiceList.
+func (in *CNFLocalServiceList) DeepCopy() *CNFLocalServiceList {
+        if in == nil {
+                return nil
+        }
+        out := new(CNFLocalServiceList)
+        in.DeepCopyInto(out)
+        return out
+}
+
+// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object.
+func (in *CNFLocalServiceList) 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 *CNFLocalServiceSpec) DeepCopyInto(out *CNFLocalServiceSpec) {
+        *out = *in
+}
+
+// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new CNFLocalServiceSpec.
+func (in *CNFLocalServiceSpec) DeepCopy() *CNFLocalServiceSpec {
+        if in == nil {
+                return nil
+        }
+        out := new(CNFLocalServiceSpec)
+        in.DeepCopyInto(out)
+        return out
+}
+
+// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
+func (in *CNFLocalServiceStatus) DeepCopyInto(out *CNFLocalServiceStatus) {
+        *out = *in
+        if in.RemoteIPs != nil {
+                in, out := &in.RemoteIPs, &out.RemoteIPs
+                *out = make([]string, len(*in))
+                copy(*out, *in)
+        }
+}
+
+// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new CNFLocalServiceStatus.
+func (in *CNFLocalServiceStatus) DeepCopy() *CNFLocalServiceStatus {
+        if in == nil {
+                return nil
+        }
+        out := new(CNFLocalServiceStatus)
+        in.DeepCopyInto(out)
+        return out
+}
+
 // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
 func (in *CNFNAT) DeepCopyInto(out *CNFNAT) {
-       *out = *in
-       out.TypeMeta = in.TypeMeta
-       in.ObjectMeta.DeepCopyInto(&out.ObjectMeta)
-       out.Spec = in.Spec
-       in.Status.DeepCopyInto(&out.Status)
+        *out = *in
+        out.TypeMeta = in.TypeMeta
+        in.ObjectMeta.DeepCopyInto(&out.ObjectMeta)
+        out.Spec = in.Spec
+        in.Status.DeepCopyInto(&out.Status)
 }
 
 // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new CNFNAT.
 func (in *CNFNAT) DeepCopy() *CNFNAT {
-       if in == nil {
-               return nil
-       }
-       out := new(CNFNAT)
-       in.DeepCopyInto(out)
-       return out
+        if in == nil {
+                return nil
+        }
+        out := new(CNFNAT)
+        in.DeepCopyInto(out)
+        return out
 }
 
 // DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object.
 func (in *CNFNAT) DeepCopyObject() runtime.Object {
-       if c := in.DeepCopy(); c != nil {
-               return c
-       }
-       return nil
+        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 *CNFNATList) DeepCopyInto(out *CNFNATList) {
-       *out = *in
-       out.TypeMeta = in.TypeMeta
-       in.ListMeta.DeepCopyInto(&out.ListMeta)
-       if in.Items != nil {
-               in, out := &in.Items, &out.Items
-               *out = make([]CNFNAT, len(*in))
-               for i := range *in {
-                       (*in)[i].DeepCopyInto(&(*out)[i])
-               }
-       }
+        *out = *in
+        out.TypeMeta = in.TypeMeta
+        in.ListMeta.DeepCopyInto(&out.ListMeta)
+        if in.Items != nil {
+                in, out := &in.Items, &out.Items
+                *out = make([]CNFNAT, len(*in))
+                for i := range *in {
+                        (*in)[i].DeepCopyInto(&(*out)[i])
+                }
+        }
 }
 
 // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new CNFNATList.
 func (in *CNFNATList) DeepCopy() *CNFNATList {
-       if in == nil {
-               return nil
-       }
-       out := new(CNFNATList)
-       in.DeepCopyInto(out)
-       return out
+        if in == nil {
+                return nil
+        }
+        out := new(CNFNATList)
+        in.DeepCopyInto(out)
+        return out
 }
 
 // DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object.
 func (in *CNFNATList) DeepCopyObject() runtime.Object {
-       if c := in.DeepCopy(); c != nil {
-               return c
-       }
-       return nil
+        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 *CNFNATSpec) DeepCopyInto(out *CNFNATSpec) {
-       *out = *in
+        *out = *in
 }
 
 // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new CNFNATSpec.
 func (in *CNFNATSpec) DeepCopy() *CNFNATSpec {
-       if in == nil {
-               return nil
-       }
-       out := new(CNFNATSpec)
-       in.DeepCopyInto(out)
-       return out
+        if in == nil {
+                return nil
+        }
+        out := new(CNFNATSpec)
+        in.DeepCopyInto(out)
+        return out
 }
 
 // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
 func (in *CNFRoute) DeepCopyInto(out *CNFRoute) {
-       *out = *in
-       out.TypeMeta = in.TypeMeta
-       in.ObjectMeta.DeepCopyInto(&out.ObjectMeta)
-       out.Spec = in.Spec
-       in.Status.DeepCopyInto(&out.Status)
+        *out = *in
+        out.TypeMeta = in.TypeMeta
+        in.ObjectMeta.DeepCopyInto(&out.ObjectMeta)
+        out.Spec = in.Spec
+        in.Status.DeepCopyInto(&out.Status)
 }
 
 // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new CNFRoute.
 func (in *CNFRoute) DeepCopy() *CNFRoute {
-       if in == nil {
-               return nil
-       }
-       out := new(CNFRoute)
-       in.DeepCopyInto(out)
-       return out
+        if in == nil {
+                return nil
+        }
+        out := new(CNFRoute)
+        in.DeepCopyInto(out)
+        return out
 }
 
 // DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object.
 func (in *CNFRoute) DeepCopyObject() runtime.Object {
-       if c := in.DeepCopy(); c != nil {
-               return c
-       }
-       return nil
+        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 *CNFRouteList) DeepCopyInto(out *CNFRouteList) {
-       *out = *in
-       out.TypeMeta = in.TypeMeta
-       in.ListMeta.DeepCopyInto(&out.ListMeta)
-       if in.Items != nil {
-               in, out := &in.Items, &out.Items
-               *out = make([]CNFRoute, len(*in))
-               for i := range *in {
-                       (*in)[i].DeepCopyInto(&(*out)[i])
-               }
-       }
+        *out = *in
+        out.TypeMeta = in.TypeMeta
+        in.ListMeta.DeepCopyInto(&out.ListMeta)
+        if in.Items != nil {
+                in, out := &in.Items, &out.Items
+                *out = make([]CNFRoute, len(*in))
+                for i := range *in {
+                        (*in)[i].DeepCopyInto(&(*out)[i])
+                }
+        }
 }
 
 // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new CNFRouteList.
 func (in *CNFRouteList) DeepCopy() *CNFRouteList {
-       if in == nil {
-               return nil
-       }
-       out := new(CNFRouteList)
-       in.DeepCopyInto(out)
-       return out
+        if in == nil {
+                return nil
+        }
+        out := new(CNFRouteList)
+        in.DeepCopyInto(out)
+        return out
 }
 
 // DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object.
 func (in *CNFRouteList) DeepCopyObject() runtime.Object {
-       if c := in.DeepCopy(); c != nil {
-               return c
-       }
-       return nil
+        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 *CNFRouteRule) DeepCopyInto(out *CNFRouteRule) {
-       *out = *in
-       out.TypeMeta = in.TypeMeta
-       in.ObjectMeta.DeepCopyInto(&out.ObjectMeta)
-       out.Spec = in.Spec
-       in.Status.DeepCopyInto(&out.Status)
+        *out = *in
+        out.TypeMeta = in.TypeMeta
+        in.ObjectMeta.DeepCopyInto(&out.ObjectMeta)
+        out.Spec = in.Spec
+        in.Status.DeepCopyInto(&out.Status)
 }
 
 // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new CNFRouteRule.
 func (in *CNFRouteRule) DeepCopy() *CNFRouteRule {
-       if in == nil {
-               return nil
-       }
-       out := new(CNFRouteRule)
-       in.DeepCopyInto(out)
-       return out
+        if in == nil {
+                return nil
+        }
+        out := new(CNFRouteRule)
+        in.DeepCopyInto(out)
+        return out
 }
 
 // DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object.
 func (in *CNFRouteRule) DeepCopyObject() runtime.Object {
-       if c := in.DeepCopy(); c != nil {
-               return c
-       }
-       return nil
+        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 *CNFRouteRuleList) DeepCopyInto(out *CNFRouteRuleList) {
-       *out = *in
-       out.TypeMeta = in.TypeMeta
-       in.ListMeta.DeepCopyInto(&out.ListMeta)
-       if in.Items != nil {
-               in, out := &in.Items, &out.Items
-               *out = make([]CNFRouteRule, len(*in))
-               for i := range *in {
-                       (*in)[i].DeepCopyInto(&(*out)[i])
-               }
-       }
+        *out = *in
+        out.TypeMeta = in.TypeMeta
+        in.ListMeta.DeepCopyInto(&out.ListMeta)
+        if in.Items != nil {
+                in, out := &in.Items, &out.Items
+                *out = make([]CNFRouteRule, len(*in))
+                for i := range *in {
+                        (*in)[i].DeepCopyInto(&(*out)[i])
+                }
+        }
 }
 
 // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new CNFRouteRuleList.
 func (in *CNFRouteRuleList) DeepCopy() *CNFRouteRuleList {
-       if in == nil {
-               return nil
-       }
-       out := new(CNFRouteRuleList)
-       in.DeepCopyInto(out)
-       return out
+        if in == nil {
+                return nil
+        }
+        out := new(CNFRouteRuleList)
+        in.DeepCopyInto(out)
+        return out
 }
 
 // DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object.
 func (in *CNFRouteRuleList) DeepCopyObject() runtime.Object {
-       if c := in.DeepCopy(); c != nil {
-               return c
-       }
-       return nil
+        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 *CNFRouteRuleSpec) DeepCopyInto(out *CNFRouteRuleSpec) {
-       *out = *in
+        *out = *in
 }
 
 // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new CNFRouteRuleSpec.
 func (in *CNFRouteRuleSpec) DeepCopy() *CNFRouteRuleSpec {
-       if in == nil {
-               return nil
-       }
-       out := new(CNFRouteRuleSpec)
-       in.DeepCopyInto(out)
-       return out
+        if in == nil {
+                return nil
+        }
+        out := new(CNFRouteRuleSpec)
+        in.DeepCopyInto(out)
+        return out
 }
 
 // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
 func (in *CNFRouteSpec) DeepCopyInto(out *CNFRouteSpec) {
-       *out = *in
+        *out = *in
 }
 
 // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new CNFRouteSpec.
 func (in *CNFRouteSpec) DeepCopy() *CNFRouteSpec {
-       if in == nil {
-               return nil
-       }
-       out := new(CNFRouteSpec)
-       in.DeepCopyInto(out)
-       return out
+        if in == nil {
+                return nil
+        }
+        out := new(CNFRouteSpec)
+        in.DeepCopyInto(out)
+        return out
 }
 
 // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
 func (in *CNFService) DeepCopyInto(out *CNFService) {
-       *out = *in
-       out.TypeMeta = in.TypeMeta
-       in.ObjectMeta.DeepCopyInto(&out.ObjectMeta)
-       out.Spec = in.Spec
-       in.Status.DeepCopyInto(&out.Status)
+        *out = *in
+        out.TypeMeta = in.TypeMeta
+        in.ObjectMeta.DeepCopyInto(&out.ObjectMeta)
+        out.Spec = in.Spec
+        out.Status = in.Status
 }
 
 // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new CNFService.
 func (in *CNFService) DeepCopy() *CNFService {
-       if in == nil {
-               return nil
-       }
-       out := new(CNFService)
-       in.DeepCopyInto(out)
-       return out
+        if in == nil {
+                return nil
+        }
+        out := new(CNFService)
+        in.DeepCopyInto(out)
+        return out
 }
 
 // DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object.
 func (in *CNFService) DeepCopyObject() runtime.Object {
-       if c := in.DeepCopy(); c != nil {
-               return c
-       }
-       return nil
+        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 *CNFServiceList) DeepCopyInto(out *CNFServiceList) {
-       *out = *in
-       out.TypeMeta = in.TypeMeta
-       in.ListMeta.DeepCopyInto(&out.ListMeta)
-       if in.Items != nil {
-               in, out := &in.Items, &out.Items
-               *out = make([]CNFService, len(*in))
-               for i := range *in {
-                       (*in)[i].DeepCopyInto(&(*out)[i])
-               }
-       }
+        *out = *in
+        out.TypeMeta = in.TypeMeta
+        in.ListMeta.DeepCopyInto(&out.ListMeta)
+        if in.Items != nil {
+                in, out := &in.Items, &out.Items
+                *out = make([]CNFService, len(*in))
+                for i := range *in {
+                        (*in)[i].DeepCopyInto(&(*out)[i])
+                }
+        }
 }
 
 // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new CNFServiceList.
 func (in *CNFServiceList) DeepCopy() *CNFServiceList {
-       if in == nil {
-               return nil
-       }
-       out := new(CNFServiceList)
-       in.DeepCopyInto(out)
-       return out
+        if in == nil {
+                return nil
+        }
+        out := new(CNFServiceList)
+        in.DeepCopyInto(out)
+        return out
 }
 
 // DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object.
 func (in *CNFServiceList) DeepCopyObject() runtime.Object {
-       if c := in.DeepCopy(); c != nil {
-               return c
-       }
-       return nil
+        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 *CNFServiceSpec) DeepCopyInto(out *CNFServiceSpec) {
-       *out = *in
+        *out = *in
 }
 
 // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new CNFServiceSpec.
 func (in *CNFServiceSpec) DeepCopy() *CNFServiceSpec {
-       if in == nil {
-               return nil
-       }
-       out := new(CNFServiceSpec)
-       in.DeepCopyInto(out)
-       return out
+        if in == nil {
+                return nil
+        }
+        out := new(CNFServiceSpec)
+        in.DeepCopyInto(out)
+        return out
+}
+
+// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
+func (in *CNFServiceStatus) DeepCopyInto(out *CNFServiceStatus) {
+        *out = *in
+}
+
+// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new CNFServiceStatus.
+func (in *CNFServiceStatus) DeepCopy() *CNFServiceStatus {
+        if in == nil {
+                return nil
+        }
+        out := new(CNFServiceStatus)
+        in.DeepCopyInto(out)
+        return out
 }
 
 // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
 func (in *CNFStatus) DeepCopyInto(out *CNFStatus) {
-       *out = *in
-       out.TypeMeta = in.TypeMeta
-       in.ObjectMeta.DeepCopyInto(&out.ObjectMeta)
-       out.Spec = in.Spec
-       in.Status.DeepCopyInto(&out.Status)
+        *out = *in
+        out.TypeMeta = in.TypeMeta
+        in.ObjectMeta.DeepCopyInto(&out.ObjectMeta)
+        out.Spec = in.Spec
+        in.Status.DeepCopyInto(&out.Status)
 }
 
 // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new CNFStatus.
 func (in *CNFStatus) DeepCopy() *CNFStatus {
-       if in == nil {
-               return nil
-       }
-       out := new(CNFStatus)
-       in.DeepCopyInto(out)
-       return out
+        if in == nil {
+                return nil
+        }
+        out := new(CNFStatus)
+        in.DeepCopyInto(out)
+        return out
 }
 
 // DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object.
 func (in *CNFStatus) DeepCopyObject() runtime.Object {
-       if c := in.DeepCopy(); c != nil {
-               return c
-       }
-       return nil
+        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 *CNFStatusInformation) DeepCopyInto(out *CNFStatusInformation) {
-       *out = *in
+        *out = *in
 }
 
 // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new CNFStatusInformation.
 func (in *CNFStatusInformation) DeepCopy() *CNFStatusInformation {
-       if in == nil {
-               return nil
-       }
-       out := new(CNFStatusInformation)
-       in.DeepCopyInto(out)
-       return out
+        if in == nil {
+                return nil
+        }
+        out := new(CNFStatusInformation)
+        in.DeepCopyInto(out)
+        return out
 }
 
 // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
 func (in *CNFStatusList) DeepCopyInto(out *CNFStatusList) {
-       *out = *in
-       out.TypeMeta = in.TypeMeta
-       in.ListMeta.DeepCopyInto(&out.ListMeta)
-       if in.Items != nil {
-               in, out := &in.Items, &out.Items
-               *out = make([]CNFStatus, len(*in))
-               for i := range *in {
-                       (*in)[i].DeepCopyInto(&(*out)[i])
-               }
-       }
+        *out = *in
+        out.TypeMeta = in.TypeMeta
+        in.ListMeta.DeepCopyInto(&out.ListMeta)
+        if in.Items != nil {
+                in, out := &in.Items, &out.Items
+                *out = make([]CNFStatus, len(*in))
+                for i := range *in {
+                        (*in)[i].DeepCopyInto(&(*out)[i])
+                }
+        }
 }
 
 // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new CNFStatusList.
 func (in *CNFStatusList) DeepCopy() *CNFStatusList {
-       if in == nil {
-               return nil
-       }
-       out := new(CNFStatusList)
-       in.DeepCopyInto(out)
-       return out
+        if in == nil {
+                return nil
+        }
+        out := new(CNFStatusList)
+        in.DeepCopyInto(out)
+        return out
 }
 
 // DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object.
 func (in *CNFStatusList) DeepCopyObject() runtime.Object {
-       if c := in.DeepCopy(); c != nil {
-               return c
-       }
-       return nil
+        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 *CNFStatusSpec) DeepCopyInto(out *CNFStatusSpec) {
-       *out = *in
+        *out = *in
 }
 
 // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new CNFStatusSpec.
 func (in *CNFStatusSpec) DeepCopy() *CNFStatusSpec {
-       if in == nil {
-               return nil
-       }
-       out := new(CNFStatusSpec)
-       in.DeepCopyInto(out)
-       return out
+        if in == nil {
+                return nil
+        }
+        out := new(CNFStatusSpec)
+        in.DeepCopyInto(out)
+        return out
 }
 
 // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
 func (in *CNFStatusStatus) DeepCopyInto(out *CNFStatusStatus) {
-       *out = *in
-       if in.AppliedTime != nil {
-               in, out := &in.AppliedTime, &out.AppliedTime
-               *out = (*in).DeepCopy()
-       }
-       if in.Information != nil {
-               in, out := &in.Information, &out.Information
-               *out = make([]CNFStatusInformation, len(*in))
-               copy(*out, *in)
-       }
+        *out = *in
+        if in.AppliedTime != nil {
+                in, out := &in.AppliedTime, &out.AppliedTime
+                *out = (*in).DeepCopy()
+        }
+        if in.Information != nil {
+                in, out := &in.Information, &out.Information
+                *out = make([]CNFStatusInformation, len(*in))
+                copy(*out, *in)
+        }
 }
 
 // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new CNFStatusStatus.
 func (in *CNFStatusStatus) DeepCopy() *CNFStatusStatus {
-       if in == nil {
-               return nil
-       }
-       out := new(CNFStatusStatus)
-       in.DeepCopyInto(out)
-       return out
+        if in == nil {
+                return nil
+        }
+        out := new(CNFStatusStatus)
+        in.DeepCopyInto(out)
+        return out
 }
 
 // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
 func (in *Connection) DeepCopyInto(out *Connection) {
-       *out = *in
-       if in.CryptoProposal != nil {
-               in, out := &in.CryptoProposal, &out.CryptoProposal
-               *out = make([]string, len(*in))
-               copy(*out, *in)
-       }
+        *out = *in
+        if in.CryptoProposal != nil {
+                in, out := &in.CryptoProposal, &out.CryptoProposal
+                *out = make([]string, len(*in))
+                copy(*out, *in)
+        }
 }
 
 // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Connection.
 func (in *Connection) DeepCopy() *Connection {
-       if in == nil {
-               return nil
-       }
-       out := new(Connection)
-       in.DeepCopyInto(out)
-       return out
+        if in == nil {
+                return nil
+        }
+        out := new(Connection)
+        in.DeepCopyInto(out)
+        return out
 }
 
 // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
 func (in *FirewallDNAT) DeepCopyInto(out *FirewallDNAT) {
-       *out = *in
-       out.TypeMeta = in.TypeMeta
-       in.ObjectMeta.DeepCopyInto(&out.ObjectMeta)
-       out.Spec = in.Spec
-       in.Status.DeepCopyInto(&out.Status)
+        *out = *in
+        out.TypeMeta = in.TypeMeta
+        in.ObjectMeta.DeepCopyInto(&out.ObjectMeta)
+        out.Spec = in.Spec
+        in.Status.DeepCopyInto(&out.Status)
 }
 
 // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new FirewallDNAT.
 func (in *FirewallDNAT) DeepCopy() *FirewallDNAT {
-       if in == nil {
-               return nil
-       }
-       out := new(FirewallDNAT)
-       in.DeepCopyInto(out)
-       return out
+        if in == nil {
+                return nil
+        }
+        out := new(FirewallDNAT)
+        in.DeepCopyInto(out)
+        return out
 }
 
 // DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object.
 func (in *FirewallDNAT) DeepCopyObject() runtime.Object {
-       if c := in.DeepCopy(); c != nil {
-               return c
-       }
-       return nil
+        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 *FirewallDNATList) DeepCopyInto(out *FirewallDNATList) {
-       *out = *in
-       out.TypeMeta = in.TypeMeta
-       in.ListMeta.DeepCopyInto(&out.ListMeta)
-       if in.Items != nil {
-               in, out := &in.Items, &out.Items
-               *out = make([]FirewallDNAT, len(*in))
-               for i := range *in {
-                       (*in)[i].DeepCopyInto(&(*out)[i])
-               }
-       }
+        *out = *in
+        out.TypeMeta = in.TypeMeta
+        in.ListMeta.DeepCopyInto(&out.ListMeta)
+        if in.Items != nil {
+                in, out := &in.Items, &out.Items
+                *out = make([]FirewallDNAT, len(*in))
+                for i := range *in {
+                        (*in)[i].DeepCopyInto(&(*out)[i])
+                }
+        }
 }
 
 // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new FirewallDNATList.
 func (in *FirewallDNATList) DeepCopy() *FirewallDNATList {
-       if in == nil {
-               return nil
-       }
-       out := new(FirewallDNATList)
-       in.DeepCopyInto(out)
-       return out
+        if in == nil {
+                return nil
+        }
+        out := new(FirewallDNATList)
+        in.DeepCopyInto(out)
+        return out
 }
 
 // DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object.
 func (in *FirewallDNATList) DeepCopyObject() runtime.Object {
-       if c := in.DeepCopy(); c != nil {
-               return c
-       }
-       return nil
+        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 *FirewallDNATSpec) DeepCopyInto(out *FirewallDNATSpec) {
-       *out = *in
+        *out = *in
 }
 
 // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new FirewallDNATSpec.
 func (in *FirewallDNATSpec) DeepCopy() *FirewallDNATSpec {
-       if in == nil {
-               return nil
-       }
-       out := new(FirewallDNATSpec)
-       in.DeepCopyInto(out)
-       return out
+        if in == nil {
+                return nil
+        }
+        out := new(FirewallDNATSpec)
+        in.DeepCopyInto(out)
+        return out
 }
 
 // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
 func (in *FirewallForwarding) DeepCopyInto(out *FirewallForwarding) {
-       *out = *in
-       out.TypeMeta = in.TypeMeta
-       in.ObjectMeta.DeepCopyInto(&out.ObjectMeta)
-       out.Spec = in.Spec
-       in.Status.DeepCopyInto(&out.Status)
+        *out = *in
+        out.TypeMeta = in.TypeMeta
+        in.ObjectMeta.DeepCopyInto(&out.ObjectMeta)
+        out.Spec = in.Spec
+        in.Status.DeepCopyInto(&out.Status)
 }
 
 // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new FirewallForwarding.
 func (in *FirewallForwarding) DeepCopy() *FirewallForwarding {
-       if in == nil {
-               return nil
-       }
-       out := new(FirewallForwarding)
-       in.DeepCopyInto(out)
-       return out
+        if in == nil {
+                return nil
+        }
+        out := new(FirewallForwarding)
+        in.DeepCopyInto(out)
+        return out
 }
 
 // DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object.
 func (in *FirewallForwarding) DeepCopyObject() runtime.Object {
-       if c := in.DeepCopy(); c != nil {
-               return c
-       }
-       return nil
+        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 *FirewallForwardingList) DeepCopyInto(out *FirewallForwardingList) {
-       *out = *in
-       out.TypeMeta = in.TypeMeta
-       in.ListMeta.DeepCopyInto(&out.ListMeta)
-       if in.Items != nil {
-               in, out := &in.Items, &out.Items
-               *out = make([]FirewallForwarding, len(*in))
-               for i := range *in {
-                       (*in)[i].DeepCopyInto(&(*out)[i])
-               }
-       }
+        *out = *in
+        out.TypeMeta = in.TypeMeta
+        in.ListMeta.DeepCopyInto(&out.ListMeta)
+        if in.Items != nil {
+                in, out := &in.Items, &out.Items
+                *out = make([]FirewallForwarding, len(*in))
+                for i := range *in {
+                        (*in)[i].DeepCopyInto(&(*out)[i])
+                }
+        }
 }
 
 // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new FirewallForwardingList.
 func (in *FirewallForwardingList) DeepCopy() *FirewallForwardingList {
-       if in == nil {
-               return nil
-       }
-       out := new(FirewallForwardingList)
-       in.DeepCopyInto(out)
-       return out
+        if in == nil {
+                return nil
+        }
+        out := new(FirewallForwardingList)
+        in.DeepCopyInto(out)
+        return out
 }
 
 // DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object.
 func (in *FirewallForwardingList) DeepCopyObject() runtime.Object {
-       if c := in.DeepCopy(); c != nil {
-               return c
-       }
-       return nil
+        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 *FirewallForwardingSpec) DeepCopyInto(out *FirewallForwardingSpec) {
-       *out = *in
+        *out = *in
 }
 
 // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new FirewallForwardingSpec.
 func (in *FirewallForwardingSpec) DeepCopy() *FirewallForwardingSpec {
-       if in == nil {
-               return nil
-       }
-       out := new(FirewallForwardingSpec)
-       in.DeepCopyInto(out)
-       return out
+        if in == nil {
+                return nil
+        }
+        out := new(FirewallForwardingSpec)
+        in.DeepCopyInto(out)
+        return out
 }
 
 // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
 func (in *FirewallRule) DeepCopyInto(out *FirewallRule) {
-       *out = *in
-       out.TypeMeta = in.TypeMeta
-       in.ObjectMeta.DeepCopyInto(&out.ObjectMeta)
-       in.Spec.DeepCopyInto(&out.Spec)
-       in.Status.DeepCopyInto(&out.Status)
+        *out = *in
+        out.TypeMeta = in.TypeMeta
+        in.ObjectMeta.DeepCopyInto(&out.ObjectMeta)
+        in.Spec.DeepCopyInto(&out.Spec)
+        in.Status.DeepCopyInto(&out.Status)
 }
 
 // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new FirewallRule.
 func (in *FirewallRule) DeepCopy() *FirewallRule {
-       if in == nil {
-               return nil
-       }
-       out := new(FirewallRule)
-       in.DeepCopyInto(out)
-       return out
+        if in == nil {
+                return nil
+        }
+        out := new(FirewallRule)
+        in.DeepCopyInto(out)
+        return out
 }
 
 // DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object.
 func (in *FirewallRule) DeepCopyObject() runtime.Object {
-       if c := in.DeepCopy(); c != nil {
-               return c
-       }
-       return nil
+        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 *FirewallRuleList) DeepCopyInto(out *FirewallRuleList) {
-       *out = *in
-       out.TypeMeta = in.TypeMeta
-       in.ListMeta.DeepCopyInto(&out.ListMeta)
-       if in.Items != nil {
-               in, out := &in.Items, &out.Items
-               *out = make([]FirewallRule, len(*in))
-               for i := range *in {
-                       (*in)[i].DeepCopyInto(&(*out)[i])
-               }
-       }
+        *out = *in
+        out.TypeMeta = in.TypeMeta
+        in.ListMeta.DeepCopyInto(&out.ListMeta)
+        if in.Items != nil {
+                in, out := &in.Items, &out.Items
+                *out = make([]FirewallRule, len(*in))
+                for i := range *in {
+                        (*in)[i].DeepCopyInto(&(*out)[i])
+                }
+        }
 }
 
 // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new FirewallRuleList.
 func (in *FirewallRuleList) DeepCopy() *FirewallRuleList {
-       if in == nil {
-               return nil
-       }
-       out := new(FirewallRuleList)
-       in.DeepCopyInto(out)
-       return out
+        if in == nil {
+                return nil
+        }
+        out := new(FirewallRuleList)
+        in.DeepCopyInto(out)
+        return out
 }
 
 // DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object.
 func (in *FirewallRuleList) DeepCopyObject() runtime.Object {
-       if c := in.DeepCopy(); c != nil {
-               return c
-       }
-       return nil
+        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 *FirewallRuleSpec) DeepCopyInto(out *FirewallRuleSpec) {
-       *out = *in
-       if in.IcmpType != nil {
-               in, out := &in.IcmpType, &out.IcmpType
-               *out = make([]string, len(*in))
-               copy(*out, *in)
-       }
+        *out = *in
+        if in.IcmpType != nil {
+                in, out := &in.IcmpType, &out.IcmpType
+                *out = make([]string, len(*in))
+                copy(*out, *in)
+        }
 }
 
 // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new FirewallRuleSpec.
 func (in *FirewallRuleSpec) DeepCopy() *FirewallRuleSpec {
-       if in == nil {
-               return nil
-       }
-       out := new(FirewallRuleSpec)
-       in.DeepCopyInto(out)
-       return out
+        if in == nil {
+                return nil
+        }
+        out := new(FirewallRuleSpec)
+        in.DeepCopyInto(out)
+        return out
 }
 
 // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
 func (in *FirewallSNAT) DeepCopyInto(out *FirewallSNAT) {
-       *out = *in
-       out.TypeMeta = in.TypeMeta
-       in.ObjectMeta.DeepCopyInto(&out.ObjectMeta)
-       out.Spec = in.Spec
-       in.Status.DeepCopyInto(&out.Status)
+        *out = *in
+        out.TypeMeta = in.TypeMeta
+        in.ObjectMeta.DeepCopyInto(&out.ObjectMeta)
+        out.Spec = in.Spec
+        in.Status.DeepCopyInto(&out.Status)
 }
 
 // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new FirewallSNAT.
 func (in *FirewallSNAT) DeepCopy() *FirewallSNAT {
-       if in == nil {
-               return nil
-       }
-       out := new(FirewallSNAT)
-       in.DeepCopyInto(out)
-       return out
+        if in == nil {
+                return nil
+        }
+        out := new(FirewallSNAT)
+        in.DeepCopyInto(out)
+        return out
 }
 
 // DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object.
 func (in *FirewallSNAT) DeepCopyObject() runtime.Object {
-       if c := in.DeepCopy(); c != nil {
-               return c
-       }
-       return nil
+        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 *FirewallSNATList) DeepCopyInto(out *FirewallSNATList) {
-       *out = *in
-       out.TypeMeta = in.TypeMeta
-       in.ListMeta.DeepCopyInto(&out.ListMeta)
-       if in.Items != nil {
-               in, out := &in.Items, &out.Items
-               *out = make([]FirewallSNAT, len(*in))
-               for i := range *in {
-                       (*in)[i].DeepCopyInto(&(*out)[i])
-               }
-       }
+        *out = *in
+        out.TypeMeta = in.TypeMeta
+        in.ListMeta.DeepCopyInto(&out.ListMeta)
+        if in.Items != nil {
+                in, out := &in.Items, &out.Items
+                *out = make([]FirewallSNAT, len(*in))
+                for i := range *in {
+                        (*in)[i].DeepCopyInto(&(*out)[i])
+                }
+        }
 }
 
 // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new FirewallSNATList.
 func (in *FirewallSNATList) DeepCopy() *FirewallSNATList {
-       if in == nil {
-               return nil
-       }
-       out := new(FirewallSNATList)
-       in.DeepCopyInto(out)
-       return out
+        if in == nil {
+                return nil
+        }
+        out := new(FirewallSNATList)
+        in.DeepCopyInto(out)
+        return out
 }
 
 // DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object.
 func (in *FirewallSNATList) DeepCopyObject() runtime.Object {
-       if c := in.DeepCopy(); c != nil {
-               return c
-       }
-       return nil
+        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 *FirewallSNATSpec) DeepCopyInto(out *FirewallSNATSpec) {
-       *out = *in
+        *out = *in
 }
 
 // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new FirewallSNATSpec.
 func (in *FirewallSNATSpec) DeepCopy() *FirewallSNATSpec {
-       if in == nil {
-               return nil
-       }
-       out := new(FirewallSNATSpec)
-       in.DeepCopyInto(out)
-       return out
+        if in == nil {
+                return nil
+        }
+        out := new(FirewallSNATSpec)
+        in.DeepCopyInto(out)
+        return out
 }
 
 // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
 func (in *FirewallZone) DeepCopyInto(out *FirewallZone) {
-       *out = *in
-       out.TypeMeta = in.TypeMeta
-       in.ObjectMeta.DeepCopyInto(&out.ObjectMeta)
-       in.Spec.DeepCopyInto(&out.Spec)
-       in.Status.DeepCopyInto(&out.Status)
+        *out = *in
+        out.TypeMeta = in.TypeMeta
+        in.ObjectMeta.DeepCopyInto(&out.ObjectMeta)
+        in.Spec.DeepCopyInto(&out.Spec)
+        in.Status.DeepCopyInto(&out.Status)
 }
 
 // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new FirewallZone.
 func (in *FirewallZone) DeepCopy() *FirewallZone {
-       if in == nil {
-               return nil
-       }
-       out := new(FirewallZone)
-       in.DeepCopyInto(out)
-       return out
+        if in == nil {
+                return nil
+        }
+        out := new(FirewallZone)
+        in.DeepCopyInto(out)
+        return out
 }
 
 // DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object.
 func (in *FirewallZone) DeepCopyObject() runtime.Object {
-       if c := in.DeepCopy(); c != nil {
-               return c
-       }
-       return nil
+        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 *FirewallZoneList) DeepCopyInto(out *FirewallZoneList) {
-       *out = *in
-       out.TypeMeta = in.TypeMeta
-       in.ListMeta.DeepCopyInto(&out.ListMeta)
-       if in.Items != nil {
-               in, out := &in.Items, &out.Items
-               *out = make([]FirewallZone, len(*in))
-               for i := range *in {
-                       (*in)[i].DeepCopyInto(&(*out)[i])
-               }
-       }
+        *out = *in
+        out.TypeMeta = in.TypeMeta
+        in.ListMeta.DeepCopyInto(&out.ListMeta)
+        if in.Items != nil {
+                in, out := &in.Items, &out.Items
+                *out = make([]FirewallZone, len(*in))
+                for i := range *in {
+                        (*in)[i].DeepCopyInto(&(*out)[i])
+                }
+        }
 }
 
 // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new FirewallZoneList.
 func (in *FirewallZoneList) DeepCopy() *FirewallZoneList {
-       if in == nil {
-               return nil
-       }
-       out := new(FirewallZoneList)
-       in.DeepCopyInto(out)
-       return out
+        if in == nil {
+                return nil
+        }
+        out := new(FirewallZoneList)
+        in.DeepCopyInto(out)
+        return out
 }
 
 // DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object.
 func (in *FirewallZoneList) DeepCopyObject() runtime.Object {
-       if c := in.DeepCopy(); c != nil {
-               return c
-       }
-       return nil
+        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 *FirewallZoneSpec) DeepCopyInto(out *FirewallZoneSpec) {
-       *out = *in
-       if in.Network != nil {
-               in, out := &in.Network, &out.Network
-               *out = make([]string, len(*in))
-               copy(*out, *in)
-       }
-       if in.MasqSrc != nil {
-               in, out := &in.MasqSrc, &out.MasqSrc
-               *out = make([]string, len(*in))
-               copy(*out, *in)
-       }
-       if in.MasqDest != nil {
-               in, out := &in.MasqDest, &out.MasqDest
-               *out = make([]string, len(*in))
-               copy(*out, *in)
-       }
-       if in.Subnet != nil {
-               in, out := &in.Subnet, &out.Subnet
-               *out = make([]string, len(*in))
-               copy(*out, *in)
-       }
+        *out = *in
+        if in.Network != nil {
+                in, out := &in.Network, &out.Network
+                *out = make([]string, len(*in))
+                copy(*out, *in)
+        }
+        if in.MasqSrc != nil {
+                in, out := &in.MasqSrc, &out.MasqSrc
+                *out = make([]string, len(*in))
+                copy(*out, *in)
+        }
+        if in.MasqDest != nil {
+                in, out := &in.MasqDest, &out.MasqDest
+                *out = make([]string, len(*in))
+                copy(*out, *in)
+        }
+        if in.Subnet != nil {
+                in, out := &in.Subnet, &out.Subnet
+                *out = make([]string, len(*in))
+                copy(*out, *in)
+        }
 }
 
 // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new FirewallZoneSpec.
 func (in *FirewallZoneSpec) DeepCopy() *FirewallZoneSpec {
-       if in == nil {
-               return nil
-       }
-       out := new(FirewallZoneSpec)
-       in.DeepCopyInto(out)
-       return out
+        if in == nil {
+                return nil
+        }
+        out := new(FirewallZoneSpec)
+        in.DeepCopyInto(out)
+        return out
 }
 
 // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
 func (in *IpsecHost) DeepCopyInto(out *IpsecHost) {
-       *out = *in
-       out.TypeMeta = in.TypeMeta
-       in.ObjectMeta.DeepCopyInto(&out.ObjectMeta)
-       in.Spec.DeepCopyInto(&out.Spec)
-       in.Status.DeepCopyInto(&out.Status)
+        *out = *in
+        out.TypeMeta = in.TypeMeta
+        in.ObjectMeta.DeepCopyInto(&out.ObjectMeta)
+        in.Spec.DeepCopyInto(&out.Spec)
+        in.Status.DeepCopyInto(&out.Status)
 }
 
 // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new IpsecHost.
 func (in *IpsecHost) DeepCopy() *IpsecHost {
-       if in == nil {
-               return nil
-       }
-       out := new(IpsecHost)
-       in.DeepCopyInto(out)
-       return out
+        if in == nil {
+                return nil
+        }
+        out := new(IpsecHost)
+        in.DeepCopyInto(out)
+        return out
 }
 
 // DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object.
 func (in *IpsecHost) DeepCopyObject() runtime.Object {
-       if c := in.DeepCopy(); c != nil {
-               return c
-       }
-       return nil
+        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 *IpsecHostList) DeepCopyInto(out *IpsecHostList) {
-       *out = *in
-       out.TypeMeta = in.TypeMeta
-       in.ListMeta.DeepCopyInto(&out.ListMeta)
-       if in.Items != nil {
-               in, out := &in.Items, &out.Items
-               *out = make([]IpsecHost, len(*in))
-               for i := range *in {
-                       (*in)[i].DeepCopyInto(&(*out)[i])
-               }
-       }
+        *out = *in
+        out.TypeMeta = in.TypeMeta
+        in.ListMeta.DeepCopyInto(&out.ListMeta)
+        if in.Items != nil {
+                in, out := &in.Items, &out.Items
+                *out = make([]IpsecHost, len(*in))
+                for i := range *in {
+                        (*in)[i].DeepCopyInto(&(*out)[i])
+                }
+        }
 }
 
 // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new IpsecHostList.
 func (in *IpsecHostList) DeepCopy() *IpsecHostList {
-       if in == nil {
-               return nil
-       }
-       out := new(IpsecHostList)
-       in.DeepCopyInto(out)
-       return out
+        if in == nil {
+                return nil
+        }
+        out := new(IpsecHostList)
+        in.DeepCopyInto(out)
+        return out
 }
 
 // DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object.
 func (in *IpsecHostList) DeepCopyObject() runtime.Object {
-       if c := in.DeepCopy(); c != nil {
-               return c
-       }
-       return nil
+        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 *IpsecHostSpec) DeepCopyInto(out *IpsecHostSpec) {
-       *out = *in
-       if in.CryptoProposal != nil {
-               in, out := &in.CryptoProposal, &out.CryptoProposal
-               *out = make([]string, len(*in))
-               copy(*out, *in)
-       }
-       if in.Connections != nil {
-               in, out := &in.Connections, &out.Connections
-               *out = make([]Connection, len(*in))
-               for i := range *in {
-                       (*in)[i].DeepCopyInto(&(*out)[i])
-               }
-       }
+        *out = *in
+        if in.CryptoProposal != nil {
+                in, out := &in.CryptoProposal, &out.CryptoProposal
+                *out = make([]string, len(*in))
+                copy(*out, *in)
+        }
+        if in.Connections != nil {
+                in, out := &in.Connections, &out.Connections
+                *out = make([]Connection, len(*in))
+                for i := range *in {
+                        (*in)[i].DeepCopyInto(&(*out)[i])
+                }
+        }
 }
 
 // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new IpsecHostSpec.
 func (in *IpsecHostSpec) DeepCopy() *IpsecHostSpec {
-       if in == nil {
-               return nil
-       }
-       out := new(IpsecHostSpec)
-       in.DeepCopyInto(out)
-       return out
+        if in == nil {
+                return nil
+        }
+        out := new(IpsecHostSpec)
+        in.DeepCopyInto(out)
+        return out
 }
 
 // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
 func (in *IpsecProposal) DeepCopyInto(out *IpsecProposal) {
-       *out = *in
-       out.TypeMeta = in.TypeMeta
-       in.ObjectMeta.DeepCopyInto(&out.ObjectMeta)
-       out.Spec = in.Spec
-       in.Status.DeepCopyInto(&out.Status)
+        *out = *in
+        out.TypeMeta = in.TypeMeta
+        in.ObjectMeta.DeepCopyInto(&out.ObjectMeta)
+        out.Spec = in.Spec
+        in.Status.DeepCopyInto(&out.Status)
 }
 
 // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new IpsecProposal.
 func (in *IpsecProposal) DeepCopy() *IpsecProposal {
-       if in == nil {
-               return nil
-       }
-       out := new(IpsecProposal)
-       in.DeepCopyInto(out)
-       return out
+        if in == nil {
+                return nil
+        }
+        out := new(IpsecProposal)
+        in.DeepCopyInto(out)
+        return out
 }
 
 // DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object.
 func (in *IpsecProposal) DeepCopyObject() runtime.Object {
-       if c := in.DeepCopy(); c != nil {
-               return c
-       }
-       return nil
+        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 *IpsecProposalList) DeepCopyInto(out *IpsecProposalList) {
-       *out = *in
-       out.TypeMeta = in.TypeMeta
-       in.ListMeta.DeepCopyInto(&out.ListMeta)
-       if in.Items != nil {
-               in, out := &in.Items, &out.Items
-               *out = make([]IpsecProposal, len(*in))
-               for i := range *in {
-                       (*in)[i].DeepCopyInto(&(*out)[i])
-               }
-       }
+        *out = *in
+        out.TypeMeta = in.TypeMeta
+        in.ListMeta.DeepCopyInto(&out.ListMeta)
+        if in.Items != nil {
+                in, out := &in.Items, &out.Items
+                *out = make([]IpsecProposal, len(*in))
+                for i := range *in {
+                        (*in)[i].DeepCopyInto(&(*out)[i])
+                }
+        }
 }
 
 // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new IpsecProposalList.
 func (in *IpsecProposalList) DeepCopy() *IpsecProposalList {
-       if in == nil {
-               return nil
-       }
-       out := new(IpsecProposalList)
-       in.DeepCopyInto(out)
-       return out
+        if in == nil {
+                return nil
+        }
+        out := new(IpsecProposalList)
+        in.DeepCopyInto(out)
+        return out
 }
 
 // DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object.
 func (in *IpsecProposalList) DeepCopyObject() runtime.Object {
-       if c := in.DeepCopy(); c != nil {
-               return c
-       }
-       return nil
+        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 *IpsecProposalSpec) DeepCopyInto(out *IpsecProposalSpec) {
-       *out = *in
+        *out = *in
 }
 
 // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new IpsecProposalSpec.
 func (in *IpsecProposalSpec) DeepCopy() *IpsecProposalSpec {
-       if in == nil {
-               return nil
-       }
-       out := new(IpsecProposalSpec)
-       in.DeepCopyInto(out)
-       return out
+        if in == nil {
+                return nil
+        }
+        out := new(IpsecProposalSpec)
+        in.DeepCopyInto(out)
+        return out
 }
 
 // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
 func (in *IpsecSite) DeepCopyInto(out *IpsecSite) {
-       *out = *in
-       out.TypeMeta = in.TypeMeta
-       in.ObjectMeta.DeepCopyInto(&out.ObjectMeta)
-       in.Spec.DeepCopyInto(&out.Spec)
-       in.Status.DeepCopyInto(&out.Status)
+        *out = *in
+        out.TypeMeta = in.TypeMeta
+        in.ObjectMeta.DeepCopyInto(&out.ObjectMeta)
+        in.Spec.DeepCopyInto(&out.Spec)
+        in.Status.DeepCopyInto(&out.Status)
 }
 
 // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new IpsecSite.
 func (in *IpsecSite) DeepCopy() *IpsecSite {
-       if in == nil {
-               return nil
-       }
-       out := new(IpsecSite)
-       in.DeepCopyInto(out)
-       return out
+        if in == nil {
+                return nil
+        }
+        out := new(IpsecSite)
+        in.DeepCopyInto(out)
+        return out
 }
 
 // DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object.
 func (in *IpsecSite) DeepCopyObject() runtime.Object {
-       if c := in.DeepCopy(); c != nil {
-               return c
-       }
-       return nil
+        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 *IpsecSiteList) DeepCopyInto(out *IpsecSiteList) {
-       *out = *in
-       out.TypeMeta = in.TypeMeta
-       in.ListMeta.DeepCopyInto(&out.ListMeta)
-       if in.Items != nil {
-               in, out := &in.Items, &out.Items
-               *out = make([]IpsecSite, len(*in))
-               for i := range *in {
-                       (*in)[i].DeepCopyInto(&(*out)[i])
-               }
-       }
+        *out = *in
+        out.TypeMeta = in.TypeMeta
+        in.ListMeta.DeepCopyInto(&out.ListMeta)
+        if in.Items != nil {
+                in, out := &in.Items, &out.Items
+                *out = make([]IpsecSite, len(*in))
+                for i := range *in {
+                        (*in)[i].DeepCopyInto(&(*out)[i])
+                }
+        }
 }
 
 // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new IpsecSiteList.
 func (in *IpsecSiteList) DeepCopy() *IpsecSiteList {
-       if in == nil {
-               return nil
-       }
-       out := new(IpsecSiteList)
-       in.DeepCopyInto(out)
-       return out
+        if in == nil {
+                return nil
+        }
+        out := new(IpsecSiteList)
+        in.DeepCopyInto(out)
+        return out
 }
 
 // DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object.
 func (in *IpsecSiteList) DeepCopyObject() runtime.Object {
-       if c := in.DeepCopy(); c != nil {
-               return c
-       }
-       return nil
+        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 *IpsecSiteSpec) DeepCopyInto(out *IpsecSiteSpec) {
-       *out = *in
-       if in.CryptoProposal != nil {
-               in, out := &in.CryptoProposal, &out.CryptoProposal
-               *out = make([]string, len(*in))
-               copy(*out, *in)
-       }
-       if in.Connections != nil {
-               in, out := &in.Connections, &out.Connections
-               *out = make([]SiteConnection, len(*in))
-               for i := range *in {
-                       (*in)[i].DeepCopyInto(&(*out)[i])
-               }
-       }
+        *out = *in
+        if in.CryptoProposal != nil {
+                in, out := &in.CryptoProposal, &out.CryptoProposal
+                *out = make([]string, len(*in))
+                copy(*out, *in)
+        }
+        if in.Connections != nil {
+                in, out := &in.Connections, &out.Connections
+                *out = make([]SiteConnection, len(*in))
+                for i := range *in {
+                        (*in)[i].DeepCopyInto(&(*out)[i])
+                }
+        }
 }
 
 // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new IpsecSiteSpec.
 func (in *IpsecSiteSpec) DeepCopy() *IpsecSiteSpec {
-       if in == nil {
-               return nil
-       }
-       out := new(IpsecSiteSpec)
-       in.DeepCopyInto(out)
-       return out
+        if in == nil {
+                return nil
+        }
+        out := new(IpsecSiteSpec)
+        in.DeepCopyInto(out)
+        return out
 }
 
 // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
 func (in *Mwan3Policy) DeepCopyInto(out *Mwan3Policy) {
-       *out = *in
-       out.TypeMeta = in.TypeMeta
-       in.ObjectMeta.DeepCopyInto(&out.ObjectMeta)
-       in.Spec.DeepCopyInto(&out.Spec)
-       in.Status.DeepCopyInto(&out.Status)
+        *out = *in
+        out.TypeMeta = in.TypeMeta
+        in.ObjectMeta.DeepCopyInto(&out.ObjectMeta)
+        in.Spec.DeepCopyInto(&out.Spec)
+        in.Status.DeepCopyInto(&out.Status)
 }
 
 // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Mwan3Policy.
 func (in *Mwan3Policy) DeepCopy() *Mwan3Policy {
-       if in == nil {
-               return nil
-       }
-       out := new(Mwan3Policy)
-       in.DeepCopyInto(out)
-       return out
+        if in == nil {
+                return nil
+        }
+        out := new(Mwan3Policy)
+        in.DeepCopyInto(out)
+        return out
 }
 
 // DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object.
 func (in *Mwan3Policy) DeepCopyObject() runtime.Object {
-       if c := in.DeepCopy(); c != nil {
-               return c
-       }
-       return nil
+        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 *Mwan3PolicyList) DeepCopyInto(out *Mwan3PolicyList) {
-       *out = *in
-       out.TypeMeta = in.TypeMeta
-       in.ListMeta.DeepCopyInto(&out.ListMeta)
-       if in.Items != nil {
-               in, out := &in.Items, &out.Items
-               *out = make([]Mwan3Policy, len(*in))
-               for i := range *in {
-                       (*in)[i].DeepCopyInto(&(*out)[i])
-               }
-       }
+        *out = *in
+        out.TypeMeta = in.TypeMeta
+        in.ListMeta.DeepCopyInto(&out.ListMeta)
+        if in.Items != nil {
+                in, out := &in.Items, &out.Items
+                *out = make([]Mwan3Policy, len(*in))
+                for i := range *in {
+                        (*in)[i].DeepCopyInto(&(*out)[i])
+                }
+        }
 }
 
 // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Mwan3PolicyList.
 func (in *Mwan3PolicyList) DeepCopy() *Mwan3PolicyList {
-       if in == nil {
-               return nil
-       }
-       out := new(Mwan3PolicyList)
-       in.DeepCopyInto(out)
-       return out
+        if in == nil {
+                return nil
+        }
+        out := new(Mwan3PolicyList)
+        in.DeepCopyInto(out)
+        return out
 }
 
 // DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object.
 func (in *Mwan3PolicyList) DeepCopyObject() runtime.Object {
-       if c := in.DeepCopy(); c != nil {
-               return c
-       }
-       return nil
+        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 *Mwan3PolicyMember) DeepCopyInto(out *Mwan3PolicyMember) {
-       *out = *in
+        *out = *in
 }
 
 // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Mwan3PolicyMember.
 func (in *Mwan3PolicyMember) DeepCopy() *Mwan3PolicyMember {
-       if in == nil {
-               return nil
-       }
-       out := new(Mwan3PolicyMember)
-       in.DeepCopyInto(out)
-       return out
+        if in == nil {
+                return nil
+        }
+        out := new(Mwan3PolicyMember)
+        in.DeepCopyInto(out)
+        return out
 }
 
 // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
 func (in *Mwan3PolicySpec) DeepCopyInto(out *Mwan3PolicySpec) {
-       *out = *in
-       if in.Members != nil {
-               in, out := &in.Members, &out.Members
-               *out = make([]Mwan3PolicyMember, len(*in))
-               copy(*out, *in)
-       }
+        *out = *in
+        if in.Members != nil {
+                in, out := &in.Members, &out.Members
+                *out = make([]Mwan3PolicyMember, len(*in))
+                copy(*out, *in)
+        }
 }
 
 // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Mwan3PolicySpec.
 func (in *Mwan3PolicySpec) DeepCopy() *Mwan3PolicySpec {
-       if in == nil {
-               return nil
-       }
-       out := new(Mwan3PolicySpec)
-       in.DeepCopyInto(out)
-       return out
+        if in == nil {
+                return nil
+        }
+        out := new(Mwan3PolicySpec)
+        in.DeepCopyInto(out)
+        return out
 }
 
 // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
 func (in *Mwan3Rule) DeepCopyInto(out *Mwan3Rule) {
-       *out = *in
-       out.TypeMeta = in.TypeMeta
-       in.ObjectMeta.DeepCopyInto(&out.ObjectMeta)
-       out.Spec = in.Spec
-       in.Status.DeepCopyInto(&out.Status)
+        *out = *in
+        out.TypeMeta = in.TypeMeta
+        in.ObjectMeta.DeepCopyInto(&out.ObjectMeta)
+        out.Spec = in.Spec
+        in.Status.DeepCopyInto(&out.Status)
 }
 
 // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Mwan3Rule.
 func (in *Mwan3Rule) DeepCopy() *Mwan3Rule {
-       if in == nil {
-               return nil
-       }
-       out := new(Mwan3Rule)
-       in.DeepCopyInto(out)
-       return out
+        if in == nil {
+                return nil
+        }
+        out := new(Mwan3Rule)
+        in.DeepCopyInto(out)
+        return out
 }
 
 // DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object.
 func (in *Mwan3Rule) DeepCopyObject() runtime.Object {
-       if c := in.DeepCopy(); c != nil {
-               return c
-       }
-       return nil
+        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 *Mwan3RuleList) DeepCopyInto(out *Mwan3RuleList) {
-       *out = *in
-       out.TypeMeta = in.TypeMeta
-       in.ListMeta.DeepCopyInto(&out.ListMeta)
-       if in.Items != nil {
-               in, out := &in.Items, &out.Items
-               *out = make([]Mwan3Rule, len(*in))
-               for i := range *in {
-                       (*in)[i].DeepCopyInto(&(*out)[i])
-               }
-       }
+        *out = *in
+        out.TypeMeta = in.TypeMeta
+        in.ListMeta.DeepCopyInto(&out.ListMeta)
+        if in.Items != nil {
+                in, out := &in.Items, &out.Items
+                *out = make([]Mwan3Rule, len(*in))
+                for i := range *in {
+                        (*in)[i].DeepCopyInto(&(*out)[i])
+                }
+        }
 }
 
 // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Mwan3RuleList.
 func (in *Mwan3RuleList) DeepCopy() *Mwan3RuleList {
-       if in == nil {
-               return nil
-       }
-       out := new(Mwan3RuleList)
-       in.DeepCopyInto(out)
-       return out
+        if in == nil {
+                return nil
+        }
+        out := new(Mwan3RuleList)
+        in.DeepCopyInto(out)
+        return out
 }
 
 // DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object.
 func (in *Mwan3RuleList) DeepCopyObject() runtime.Object {
-       if c := in.DeepCopy(); c != nil {
-               return c
-       }
-       return nil
+        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 *Mwan3RuleSpec) DeepCopyInto(out *Mwan3RuleSpec) {
-       *out = *in
+        *out = *in
 }
 
 // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Mwan3RuleSpec.
 func (in *Mwan3RuleSpec) DeepCopy() *Mwan3RuleSpec {
-       if in == nil {
-               return nil
-       }
-       out := new(Mwan3RuleSpec)
-       in.DeepCopyInto(out)
-       return out
+        if in == nil {
+                return nil
+        }
+        out := new(Mwan3RuleSpec)
+        in.DeepCopyInto(out)
+        return out
 }
 
 // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
-func (in *SdewanApplication) DeepCopyInto(out *SdewanApplication) {
+func (in *NetworkFirewallRule) DeepCopyInto(out *NetworkFirewallRule) {
        *out = *in
        out.TypeMeta = in.TypeMeta
        in.ObjectMeta.DeepCopyInto(&out.ObjectMeta)
        in.Spec.DeepCopyInto(&out.Spec)
        in.Status.DeepCopyInto(&out.Status)
-       out.AppInfo = in.AppInfo
 }
 
-// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new SdewanApplication.
-func (in *SdewanApplication) DeepCopy() *SdewanApplication {
+// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new NetworkFirewallRule.
+func (in *NetworkFirewallRule) DeepCopy() *NetworkFirewallRule {
        if in == nil {
                return nil
        }
-       out := new(SdewanApplication)
+       out := new(NetworkFirewallRule)
        in.DeepCopyInto(out)
        return out
 }
 
 // DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object.
-func (in *SdewanApplication) DeepCopyObject() runtime.Object {
+func (in *NetworkFirewallRule) DeepCopyObject() runtime.Object {
        if c := in.DeepCopy(); c != nil {
                return c
        }
@@ -1418,31 +1526,31 @@ func (in *SdewanApplication) DeepCopyObject() runtime.Object {
 }
 
 // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
-func (in *SdewanApplicationList) DeepCopyInto(out *SdewanApplicationList) {
+func (in *NetworkFirewallRuleList) DeepCopyInto(out *NetworkFirewallRuleList) {
        *out = *in
        out.TypeMeta = in.TypeMeta
        in.ListMeta.DeepCopyInto(&out.ListMeta)
        if in.Items != nil {
                in, out := &in.Items, &out.Items
-               *out = make([]SdewanApplication, len(*in))
+               *out = make([]NetworkFirewallRule, len(*in))
                for i := range *in {
                        (*in)[i].DeepCopyInto(&(*out)[i])
                }
        }
 }
 
-// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new SdewanApplicationList.
-func (in *SdewanApplicationList) DeepCopy() *SdewanApplicationList {
+// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new NetworkFirewallRuleList.
+func (in *NetworkFirewallRuleList) DeepCopy() *NetworkFirewallRuleList {
        if in == nil {
                return nil
        }
-       out := new(SdewanApplicationList)
+       out := new(NetworkFirewallRuleList)
        in.DeepCopyInto(out)
        return out
 }
 
 // DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object.
-func (in *SdewanApplicationList) DeepCopyObject() runtime.Object {
+func (in *NetworkFirewallRuleList) DeepCopyObject() runtime.Object {
        if c := in.DeepCopy(); c != nil {
                return c
        }
@@ -1450,60 +1558,140 @@ func (in *SdewanApplicationList) DeepCopyObject() runtime.Object {
 }
 
 // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
-func (in *SdewanApplicationSpec) DeepCopyInto(out *SdewanApplicationSpec) {
+func (in *NetworkFirewallRuleSpec) DeepCopyInto(out *NetworkFirewallRuleSpec) {
        *out = *in
-       if in.PodSelector != nil {
-               in, out := &in.PodSelector, &out.PodSelector
-               *out = new(v1.LabelSelector)
-               (*in).DeepCopyInto(*out)
+       if in.IcmpType != nil {
+               in, out := &in.IcmpType, &out.IcmpType
+               *out = make([]string, len(*in))
+               copy(*out, *in)
        }
 }
 
-// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new SdewanApplicationSpec.
-func (in *SdewanApplicationSpec) DeepCopy() *SdewanApplicationSpec {
+// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new NetworkFirewallRuleSpec.
+func (in *NetworkFirewallRuleSpec) DeepCopy() *NetworkFirewallRuleSpec {
        if in == nil {
                return nil
        }
-       out := new(SdewanApplicationSpec)
+       out := new(NetworkFirewallRuleSpec)
        in.DeepCopyInto(out)
        return out
 }
 
+// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
+func (in *SdewanApplication) DeepCopyInto(out *SdewanApplication) {
+        *out = *in
+        out.TypeMeta = in.TypeMeta
+        in.ObjectMeta.DeepCopyInto(&out.ObjectMeta)
+        in.Spec.DeepCopyInto(&out.Spec)
+        in.Status.DeepCopyInto(&out.Status)
+        out.AppInfo = in.AppInfo
+}
+
+// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new SdewanApplication.
+func (in *SdewanApplication) DeepCopy() *SdewanApplication {
+        if in == nil {
+                return nil
+        }
+        out := new(SdewanApplication)
+        in.DeepCopyInto(out)
+        return out
+}
+
+// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object.
+func (in *SdewanApplication) 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 *SdewanApplicationList) DeepCopyInto(out *SdewanApplicationList) {
+        *out = *in
+        out.TypeMeta = in.TypeMeta
+        in.ListMeta.DeepCopyInto(&out.ListMeta)
+        if in.Items != nil {
+                in, out := &in.Items, &out.Items
+                *out = make([]SdewanApplication, len(*in))
+                for i := range *in {
+                        (*in)[i].DeepCopyInto(&(*out)[i])
+                }
+        }
+}
+
+// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new SdewanApplicationList.
+func (in *SdewanApplicationList) DeepCopy() *SdewanApplicationList {
+        if in == nil {
+                return nil
+        }
+        out := new(SdewanApplicationList)
+        in.DeepCopyInto(out)
+        return out
+}
+
+// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object.
+func (in *SdewanApplicationList) 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 *SdewanApplicationSpec) DeepCopyInto(out *SdewanApplicationSpec) {
+        *out = *in
+        if in.PodSelector != nil {
+                in, out := &in.PodSelector, &out.PodSelector
+                *out = new(v1.LabelSelector)
+                (*in).DeepCopyInto(*out)
+        }
+}
+
+// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new SdewanApplicationSpec.
+func (in *SdewanApplicationSpec) DeepCopy() *SdewanApplicationSpec {
+        if in == nil {
+                return nil
+        }
+        out := new(SdewanApplicationSpec)
+        in.DeepCopyInto(out)
+        return out
+}
+
 // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
 func (in *SdewanStatus) DeepCopyInto(out *SdewanStatus) {
-       *out = *in
-       if in.AppliedTime != nil {
-               in, out := &in.AppliedTime, &out.AppliedTime
-               *out = (*in).DeepCopy()
-       }
+        *out = *in
+        if in.AppliedTime != nil {
+                in, out := &in.AppliedTime, &out.AppliedTime
+                *out = (*in).DeepCopy()
+        }
 }
 
 // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new SdewanStatus.
 func (in *SdewanStatus) DeepCopy() *SdewanStatus {
-       if in == nil {
-               return nil
-       }
-       out := new(SdewanStatus)
-       in.DeepCopyInto(out)
-       return out
+        if in == nil {
+                return nil
+        }
+        out := new(SdewanStatus)
+        in.DeepCopyInto(out)
+        return out
 }
 
 // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
 func (in *SiteConnection) DeepCopyInto(out *SiteConnection) {
-       *out = *in
-       if in.CryptoProposal != nil {
-               in, out := &in.CryptoProposal, &out.CryptoProposal
-               *out = make([]string, len(*in))
-               copy(*out, *in)
-       }
+        *out = *in
+        if in.CryptoProposal != nil {
+                in, out := &in.CryptoProposal, &out.CryptoProposal
+                *out = make([]string, len(*in))
+                copy(*out, *in)
+        }
 }
 
 // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new SiteConnection.
 func (in *SiteConnection) DeepCopy() *SiteConnection {
-       if in == nil {
-               return nil
-       }
-       out := new(SiteConnection)
-       in.DeepCopyInto(out)
-       return out
+        if in == nil {
+                return nil
+        }
+        out := new(SiteConnection)
+        in.DeepCopyInto(out)
+        return out
 }
diff --git a/platform/crd-ctrlr/src/config/crd/bases/batch.sdewan.akraino.org_cnfhubsites.yaml b/platform/crd-ctrlr/src/config/crd/bases/batch.sdewan.akraino.org_cnfhubsites.yaml
new file mode 100644 (file)
index 0000000..d9778a1
--- /dev/null
@@ -0,0 +1,81 @@
+
+---
+apiVersion: apiextensions.k8s.io/v1
+kind: CustomResourceDefinition
+metadata:
+  annotations:
+    controller-gen.kubebuilder.io/version: v0.7.0
+  creationTimestamp: null
+  name: cnfhubsites.batch.sdewan.akraino.org
+spec:
+  group: batch.sdewan.akraino.org
+  names:
+    kind: CNFHubSite
+    listKind: CNFHubSiteList
+    plural: cnfhubsites
+    singular: cnfhubsite
+  scope: Namespaced
+  versions:
+  - name: v1alpha1
+    schema:
+      openAPIV3Schema:
+        description: CNFHubSite is the Schema for the cnfhubsites API
+        properties:
+          apiVersion:
+            description: 'APIVersion defines the versioned schema of this representation
+              of an object. Servers should convert recognized schemas to the latest
+              internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources'
+            type: string
+          kind:
+            description: 'Kind is a string value representing the REST resource this
+              object represents. Servers may infer this from the endpoint the client
+              submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds'
+            type: string
+          metadata:
+            type: object
+          spec:
+            description: CNFHubSiteSpec defines the desired state of CNFHubSite
+            properties:
+              devicepip:
+                type: string
+              hubip:
+                type: string
+              site:
+                type: string
+              subnet:
+                type: string
+              type:
+                type: string
+            type: object
+          status:
+            description: CNFHubSiteStatus defines the observed state of CNFHubSiteStatus
+            properties:
+              devicepip:
+                type: string
+              hubip:
+                type: string
+              message:
+                type: string
+              remoteips:
+                items:
+                  type: string
+                type: array
+              subnet:
+                type: string
+              type:
+                description: 'INSERT ADDITIONAL STATUS FIELD - define observed state
+                  of cluster Important: Run "make" to regenerate code after modifying
+                  this file'
+                type: string
+            type: object
+        type: object
+    served: true
+    storage: true
+    subresources:
+      status: {}
+status:
+  acceptedNames:
+    kind: ""
+    plural: ""
+  conditions: []
+  storedVersions: []
diff --git a/platform/crd-ctrlr/src/config/crd/bases/batch.sdewan.akraino.org_networkfirewallrules.yaml b/platform/crd-ctrlr/src/config/crd/bases/batch.sdewan.akraino.org_networkfirewallrules.yaml
new file mode 100644 (file)
index 0000000..741703d
--- /dev/null
@@ -0,0 +1,103 @@
+
+---
+apiVersion: apiextensions.k8s.io/v1
+kind: CustomResourceDefinition
+metadata:
+  annotations:
+    controller-gen.kubebuilder.io/version: v0.7.0
+  creationTimestamp: null
+  name: networkfirewallrules.batch.sdewan.akraino.org
+spec:
+  group: batch.sdewan.akraino.org
+  names:
+    kind: NetworkFirewallRule
+    listKind: NetworkFirewallRuleList
+    plural: networkfirewallrules
+    singular: networkfirewallrule
+  scope: Namespaced
+  versions:
+  - name: v1alpha1
+    schema:
+      openAPIV3Schema:
+        description: NetworkFirewallRule is the Schema for the networkfirewallrules
+          API
+        properties:
+          apiVersion:
+            description: 'APIVersion defines the versioned schema of this representation
+              of an object. Servers should convert recognized schemas to the latest
+              internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources'
+            type: string
+          kind:
+            description: 'Kind is a string value representing the REST resource this
+              object represents. Servers may infer this from the endpoint the client
+              submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds'
+            type: string
+          metadata:
+            type: object
+          spec:
+            description: NetworkFirewallRuleSpec defines the desired state of NetworkFirewallRule
+            properties:
+              dest:
+                type: string
+              dest_ip:
+                type: string
+              dest_port:
+                type: string
+              extra:
+                type: string
+              family:
+                type: string
+              icmp_type:
+                items:
+                  type: string
+                type: array
+              mark:
+                type: string
+              name:
+                description: Foo is an example field of NetworkFirewallRule. Edit
+                  NetworkFirewallRule_types.go to remove/update
+                type: string
+              proto:
+                type: string
+              set_mark:
+                type: string
+              set_xmark:
+                type: string
+              src:
+                type: string
+              src_ip:
+                type: string
+              src_mac:
+                type: string
+              src_port:
+                type: string
+              target:
+                type: string
+            type: object
+          status:
+            description: status subsource used for Sdewan rule CRDs
+            properties:
+              appliedGeneration:
+                format: int64
+                type: integer
+              appliedTime:
+                format: date-time
+                type: string
+              message:
+                type: string
+              state:
+                type: string
+            required:
+            - state
+            type: object
+        type: object
+    served: true
+    storage: true
+    subresources:
+      status: {}
+status:
+  acceptedNames:
+    kind: ""
+    plural: ""
+  conditions: []
+  storedVersions: []
index daeb9c2..c46bdf5 100644 (file)
@@ -6,6 +6,7 @@
 resources:
 - bases/batch.sdewan.akraino.org_mwan3policies.yaml
 - bases/batch.sdewan.akraino.org_mwan3rules.yaml
+- bases/batch.sdewan.akraino.org_networkfirewallrules.yaml
 - bases/batch.sdewan.akraino.org_firewallzones.yaml
 - bases/batch.sdewan.akraino.org_firewallrules.yaml
 - bases/batch.sdewan.akraino.org_firewallsnats.yaml
@@ -16,6 +17,7 @@ resources:
 - bases/batch.sdewan.akraino.org_ipsecsites.yaml
 - bases/batch.sdewan.akraino.org_cnfservices.yaml
 - bases/batch.sdewan.akraino.org_cnflocalservices.yaml
+- bases/batch.sdewan.akraino.org_cnfhubsites.yaml
 - bases/batch.sdewan.akraino.org_sdewanapplications.yaml
 - bases/batch.sdewan.akraino.org_cnfstatuses.yaml
 - bases/batch.sdewan.akraino.org_cnfroutes.yaml
index f87d1e5..271f32f 100644 (file)
@@ -54,6 +54,26 @@ rules:
   - get
   - list
   - watch
+- apiGroups:
+  - batch.sdewan.akraino.org
+  resources:
+  - cnfhubsites
+  verbs:
+  - create
+  - delete
+  - get
+  - list
+  - patch
+  - update
+  - watch
+- apiGroups:
+  - batch.sdewan.akraino.org
+  resources:
+  - cnfhubsites/status
+  verbs:
+  - get
+  - patch
+  - update
 - apiGroups:
   - batch.sdewan.akraino.org
   resources:
@@ -374,6 +394,26 @@ rules:
   - get
   - patch
   - update
+- apiGroups:
+  - batch.sdewan.akraino.org
+  resources:
+  - networkfirewallrules
+  verbs:
+  - create
+  - delete
+  - get
+  - list
+  - patch
+  - update
+  - watch
+- apiGroups:
+  - batch.sdewan.akraino.org
+  resources:
+  - networkfirewallrules/status
+  verbs:
+  - get
+  - patch
+  - update
 - apiGroups:
   - batch.sdewan.akraino.org
   resources:
index 8eb7bd1..1e98ca1 100644 (file)
@@ -27,6 +27,7 @@ webhooks:
     resources:
     - mwan3policies
     - mwan3rules
+    - networkfirewallrules
     - firewallzones
     - firewallforwardings
     - firewallrules
@@ -37,6 +38,7 @@ webhooks:
     - cnfrouterules
     - cnfservices
     - cnflocalservices
+    - cnfhubsites
     - cnfstatuses
     - sdewanapplication
     - ipsecproposals
@@ -61,9 +63,9 @@ webhooks:
     operations:
     - UPDATE
     resources:
-    - deployments
     - mwan3policies
     - mwan3rules
+    - networkfirewallrules
     - firewallzones
     - firewallforwardings
     - firewallrules
@@ -74,6 +76,7 @@ webhooks:
     - cnfroutes
     - cnfrouterules
     - cnflocalservices
+    - cnfhubsites
     - cnfstatuses
     - sdewanapplication
     - ipsecproposals
diff --git a/platform/crd-ctrlr/src/controllers/cnfhubsite_controller.go b/platform/crd-ctrlr/src/controllers/cnfhubsite_controller.go
new file mode 100644 (file)
index 0000000..9fd965c
--- /dev/null
@@ -0,0 +1,484 @@
+// SPDX-License-Identifier: Apache-2.0\r
+// Copyright (c) 2021 Intel Corporation\r
+package controllers\r
+\r
+import (\r
+       "context"\r
+       "errors"\r
+       "net"\r
+       "strconv"\r
+       "strings"\r
+       "sync"\r
+       "time"\r
+       "log"\r
+\r
+       "github.com/go-logr/logr"\r
+       errs "k8s.io/apimachinery/pkg/api/errors"\r
+       metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"\r
+       "k8s.io/apimachinery/pkg/runtime"\r
+       "k8s.io/apimachinery/pkg/util/wait"\r
+       ctrl "sigs.k8s.io/controller-runtime"\r
+       "sigs.k8s.io/controller-runtime/pkg/builder"\r
+       "sigs.k8s.io/controller-runtime/pkg/client"\r
+       "sigs.k8s.io/controller-runtime/pkg/predicate"\r
+\r
+       batchv1alpha1 "sdewan.akraino.org/sdewan/api/v1alpha1"\r
+)\r
+\r
+var inHSQueryStatus = false\r
+\r
+// CNFHubSiteReconciler reconciles a CNFHubSite object\r
+type CNFHubSiteReconciler struct {\r
+       client.Client\r
+       Log           logr.Logger\r
+       CheckInterval time.Duration\r
+       Scheme        *runtime.Scheme\r
+       mux           sync.Mutex\r
+}\r
+\r
+// +kubebuilder:rbac:groups=batch.sdewan.akraino.org,resources=cnfhubsites,verbs=get;list;watch;create;update;patch;delete\r
+// +kubebuilder:rbac:groups=batch.sdewan.akraino.org,resources=cnfhubsites/status,verbs=get;update;patch\r
+\r
+func (r *CNFHubSiteReconciler) Reconcile(req ctrl.Request) (ctrl.Result, error) {\r
+       ctx := context.Background()\r
+       log := r.Log.WithValues("CNFHubSite", req.NamespacedName)\r
+       during, _ := time.ParseDuration("5s")\r
+\r
+       instance, err := r.getInstance(req)\r
+       if err != nil {\r
+               if errs.IsNotFound(err) {\r
+                       // No instance\r
+                       return ctrl.Result{}, nil\r
+               }\r
+               // Error reading the object - requeue the request.\r
+               return ctrl.Result{RequeueAfter: during}, nil\r
+       }\r
+\r
+       finalizerName := "cnfhubsite.finalizers.sdewan.akraino.org"\r
+       delete_timestamp := getDeletionTempstamp(instance)\r
+\r
+       if delete_timestamp.IsZero() {\r
+               // Creating or updating CR\r
+               // Process instance\r
+               err = r.processInstance(instance)\r
+               if err != nil {\r
+                       log.Error(err, "Adding/Updating CR")\r
+                       instance.Status.Message = err.Error()\r
+                       r.Status().Update(ctx, instance)\r
+\r
+                       return ctrl.Result{}, err\r
+               }\r
+\r
+               finalizers := getFinalizers(instance)\r
+               if !containsString(finalizers, finalizerName) {\r
+                       appendFinalizer(instance, finalizerName)\r
+                       if err := r.Update(ctx, instance); err != nil {\r
+                               return ctrl.Result{}, err\r
+                       }\r
+                       log.Info("Added finalizer for CNFHubSite")\r
+               }\r
+       } else {\r
+               // Deleting CR\r
+               // Remove instance\r
+               err = r.removeInstance(instance)\r
+               if err != nil {\r
+                       log.Error(err, "Deleting CR")\r
+                       return ctrl.Result{RequeueAfter: during}, nil\r
+               }\r
+\r
+               finalizers := getFinalizers(instance)\r
+               if containsString(finalizers, finalizerName) {\r
+                       removeFinalizer(instance, finalizerName)\r
+                       if err := r.Update(ctx, instance); err != nil {\r
+                               return ctrl.Result{}, err\r
+                       }\r
+               }\r
+       }\r
+\r
+       return ctrl.Result{}, nil\r
+}\r
+\r
+func (r *CNFHubSiteReconciler) getInstance(req ctrl.Request) (*batchv1alpha1.CNFHubSite, error) {\r
+       instance := &batchv1alpha1.CNFHubSite{}\r
+       err := r.Get(context.Background(), req.NamespacedName, instance)\r
+       return instance, err\r
+}\r
+\r
+func (r *CNFHubSiteReconciler) getIP4s(dns string) ([]string, error) {\r
+       ips, err := net.LookupIP(dns)\r
+       var ip4s []string\r
+\r
+       if err == nil {\r
+               for _, ip := range ips {\r
+                       if strings.Contains(ip.String(), ".") {\r
+                               ip4s = append(ip4s, ip.String())\r
+                       }\r
+               }\r
+       }\r
+\r
+       return ip4s, err\r
+}\r
+\r
+func (r *CNFHubSiteReconciler) processInstance(instance *batchv1alpha1.CNFHubSite) error {\r
+       r.mux.Lock()\r
+       defer r.mux.Unlock()\r
+\r
+       log.Println("Into hubsite processing")\r
+       // check Type\r
+       t := instance.Spec.Type\r
+       log.Println("Type:", t)\r
+       if t != "Hub" && t != "Device" {\r
+               return errors.New("Invalid Type: should be Hub or Device")\r
+       }\r
+\r
+       ls := instance.Spec.Site\r
+       sn := instance.Spec.Subnet\r
+\r
+       if ls == "" && sn == "" {\r
+               return errors.New("Invalid Site: neither of the url or the subnet set")\r
+       }\r
+\r
+       // check Site\r
+       var lips []string\r
+       if ls != "" {\r
+               lips, err := r.getIP4s(ls)\r
+               if err != nil || len(lips) == 0 {\r
+                       if err != nil {\r
+                               r.Log.Error(err, "Hub Site")\r
+                       }\r
+                       return errors.New("Cannot retrieve Site ip")\r
+               }\r
+       }\r
+\r
+       // check subnet\r
+       if sn != "" {\r
+               _, _, err := net.ParseCIDR(sn)\r
+               log.Println("Parsing subnet")\r
+               if err != nil {\r
+                       r.Log.Error(err, "Subnet")\r
+                       return errors.New("Invalid Subnet")\r
+               }\r
+       }\r
+\r
+       // check HubIP\r
+       hip := instance.Spec.HubIP\r
+       if hip == "" {\r
+               if t == "Hub" {\r
+                       return errors.New("HubIP is required")\r
+               }\r
+       } else {\r
+               ip := net.ParseIP(hip)\r
+               if ip == nil {\r
+                       return errors.New("Invalid HubIP: " + hip)\r
+               }\r
+       }\r
+\r
+       // check DevicePIP\r
+       dpip := instance.Spec.DevicePIP\r
+       if dpip == "" {\r
+               if t == "Device" {\r
+                       return errors.New("DevicePIP is required")\r
+               }\r
+       } else {\r
+               ip := net.ParseIP(dpip)\r
+               if ip == nil {\r
+                       return errors.New("Invalid DevicePIP: " + dpip)\r
+               }\r
+       }\r
+\r
+       var curStatus = batchv1alpha1.CNFHubSiteStatus{\r
+               Type:      t,\r
+               SiteIPs:   lips,\r
+               Subnet:    sn,\r
+               HubIP:     hip,\r
+               DevicePIP: dpip,\r
+               Message:   "",\r
+       }\r
+\r
+       if !curStatus.IsEqual(&instance.Status) {\r
+               r.removeCRs(instance)\r
+               r.addCRs(instance, &curStatus)\r
+               instance.Status = curStatus\r
+               r.Status().Update(context.Background(), instance)\r
+       }\r
+\r
+       return nil\r
+}\r
+\r
+func (r *CNFHubSiteReconciler) addCRs(instance *batchv1alpha1.CNFHubSite, status *batchv1alpha1.CNFHubSiteStatus) error {\r
+       r.Log.Info("Creating New CRs for Hub Site : " + instance.Name)\r
+       var dips []string\r
+       if status.Subnet != "" {\r
+               dips = append(dips, status.Subnet)\r
+       }\r
+       dips = append(dips, status.SiteIPs...)\r
+       t := status.Type\r
+       if t == "Hub" {\r
+               // Create Route CR in Hub\r
+               route_base_name := instance.Name + "route"\r
+               for i, ip := range dips {\r
+                       route_name := route_base_name + strconv.Itoa(i)\r
+                       route_instance := &batchv1alpha1.CNFRoute{\r
+                               ObjectMeta: metav1.ObjectMeta{\r
+                                       Name:      route_name,\r
+                                       Namespace: instance.Namespace,\r
+                                       Labels:    instance.Labels,\r
+                               },\r
+                               Spec: batchv1alpha1.CNFRouteSpec{\r
+                                       Dst:   ip,\r
+                                       Dev:   "vti_" + status.HubIP,\r
+                                       Table: "default",\r
+                               },\r
+                       }\r
+\r
+                       err := r.Create(context.Background(), route_instance)\r
+                       if err != nil {\r
+                               r.Log.Error(err, "Creating Route CR : "+route_name)\r
+                       }\r
+               }\r
+       } else {\r
+               // Create Route CR and SNAT CR in Device\r
+               route_base_name := instance.Name + "route"\r
+               nat_base_name := instance.Name + "snat"\r
+               for i, ip := range dips {\r
+                       // Route CR\r
+                       route_name := route_base_name + strconv.Itoa(i)\r
+                       route_instance := &batchv1alpha1.CNFRoute{\r
+                               ObjectMeta: metav1.ObjectMeta{\r
+                                       Name:      route_name,\r
+                                       Namespace: instance.Namespace,\r
+                                       Labels:    instance.Labels,\r
+                               },\r
+                               Spec: batchv1alpha1.CNFRouteSpec{\r
+                                       Dst:   ip,\r
+                                       Dev:   "#" + status.DevicePIP,\r
+                                       Table: "cnf",\r
+                               },\r
+                       }\r
+                       log.Println(route_instance)\r
+\r
+                       err := r.Create(context.Background(), route_instance)\r
+                       if err != nil {\r
+                               r.Log.Error(err, "Creating Route CR : "+route_name)\r
+                       }\r
+\r
+                       // SNAT CR\r
+                       nat_name := nat_base_name + strconv.Itoa(i)\r
+                       nat_instance := &batchv1alpha1.CNFNAT{\r
+                               ObjectMeta: metav1.ObjectMeta{\r
+                                       Name:      nat_name,\r
+                                       Namespace: instance.Namespace,\r
+                                       Labels:    instance.Labels,\r
+                               },\r
+                               Spec: batchv1alpha1.CNFNATSpec{\r
+                                       DestIp:   ip,\r
+                                       Dest:     "#source",\r
+                                       SrcDIp:   status.DevicePIP,\r
+                                       Index:    "1",\r
+                                       Target:   "SNAT",\r
+                               },\r
+                       }\r
+\r
+                       err = r.Create(context.Background(), nat_instance)\r
+                       if err != nil {\r
+                               r.Log.Error(err, "Creating SNAT CR : "+nat_name)\r
+                       }\r
+               }\r
+       }\r
+       \r
+       return nil\r
+}\r
+\r
+func (r *CNFHubSiteReconciler) removeInstance(instance *batchv1alpha1.CNFHubSite) error {\r
+       r.mux.Lock()\r
+       defer r.mux.Unlock()\r
+       return r.removeCRs(instance)\r
+}\r
+\r
+func (r *CNFHubSiteReconciler) removeCRs(instance *batchv1alpha1.CNFHubSite) error {\r
+       r.Log.Info("Deleting CRs for Hub Site : " + instance.Name)\r
+       var dips []string\r
+       if instance.Status.Subnet != "" {\r
+               dips = append(dips, instance.Status.Subnet)\r
+       }\r
+       dips = append(dips, instance.Status.SiteIPs...)\r
+\r
+       t := instance.Status.Type\r
+       if t == "Hub" {\r
+               // Create Route CR in Hub\r
+               route_base_name := instance.Name + "route"\r
+               for i, _ := range dips {\r
+                       route_name := route_base_name + strconv.Itoa(i)\r
+                       route_instance := &batchv1alpha1.CNFRoute{\r
+                               ObjectMeta: metav1.ObjectMeta{\r
+                                       Name:      route_name,\r
+                                       Namespace: instance.Namespace,\r
+                                       Labels:    instance.Labels,\r
+                               },\r
+                               Spec: batchv1alpha1.CNFRouteSpec{},\r
+                       }\r
+\r
+                       err := r.Delete(context.Background(), route_instance)\r
+                       if err != nil {\r
+                               r.Log.Error(err, "Deleting Route CR : "+route_name)\r
+                       }\r
+\r
+                       // check resource\r
+                       err = wait.PollImmediate(time.Second, time.Second*10,\r
+                               func() (bool, error) {\r
+                                       route_instance_temp := &batchv1alpha1.CNFRoute{}\r
+                                       err_get := r.Get(context.Background(), client.ObjectKey{\r
+                                               Namespace: instance.Namespace,\r
+                                               Name:      route_name,\r
+                                       }, route_instance_temp)\r
+\r
+                                       if errs.IsNotFound(err_get) {\r
+                                               return true, nil\r
+                                       }\r
+                                       r.Log.Info("Waiting for Deleting CR : " + route_name)\r
+                                       return false, nil\r
+                               },\r
+                       )\r
+\r
+                       if err != nil {\r
+                               r.Log.Error(err, "Failed to delete CR : "+route_name)\r
+                       }\r
+               }\r
+       } else {\r
+               // Delete Route CR and SNAT CR in Device\r
+               route_base_name := instance.Name + "route"\r
+               nat_base_name := instance.Name + "snat"\r
+               for i, _ := range dips {\r
+                       // Route CR\r
+                       route_name := route_base_name + strconv.Itoa(i)\r
+                       route_instance := &batchv1alpha1.CNFRoute{\r
+                               ObjectMeta: metav1.ObjectMeta{\r
+                                       Name:      route_name,\r
+                                       Namespace: instance.Namespace,\r
+                                       Labels:    instance.Labels,\r
+                               },\r
+                               Spec: batchv1alpha1.CNFRouteSpec{},\r
+                       }\r
+\r
+                       err := r.Delete(context.Background(), route_instance)\r
+                       if err != nil {\r
+                               r.Log.Error(err, "Deleting Route CR : "+route_name)\r
+                       }\r
+\r
+                       // SNAT CR\r
+                       nat_name := nat_base_name + strconv.Itoa(i)\r
+                       nat_instance := &batchv1alpha1.CNFNAT{\r
+                               ObjectMeta: metav1.ObjectMeta{\r
+                                       Name:      nat_name,\r
+                                       Namespace: instance.Namespace,\r
+                                       Labels:    instance.Labels,\r
+                               },\r
+                               Spec: batchv1alpha1.CNFNATSpec{},\r
+                       }\r
+\r
+                       err = r.Delete(context.Background(), nat_instance)\r
+                       if err != nil {\r
+                               r.Log.Error(err, "Deleting SNAT CR : "+nat_name)\r
+                       }\r
+\r
+                       // check resource\r
+                       err = wait.PollImmediate(time.Second, time.Second*10,\r
+                               func() (bool, error) {\r
+                                       route_instance_temp := &batchv1alpha1.CNFRoute{}\r
+                                       err_get := r.Get(context.Background(), client.ObjectKey{\r
+                                               Namespace: instance.Namespace,\r
+                                               Name:      route_name,\r
+                                       }, route_instance_temp)\r
+\r
+                                       if errs.IsNotFound(err_get) {\r
+                                               return true, nil\r
+                                       }\r
+                                       r.Log.Info("Waiting for Deleting CR : " + route_name)\r
+                                       return false, nil\r
+                               },\r
+                       )\r
+\r
+                       if err != nil {\r
+                               r.Log.Error(err, "Failed to delete CR : "+route_name)\r
+                       }\r
+\r
+                       err = wait.PollImmediate(time.Second, time.Second*10,\r
+                               func() (bool, error) {\r
+                                       nat_instance_temp := &batchv1alpha1.CNFNAT{}\r
+                                       err_get := r.Get(context.Background(), client.ObjectKey{\r
+                                               Namespace: instance.Namespace,\r
+                                               Name:      nat_name,\r
+                                       }, nat_instance_temp)\r
+\r
+                                       if errs.IsNotFound(err_get) {\r
+                                               return true, nil\r
+                                       }\r
+                                       r.Log.Info("Waiting for Deleting CR : " + nat_name)\r
+                                       return false, nil\r
+                               },\r
+                       )\r
+\r
+                       if err != nil {\r
+                               r.Log.Error(err, "Failed to delete CR : "+nat_name)\r
+                       }\r
+               }\r
+       }\r
+\r
+       return nil\r
+}\r
+\r
+func (r *CNFHubSiteReconciler) check() {\r
+       ls_list := &batchv1alpha1.CNFHubSiteList{}\r
+       err := r.List(context.Background(), ls_list)\r
+       if err != nil {\r
+               r.Log.Error(err, "Failed to list CNFHubSite CRs")\r
+       } else {\r
+               if len(ls_list.Items) > 0 {\r
+                       for _, inst := range ls_list.Items {\r
+                               r.Log.Info("Checking CNFHubSite: " + inst.Name)\r
+                               r.processInstance(&inst)\r
+                       }\r
+               }\r
+       }\r
+}\r
+\r
+// Regular check\r
+func (r *CNFHubSiteReconciler) SafeCheck() {\r
+       doCheck := true\r
+       r.mux.Lock()\r
+       if !inHSQueryStatus {\r
+               inHSQueryStatus = true\r
+       } else {\r
+               doCheck = false\r
+       }\r
+       r.mux.Unlock()\r
+\r
+       if doCheck {\r
+               r.check()\r
+\r
+               r.mux.Lock()\r
+               inHSQueryStatus = false\r
+               r.mux.Unlock()\r
+       }\r
+}\r
+\r
+func (r *CNFHubSiteReconciler) SetupWithManager(mgr ctrl.Manager) error {\r
+       // Start the loop to check ip address change of local/remote services\r
+       go func() {\r
+               interval := time.After(r.CheckInterval)\r
+               for {\r
+                       select {\r
+                       case <-interval:\r
+                               r.SafeCheck()\r
+                               interval = time.After(r.CheckInterval)\r
+                       case <-context.Background().Done():\r
+                               return\r
+                       }\r
+               }\r
+       }()\r
+\r
+       ps := builder.WithPredicates(predicate.GenerationChangedPredicate{})\r
+       return ctrl.NewControllerManagedBy(mgr).\r
+               For(&batchv1alpha1.CNFHubSite{}, ps).\r
+               Complete(r)\r
+}\r
index 2efaacf..736ecd3 100644 (file)
 // SPDX-License-Identifier: Apache-2.0
+// SPDX-License-Identifier: Apache-2.0
 // Copyright (c) 2021 Intel Corporation
 package controllers
 
 import (
        "context"
-       "reflect"
+       "errors"
+       "net"
+       "strconv"
+       "strings"
+       "sync"
+       "time"
 
        "github.com/go-logr/logr"
-       appsv1 "k8s.io/api/apps/v1"
-       //corev1 "k8s.io/api/core/v1"
+
+       errs "k8s.io/apimachinery/pkg/api/errors"
+       metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
        "k8s.io/apimachinery/pkg/runtime"
+       "k8s.io/apimachinery/pkg/util/wait"
        ctrl "sigs.k8s.io/controller-runtime"
        "sigs.k8s.io/controller-runtime/pkg/client"
-       "sigs.k8s.io/controller-runtime/pkg/handler"
-       "sigs.k8s.io/controller-runtime/pkg/source"
 
        batchv1alpha1 "sdewan.akraino.org/sdewan/api/v1alpha1"
-       "sdewan.akraino.org/sdewan/openwrt"
 )
 
-var cnfServiceHandler = new(CNFServiceHandler)
-
-type CNFServiceHandler struct {
+// CNFServiceReconciler reconciles a CNFService object
+type CNFServiceReconciler struct {
+       client.Client
+       Log           logr.Logger
+       Scheme        *runtime.Scheme
+       mux           sync.Mutex
+       CheckInterval time.Duration
 }
 
-func (m *CNFServiceHandler) GetType() string {
-       return "cnfService"
-}
+var inSQueryStatus = false
 
-func (m *CNFServiceHandler) GetName(instance runtime.Object) string {
-       service := instance.(*batchv1alpha1.CNFService)
-       return service.Name
-}
+// +kubebuilder:rbac:groups=batch.sdewan.akraino.org,resources=cnfservices,verbs=get;list;watch;create;update;patch;delete
+// +kubebuilder:rbac:groups=batch.sdewan.akraino.org,resources=cnfservices/status,verbs=get;update;patch
+
+func (r *CNFServiceReconciler) Reconcile(req ctrl.Request) (ctrl.Result, error) {
+       ctx := context.Background()
+       log := r.Log.WithValues("cnfservices", req.NamespacedName)
+       during, _ := time.ParseDuration("5s")
+       instance, err := r.GetInstance(req)
+       if err != nil {
+               if errs.IsNotFound(err) {
+                       // No instance
+                       return ctrl.Result{}, nil
+               }
+               // Error reading the object - requeue the request.
+               return ctrl.Result{RequeueAfter: during}, nil
+       }
+       finalizerName := "cnfservice.finalizers.sdewan.akraino.org"
+       delete_timestamp := getDeletionTempstamp(instance)
+       log.Info("start Reconcile")
+       if delete_timestamp.IsZero() {
+               // Creating or updating CR
+               // Process instance
+               err = r.processInstance(instance)
+               if err != nil {
+                       log.Error(err, "Adding/Updating CR")
+                       instance.Status.Message = err.Error()
+                       r.Status().Update(ctx, instance)
+                       return ctrl.Result{}, err
+               }
+
+               finalizers := getFinalizers(instance)
+               if !containsString(finalizers, finalizerName) {
+                       appendFinalizer(instance, finalizerName)
+                       if err := r.Update(ctx, instance); err != nil {
+                               return ctrl.Result{}, err
+                       }
+                       log.Info("Added finalizer for CNFService")
+               }
+       } else {
+               // Deleting CR
+               // Remove instance
+               err = r.removeInstance(instance)
+               if err != nil {
+                       log.Error(err, "Deleting CR")
+                       return ctrl.Result{RequeueAfter: during}, nil
+               }
 
-func (m *CNFServiceHandler) GetFinalizer() string {
-       return "rule.finalizers.sdewan.akraino.org"
+               finalizers := getFinalizers(instance)
+               if containsString(finalizers, finalizerName) {
+                       removeFinalizer(instance, finalizerName)
+                       if err := r.Update(ctx, instance); err != nil {
+                               return ctrl.Result{}, err
+                       }
+               }
+       }
+
+       return ctrl.Result{}, nil
 }
 
-func (m *CNFServiceHandler) GetInstance(r client.Client, ctx context.Context, req ctrl.Request) (runtime.Object, error) {
+func (r *CNFServiceReconciler) GetInstance(req ctrl.Request) (*batchv1alpha1.CNFService, error) {
        instance := &batchv1alpha1.CNFService{}
-       err := r.Get(ctx, req.NamespacedName, instance)
+       err := r.Get(context.Background(), req.NamespacedName, instance)
        return instance, err
 }
 
-func (m *CNFServiceHandler) Convert(instance runtime.Object, deployment appsv1.Deployment) (openwrt.IOpenWrtObject, error) {
-       svc := instance.(*batchv1alpha1.CNFService)
-       openwrtsvc := openwrt.SdewanSvc{
-               Name:     svc.Name,
-               FullName: svc.Spec.FullName,
-               Port:     svc.Spec.Port,
-               DPort:    svc.Spec.DPort,
+func (r *CNFServiceReconciler) processInstance(instance *batchv1alpha1.CNFService) error {
+       r.mux.Lock()
+       defer r.mux.Unlock()
+       // check service ip
+       name := instance.Spec.FullName
+       ipList, err := r.getIP4s(name)
+       if err != nil || len(ipList) == 0 {
+               if err != nil {
+                       r.removeNats(instance)
+                       r.Log.Error(err, "CNF Service")
+               }
+               return errors.New("Cannot reterive CNF Service ip")
        }
-       return &openwrtsvc, nil
-}
 
-func (m *CNFServiceHandler) IsEqual(instance1 openwrt.IOpenWrtObject, instance2 openwrt.IOpenWrtObject) bool {
-       service1 := instance1.(*openwrt.SdewanSvc)
-       service2 := instance2.(*openwrt.SdewanSvc)
-       return reflect.DeepEqual(*service1, *service2)
-}
+       // check  port
+       svcPort := instance.Spec.Port
+       if svcPort != "" {
+               _, err = strconv.Atoi(svcPort)
+               if err != nil {
+                       return errors.New("Port: " + err.Error())
+               }
+       }
 
-func (m *CNFServiceHandler) GetObject(clientInfo *openwrt.OpenwrtClientInfo, name string) (openwrt.IOpenWrtObject, error) {
-       openwrtClient := openwrt.GetOpenwrtClient(*clientInfo)
-       svc := openwrt.SvcClient{OpenwrtClient: openwrtClient}
-       ret, err := svc.GetSvc(name)
-       return ret, err
+       // check dport
+       svcDPort := instance.Spec.DPort
+       if svcDPort != "" {
+               _, err = strconv.Atoi(svcDPort)
+               if err != nil {
+                       return errors.New("svcDPort: " + err.Error())
+               }
+       }
+
+       var curStatus = batchv1alpha1.CNFServiceStatus{
+               SIp:   ipList[0],
+               Port:  svcPort,
+               DPort: svcDPort,
+       }
+
+       if !curStatus.IsEqual(&instance.Status) {
+               r.removeNats(instance)
+               r.addNats(instance, &curStatus)
+               instance.Status = curStatus
+               r.Log.Info("start update")
+               r.Status().Update(context.Background(), instance)
+
+       }
+
+       return nil
 }
+func (r *CNFServiceReconciler) getIP4s(dns string) ([]string, error) {
+       ips, err := net.LookupIP(dns)
+       var ip4s []string
+
+       if err == nil {
+               for _, ip := range ips {
+                       if strings.Contains(ip.String(), ".") {
+                               ip4s = append(ip4s, ip.String())
+                       }
+               }
+       }
 
-func (m *CNFServiceHandler) CreateObject(clientInfo *openwrt.OpenwrtClientInfo, instance openwrt.IOpenWrtObject) (openwrt.IOpenWrtObject, error) {
-       openwrtClient := openwrt.GetOpenwrtClient(*clientInfo)
-       svc := openwrt.SvcClient{OpenwrtClient: openwrtClient}
-       service := instance.(*openwrt.SdewanSvc)
-       return svc.CreateSvc(*service)
+       return ip4s, err
 }
 
-func (m *CNFServiceHandler) UpdateObject(clientInfo *openwrt.OpenwrtClientInfo, instance openwrt.IOpenWrtObject) (openwrt.IOpenWrtObject, error) {
-       openwrtClient := openwrt.GetOpenwrtClient(*clientInfo)
-       svc := openwrt.SvcClient{OpenwrtClient: openwrtClient}
-       service := instance.(*openwrt.SdewanSvc)
-       return svc.UpdateSvc(*service)
+func (r *CNFServiceReconciler) removeNats(instance *batchv1alpha1.CNFService) error {
+       r.Log.Info("Deleting CNFNAT CR for CNF Service : " + instance.Name)
+       nat_name := instance.Name + "nat"
+       nat_instance := &batchv1alpha1.CNFNAT{
+               ObjectMeta: metav1.ObjectMeta{
+                       Name:      nat_name,
+                       Namespace: instance.Namespace,
+                       Labels:    instance.Labels,
+               },
+               Spec: batchv1alpha1.CNFNATSpec{},
+       }
+       err := r.Delete(context.Background(), nat_instance)
+       if err != nil {
+               r.Log.Error(err, "Deleting NAT CR : "+nat_name)
+       }
+       // check resource
+       err = wait.PollImmediate(time.Second, time.Second*10,
+               func() (bool, error) {
+                       nat_instance_temp := &batchv1alpha1.CNFNAT{}
+                       err_get := r.Get(context.Background(), client.ObjectKey{
+                               Namespace: instance.Namespace,
+                               Name:      nat_name,
+                       }, nat_instance_temp)
+                       if errs.IsNotFound(err_get) {
+                               return true, nil
+                       }
+                       r.Log.Info("Waiting for Deleting CR : " + nat_name)
+                       return false, nil
+               },
+       )
+
+       if err != nil {
+               r.Log.Error(err, "Failed to delete CR : "+nat_name)
+       }
+       return nil
 }
 
-func (m *CNFServiceHandler) DeleteObject(clientInfo *openwrt.OpenwrtClientInfo, name string) error {
-       openwrtClient := openwrt.GetOpenwrtClient(*clientInfo)
-       svc := openwrt.SvcClient{OpenwrtClient: openwrtClient}
-       return svc.DeleteSvc(name)
+func (r *CNFServiceReconciler) addNats(instance *batchv1alpha1.CNFService, status *batchv1alpha1.CNFServiceStatus) error {
+       r.Log.Info("Creating New CNFNAT CR for CNF Service : " + instance.Name)
+       nat_name := instance.Name + "nat"
+       nat_instance := &batchv1alpha1.CNFNAT{
+               ObjectMeta: metav1.ObjectMeta{
+                       Name:      nat_name,
+                       Namespace: instance.Namespace,
+                       Labels:    instance.Labels,
+               },
+               Spec: batchv1alpha1.CNFNATSpec{
+                       DestIp:   status.SIp,
+                       DestPort: status.Port,
+                       SrcDPort: status.DPort,
+                       Index:    "2",
+                       Proto:    "tcp",
+                       Target:   "DNAT",
+               }}
+
+       err := r.Create(context.Background(), nat_instance)
+       if err != nil {
+               r.Log.Error(err, "Creating NAT CR : "+nat_name)
+       }
+       return nil
 }
 
-func (m *CNFServiceHandler) Restart(clientInfo *openwrt.OpenwrtClientInfo) (bool, error) {
-       return true, nil
+func (r *CNFServiceReconciler) removeInstance(instance *batchv1alpha1.CNFService) error {
+       r.mux.Lock()
+       defer r.mux.Unlock()
+       return r.removeNats(instance)
 }
 
-// CNFServiceReconciler reconciles a CNFService object
-type CNFServiceReconciler struct {
-       client.Client
-       Log    logr.Logger
-       Scheme *runtime.Scheme
+func (r *CNFServiceReconciler) check() {
+       ls_list := &batchv1alpha1.CNFServiceList{}
+       err := r.List(context.Background(), ls_list)
+       r.Log.Info("start check")
+       if err != nil {
+               r.Log.Error(err, "Failed to list CNFService CRs")
+       } else {
+               if len(ls_list.Items) > 0 {
+                       for _, inst := range ls_list.Items {
+                               r.processInstance(&inst)
+                       }
+               }
+       }
 }
 
-// +kubebuilder:rbac:groups=batch.sdewan.akraino.org,resources=cnfservices,verbs=get;list;watch;create;update;patch;delete
-// +kubebuilder:rbac:groups=batch.sdewan.akraino.org,resources=cnfservices/status,verbs=get;update;patch
+func (r *CNFServiceReconciler) SafeCheck() {
+       doCheck := true
+       r.mux.Lock()
+       if !inSQueryStatus {
+               inSQueryStatus = true
+       } else {
+               doCheck = false
+       }
+       r.mux.Unlock()
 
-func (r *CNFServiceReconciler) Reconcile(req ctrl.Request) (ctrl.Result, error) {
-       return ProcessReconcile(r, r.Log, req, cnfServiceHandler)
+       if doCheck {
+               r.check()
+               r.mux.Lock()
+               inSQueryStatus = false
+               r.mux.Unlock()
+       }
 }
 
 func (r *CNFServiceReconciler) SetupWithManager(mgr ctrl.Manager) error {
+       go func() {
+               interval := time.After(r.CheckInterval)
+               for {
+                       select {
+                       case <-interval:
+                               r.SafeCheck()
+                               interval = time.After(r.CheckInterval)
+                       case <-context.Background().Done():
+                               return
+                       }
+               }
+       }()
        return ctrl.NewControllerManagedBy(mgr).
                For(&batchv1alpha1.CNFService{}).
-               Watches(
-                       &source.Kind{Type: &appsv1.Deployment{}},
-                       &handler.EnqueueRequestsFromMapFunc{
-                               ToRequests: handler.ToRequestsFunc(GetToRequestsFunc(r, &batchv1alpha1.CNFServiceList{})),
-                       },
-                       Filter).
-               //Watches(
-               //      &source.Kind{Type: &corev1.Service{}},
-               //      &handler.EnqueueRequestsFromMapFunc{
-               //              ToRequests: handler.ToRequestsFunc(GetServiceToRequestsFunc(r)),
-               //      },
-               //      IPFilter).
                Complete(r)
 }
diff --git a/platform/crd-ctrlr/src/controllers/networkfirewallrule_controller.go b/platform/crd-ctrlr/src/controllers/networkfirewallrule_controller.go
new file mode 100644 (file)
index 0000000..49e2ac7
--- /dev/null
@@ -0,0 +1,116 @@
+// SPDX-License-Identifier: Apache-2.0\r
+// Copyright (c) 2021 Intel Corporation\r
+package controllers\r
+\r
+import (\r
+       "context"\r
+       "reflect"\r
+\r
+       "github.com/go-logr/logr"\r
+       appsv1 "k8s.io/api/apps/v1"\r
+       "k8s.io/apimachinery/pkg/runtime"\r
+       ctrl "sigs.k8s.io/controller-runtime"\r
+       "sigs.k8s.io/controller-runtime/pkg/builder"\r
+       "sigs.k8s.io/controller-runtime/pkg/client"\r
+       "sigs.k8s.io/controller-runtime/pkg/handler"\r
+       "sigs.k8s.io/controller-runtime/pkg/predicate"\r
+       "sigs.k8s.io/controller-runtime/pkg/source"\r
+\r
+       batchv1alpha1 "sdewan.akraino.org/sdewan/api/v1alpha1"\r
+       "sdewan.akraino.org/sdewan/openwrt"\r
+)\r
+\r
+var networkFirewallRuleHandler = new(NetworkFirewallRuleHandler)\r
+\r
+type NetworkFirewallRuleHandler struct {\r
+}\r
+\r
+func (m *NetworkFirewallRuleHandler) GetType() string {\r
+       return "NetworkFirewallRule"\r
+}\r
+\r
+func (m *NetworkFirewallRuleHandler) GetName(instance runtime.Object) string {\r
+       rule := instance.(*batchv1alpha1.NetworkFirewallRule)\r
+       return rule.Name\r
+}\r
+\r
+func (m *NetworkFirewallRuleHandler) GetFinalizer() string {\r
+       return "networkfirewallrule.finalizers.sdewan.akraino.org"\r
+}\r
+\r
+func (m *NetworkFirewallRuleHandler) GetInstance(r client.Client, ctx context.Context, req ctrl.Request) (runtime.Object, error) {\r
+       instance := &batchv1alpha1.NetworkFirewallRule{}\r
+       err := r.Get(ctx, req.NamespacedName, instance)\r
+       return instance, err\r
+}\r
+\r
+func (m *NetworkFirewallRuleHandler) Convert(instance runtime.Object, deployment appsv1.Deployment) (openwrt.IOpenWrtObject, error) {\r
+       firewallrule := instance.(*batchv1alpha1.NetworkFirewallRule)\r
+       firewallrule.Spec.Name = firewallrule.ObjectMeta.Name\r
+       firewallruleObject := openwrt.SdewanNetworkFirewallRule(firewallrule.Spec)\r
+       return &firewallruleObject, nil\r
+}\r
+\r
+func (m *NetworkFirewallRuleHandler) IsEqual(instance1 openwrt.IOpenWrtObject, instance2 openwrt.IOpenWrtObject) bool {\r
+       rule1 := instance1.(*openwrt.SdewanNetworkFirewallRule)\r
+       rule2 := instance2.(*openwrt.SdewanNetworkFirewallRule)\r
+       return reflect.DeepEqual(*rule1, *rule2)\r
+}\r
+\r
+func (m *NetworkFirewallRuleHandler) GetObject(clientInfo *openwrt.OpenwrtClientInfo, name string) (openwrt.IOpenWrtObject, error) {\r
+       openwrtClient := openwrt.GetOpenwrtClient(*clientInfo)\r
+       firewall := openwrt.NetworkFirewallClient{OpenwrtClient: openwrtClient}\r
+       ret, err := firewall.GetRule(name)\r
+       return ret, err\r
+}\r
+\r
+func (m *NetworkFirewallRuleHandler) CreateObject(clientInfo *openwrt.OpenwrtClientInfo, instance openwrt.IOpenWrtObject) (openwrt.IOpenWrtObject, error) {\r
+       openwrtClient := openwrt.GetOpenwrtClient(*clientInfo)\r
+       firewall := openwrt.NetworkFirewallClient{OpenwrtClient: openwrtClient}\r
+       rule := instance.(*openwrt.SdewanNetworkFirewallRule)\r
+       return firewall.CreateRule(*rule)\r
+}\r
+\r
+func (m *NetworkFirewallRuleHandler) UpdateObject(clientInfo *openwrt.OpenwrtClientInfo, instance openwrt.IOpenWrtObject) (openwrt.IOpenWrtObject, error) {\r
+       openwrtClient := openwrt.GetOpenwrtClient(*clientInfo)\r
+       firewall := openwrt.NetworkFirewallClient{OpenwrtClient: openwrtClient}\r
+       rule := instance.(*openwrt.SdewanNetworkFirewallRule)\r
+       return firewall.UpdateRule(*rule)\r
+}\r
+\r
+func (m *NetworkFirewallRuleHandler) DeleteObject(clientInfo *openwrt.OpenwrtClientInfo, name string) error {\r
+       openwrtClient := openwrt.GetOpenwrtClient(*clientInfo)\r
+       firewall := openwrt.NetworkFirewallClient{OpenwrtClient: openwrtClient}\r
+       return firewall.DeleteRule(name)\r
+}\r
+\r
+func (m *NetworkFirewallRuleHandler) Restart(clientInfo *openwrt.OpenwrtClientInfo) (bool, error) {\r
+       return true, nil\r
+}\r
+\r
+// NetworkFirewallRuleReconciler reconciles a NetworkFirewallRule object\r
+type NetworkFirewallRuleReconciler struct {\r
+       client.Client\r
+       Log    logr.Logger\r
+       Scheme *runtime.Scheme\r
+}\r
+\r
+// +kubebuilder:rbac:groups=batch.sdewan.akraino.org,resources=networkfirewallrules,verbs=get;list;watch;create;update;patch;delete\r
+// +kubebuilder:rbac:groups=batch.sdewan.akraino.org,resources=networkfirewallrules/status,verbs=get;update;patch\r
+\r
+func (r *NetworkFirewallRuleReconciler) Reconcile(req ctrl.Request) (ctrl.Result, error) {\r
+       return ProcessReconcile(r, r.Log, req, networkFirewallRuleHandler)\r
+}\r
+\r
+func (r *NetworkFirewallRuleReconciler) SetupWithManager(mgr ctrl.Manager) error {\r
+       ps := builder.WithPredicates(predicate.GenerationChangedPredicate{})\r
+       return ctrl.NewControllerManagedBy(mgr).\r
+               For(&batchv1alpha1.NetworkFirewallRule{}, ps).\r
+               Watches(\r
+                       &source.Kind{Type: &appsv1.Deployment{}},\r
+                       &handler.EnqueueRequestsFromMapFunc{\r
+                               ToRequests: handler.ToRequestsFunc(GetToRequestsFunc(r, &batchv1alpha1.NetworkFirewallRuleList{})),\r
+                       },\r
+                       Filter).\r
+               Complete(r)\r
+}\r
index f59e88d..02ebce6 100644 (file)
@@ -134,6 +134,14 @@ func main() {
                setupLog.Error(err, "unable to create controller", "controller", "CNFNAT")
                os.Exit(1)
        }
+       if err = (&controllers.NetworkFirewallRuleReconciler{
+               Client: mgr.GetClient(),
+               Log:    ctrl.Log.WithName("controllers").WithName("NetworkFirewallRule"),
+               Scheme: mgr.GetScheme(),
+       }).SetupWithManager(mgr); err != nil {
+               setupLog.Error(err, "unable to create controller", "controller", "NetworkFirewallRule")
+               os.Exit(1)
+       }
        if err = (&controllers.FirewallZoneReconciler{
                Client: mgr.GetClient(),
                Log:    ctrl.Log.WithName("controllers").WithName("FirewallZone"),
@@ -209,9 +217,10 @@ func main() {
                os.Exit(1)
        }
        if err = (&controllers.CNFServiceReconciler{
-               Client: mgr.GetClient(),
-               Log:    ctrl.Log.WithName("controllers").WithName("CNFService"),
-               Scheme: mgr.GetScheme(),
+               Client:        mgr.GetClient(),
+               Log:           ctrl.Log.WithName("controllers").WithName("CNFService"),
+               CheckInterval: time.Duration(checkInterval) * time.Second,
+               Scheme:        mgr.GetScheme(),
        }).SetupWithManager(mgr); err != nil {
                setupLog.Error(err, "unable to create controller", "controller", "CNFService")
                os.Exit(1)
@@ -249,6 +258,15 @@ func main() {
                setupLog.Error(err, "unable to create controller", "controller", "CNFLocalService")
                os.Exit(1)
        }
+       if err = (&controllers.CNFHubSiteReconciler{
+               Client:        mgr.GetClient(),
+               Log:           ctrl.Log.WithName("controllers").WithName("CNFHubSite"),
+               CheckInterval: time.Duration(checkInterval) * time.Second,
+               Scheme:        mgr.GetScheme(),
+       }).SetupWithManager(mgr); err != nil {
+               setupLog.Error(err, "unable to create controller", "controller", "CNFHubSite")
+               os.Exit(1)
+       }
        // +kubebuilder:scaffold:builder
 
        setupLog.Info("start CNFStatusController to query CNF status periodicly")
diff --git a/platform/crd-ctrlr/src/openwrt/networkfirewall.go b/platform/crd-ctrlr/src/openwrt/networkfirewall.go
new file mode 100644 (file)
index 0000000..56a3dcc
--- /dev/null
@@ -0,0 +1,129 @@
+// SPDX-License-Identifier: Apache-2.0\r
+// Copyright (c) 2021 Intel Corporation\r
+\r
+package openwrt\r
+\r
+import (\r
+       "encoding/json"\r
+)\r
+\r
+const (\r
+       networkfirewallBaseURL = "sdewan/networkfirewall/v1/"\r
+)\r
+\r
+type NetworkFirewallClient struct {\r
+       OpenwrtClient *openwrtClient\r
+}\r
+\r
+// NetworkFirewall Rule\r
+type SdewanNetworkFirewallRule struct {\r
+       Name     string   `json:"name"`\r
+       Src      string   `json:"src"`\r
+       SrcIp    string   `json:"src_ip"`\r
+       SrcMac   string   `json:"src_mac"`\r
+       SrcPort  string   `json:"src_port"`\r
+       Proto    string   `json:"proto"`\r
+       IcmpType []string `json:"icmp_type"`\r
+       Dest     string   `json:"dest"`\r
+       DestIp   string   `json:"dest_ip"`\r
+       DestPort string   `json:"dest_port"`\r
+       Mark     string   `json:"mark"`\r
+       Target   string   `json:"target"`\r
+       SetMark  string   `json:"set_mark"`\r
+       SetXmark string   `json:"set_xmark"`\r
+       Family   string   `json:"family"`\r
+       Extra    string   `json:"extra"`\r
+}\r
+\r
+func (o *SdewanNetworkFirewallRule) GetName() string {\r
+       return o.Name\r
+}\r
+\r
+type SdewanNetworkFirewallRules struct {\r
+       Rules []SdewanNetworkFirewallRule `json:"rules"`\r
+}\r
+\r
+// get rules\r
+func (f *NetworkFirewallClient) GetRules() (*SdewanNetworkFirewallRules, error) {\r
+       var response string\r
+       var err error\r
+       response, err = f.OpenwrtClient.Get(networkfirewallBaseURL + "rules")\r
+       if err != nil {\r
+               return nil, err\r
+       }\r
+\r
+       var sdewanNetworkFirewallRules SdewanNetworkFirewallRules\r
+       err = json.Unmarshal([]byte(response), &sdewanNetworkFirewallRules)\r
+       if err != nil {\r
+               return nil, err\r
+       }\r
+\r
+       return &sdewanNetworkFirewallRules, nil\r
+}\r
+\r
+// get rule\r
+func (m *NetworkFirewallClient) GetRule(rule string) (*SdewanNetworkFirewallRule, error) {\r
+       var response string\r
+       var err error\r
+       response, err = m.OpenwrtClient.Get(networkfirewallBaseURL + "rules/" + rule)\r
+       if err != nil {\r
+               return nil, err\r
+       }\r
+\r
+       var sdewanNetworkFirewallRule SdewanNetworkFirewallRule\r
+       err = json.Unmarshal([]byte(response), &sdewanNetworkFirewallRule)\r
+       if err != nil {\r
+               return nil, err\r
+       }\r
+\r
+       return &sdewanNetworkFirewallRule, nil\r
+}\r
+\r
+// create rule\r
+func (m *NetworkFirewallClient) CreateRule(rule SdewanNetworkFirewallRule) (*SdewanNetworkFirewallRule, error) {\r
+       var response string\r
+       var err error\r
+       rule_obj, _ := json.Marshal(rule)\r
+       response, err = m.OpenwrtClient.Post(networkfirewallBaseURL+"rules", string(rule_obj))\r
+       if err != nil {\r
+               return nil, err\r
+       }\r
+\r
+       var sdewanNetworkFirewallRule SdewanNetworkFirewallRule\r
+       err = json.Unmarshal([]byte(response), &sdewanNetworkFirewallRule)\r
+       if err != nil {\r
+               return nil, err\r
+       }\r
+\r
+       return &sdewanNetworkFirewallRule, nil\r
+}\r
+\r
+// delete rule\r
+func (m *NetworkFirewallClient) DeleteRule(rule_name string) error {\r
+       _, err := m.OpenwrtClient.Delete(networkfirewallBaseURL + "rules/" + rule_name)\r
+       if err != nil {\r
+               return err\r
+       }\r
+\r
+       return nil\r
+}\r
+\r
+// update rule\r
+func (m *NetworkFirewallClient) UpdateRule(rule SdewanNetworkFirewallRule) (*SdewanNetworkFirewallRule, error) {\r
+       var response string\r
+       var err error\r
+       rule_obj, _ := json.Marshal(rule)\r
+       rule_name := rule.Name\r
+       response, err = m.OpenwrtClient.Put(networkfirewallBaseURL+"rules/"+rule_name, string(rule_obj))\r
+       if err != nil {\r
+               return nil, err\r
+       }\r
+\r
+       var sdewanNetworkFirewallRule SdewanNetworkFirewallRule\r
+       err = json.Unmarshal([]byte(response), &sdewanNetworkFirewallRule)\r
+       if err != nil {\r
+               return nil, err\r
+       }\r
+\r
+       return &sdewanNetworkFirewallRule, nil\r
+}
\ No newline at end of file
index f83e5bf..9127e64 100644 (file)
@@ -1,6 +1,188 @@
 # SPDX-License-Identifier: Apache-2.0
 # Copyright (c) 2021 Intel Corporation
 
+---
+apiVersion: apiextensions.k8s.io/v1
+kind: CustomResourceDefinition
+metadata:
+  annotations:
+    controller-gen.kubebuilder.io/version: v0.7.0
+  creationTimestamp: null
+  name: cnfhubsites.batch.sdewan.akraino.org
+spec:
+  group: batch.sdewan.akraino.org
+  names:
+    kind: CNFHubSite
+    listKind: CNFHubSiteList
+    plural: cnfhubsites
+    singular: cnfhubsite
+  scope: Namespaced
+  versions:
+  - name: v1alpha1
+    schema:
+      openAPIV3Schema:
+        description: CNFHubSite is the Schema for the cnfhubsites API
+        properties:
+          apiVersion:
+            description: 'APIVersion defines the versioned schema of this representation
+              of an object. Servers should convert recognized schemas to the latest
+              internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources'
+            type: string
+          kind:
+            description: 'Kind is a string value representing the REST resource this
+              object represents. Servers may infer this from the endpoint the client
+              submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds'
+            type: string
+          metadata:
+            type: object
+          spec:
+            description: CNFHubSiteSpec defines the desired state of CNFHubSite
+            properties:
+              devicepip:
+                type: string
+              hubip:
+                type: string
+              site:
+                type: string
+              subnet:
+                type: string
+              type:
+                type: string
+            type: object
+          status:
+            description: CNFHubSiteStatus defines the observed state of CNFHubSiteStatus
+            properties:
+              devicepip:
+                type: string
+              hubip:
+                type: string
+              message:
+                type: string
+              remoteips:
+                items:
+                  type: string
+                type: array
+              subnet:
+                type: string
+              type:
+                description: 'INSERT ADDITIONAL STATUS FIELD - define observed state
+                  of cluster Important: Run "make" to regenerate code after modifying
+                  this file'
+                type: string
+            type: object
+        type: object
+    served: true
+    storage: true
+    subresources:
+      status: {}
+status:
+  acceptedNames:
+    kind: ""
+    plural: ""
+  conditions: []
+  storedVersions: []
+---
+apiVersion: apiextensions.k8s.io/v1
+kind: CustomResourceDefinition
+metadata:
+  annotations:
+    controller-gen.kubebuilder.io/version: v0.7.0
+  creationTimestamp: null
+  name: networkfirewallrules.batch.sdewan.akraino.org
+spec:
+  group: batch.sdewan.akraino.org
+  names:
+    kind: NetworkFirewallRule
+    listKind: NetworkFirewallRuleList
+    plural: networkfirewallrules
+    singular: networkfirewallrule
+  scope: Namespaced
+  versions:
+  - name: v1alpha1
+    schema:
+      openAPIV3Schema:
+        description: NetworkFirewallRule is the Schema for the networkfirewallrules
+          API
+        properties:
+          apiVersion:
+            description: 'APIVersion defines the versioned schema of this representation
+              of an object. Servers should convert recognized schemas to the latest
+              internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources'
+            type: string
+          kind:
+            description: 'Kind is a string value representing the REST resource this
+              object represents. Servers may infer this from the endpoint the client
+              submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds'
+            type: string
+          metadata:
+            type: object
+          spec:
+            description: NetworkFirewallRuleSpec defines the desired state of NetworkFirewallRule
+            properties:
+              dest:
+                type: string
+              dest_ip:
+                type: string
+              dest_port:
+                type: string
+              extra:
+                type: string
+              family:
+                type: string
+              icmp_type:
+                items:
+                  type: string
+                type: array
+              mark:
+                type: string
+              name:
+                description: Foo is an example field of NetworkFirewallRule. Edit
+                  NetworkFirewallRule_types.go to remove/update
+                type: string
+              proto:
+                type: string
+              set_mark:
+                type: string
+              set_xmark:
+                type: string
+              src:
+                type: string
+              src_ip:
+                type: string
+              src_mac:
+                type: string
+              src_port:
+                type: string
+              target:
+                type: string
+            type: object
+          status:
+            description: status subsource used for Sdewan rule CRDs
+            properties:
+              appliedGeneration:
+                format: int64
+                type: integer
+              appliedTime:
+                format: date-time
+                type: string
+              message:
+                type: string
+              state:
+                type: string
+            required:
+            - state
+            type: object
+        type: object
+    served: true
+    storage: true
+    subresources:
+      status: {}
+status:
+  acceptedNames:
+    kind: ""
+    plural: ""
+  conditions: []
+  storedVersions: []
 ---
 apiVersion: apiextensions.k8s.io/v1
 kind: CustomResourceDefinition
index 4b19ced..d82a14d 100644 (file)
@@ -78,6 +78,46 @@ rules:
   - get
   - list
   - watch
+- apiGroups:
+  - batch.sdewan.akraino.org
+  resources:
+  - cnfhubsites
+  verbs:
+  - create
+  - delete
+  - get
+  - list
+  - patch
+  - update
+  - watch
+- apiGroups:
+  - batch.sdewan.akraino.org
+  resources:
+  - cnfhubsites/status
+  verbs:
+  - get
+  - patch
+  - update
+- apiGroups:
+  - batch.sdewan.akraino.org
+  resources:
+  - networkfirewallrules
+  verbs:
+  - create
+  - delete
+  - get
+  - list
+  - patch
+  - update
+  - watch
+- apiGroups:
+  - batch.sdewan.akraino.org
+  resources:
+  - networkfirewallrules/status
+  verbs:
+  - get
+  - patch
+  - update
 - apiGroups:
   - batch.sdewan.akraino.org
   resources:
index 51b5471..ffc7106 100644 (file)
@@ -45,6 +45,8 @@ webhooks:
     - ipsecproposals
     - ipsechosts
     - ipsecsites
+    - networkfirewallrules
+    - cnfhubsites
   sideEffects: None
 - admissionReviewVersions:
   - v1
@@ -64,7 +66,6 @@ webhooks:
     operations:
     - UPDATE
     resources:
-    - deployments
     - mwan3policies
     - mwan3rules
     - firewallzones
@@ -82,4 +83,6 @@ webhooks:
     - ipsecproposals
     - ipsechosts
     - ipsecsites
+    - cnfhubsites
+    - networkfirewallrules
   sideEffects: None