From 75c16b7254bad3125a64fc4a5ebb370e38948c40 Mon Sep 17 00:00:00 2001 From: Elis Lulja Date: Mon, 14 Jun 2021 15:18:15 +0200 Subject: [PATCH 1/6] Add cloud configuration The `cloudConfiguration` field is added among operator's settings and will contain data about the cloud provider. For now, it contains the name of the network and subnetwork. Signed-off-by: Elis Lulja --- deploy/settings/settings.yaml | 3 + internal/types/settings.go | 12 +++- internal/utils/utils.go | 16 +++++ internal/utils/utils_test.go | 114 +++++++++++++++++++++++++++++++--- 4 files changed, 134 insertions(+), 11 deletions(-) diff --git a/deploy/settings/settings.yaml b/deploy/settings/settings.yaml index f3f9d13..21b40fd 100644 --- a/deploy/settings/settings.yaml +++ b/deploy/settings/settings.yaml @@ -14,4 +14,7 @@ serviceRegistry: gcpServiceDirectory: defaultRegion: projectID: +cloudMetadata: + network: auto + subNetwork: auto diff --git a/internal/types/settings.go b/internal/types/settings.go index 1818588..4febfed 100644 --- a/internal/types/settings.go +++ b/internal/types/settings.go @@ -50,7 +50,8 @@ type Settings struct { // DEPRECATED: include this under serviceRegistry instead of here. // TODO: remove this on v0.6.0 - Gcloud *GcloudSettings `yaml:"gcloud"` + Gcloud *GcloudSettings `yaml:"gcloud"` + CloudMetadata *CloudMetadata `yaml:"cloudMetadata"` } // GcloudSettings holds gcloud settings @@ -142,3 +143,12 @@ type EtcdEndpoint struct { Host string `yaml:"host"` Port *int `yaml:"port"` } + +// CloudMetadata contains data and configuration about the cloud provider +// that is hosting the cluster, if any. +type CloudMetadata struct { + // Network name + Network *string `yaml:"network"` + // SubNetwork name + SubNetwork *string `yaml:"subNetwork"` +} diff --git a/internal/utils/utils.go b/internal/utils/utils.go index df3ca72..9b3a6fb 100644 --- a/internal/utils/utils.go +++ b/internal/utils/utils.go @@ -87,6 +87,22 @@ func ParseAndValidateSettings(settings *types.Settings) (*types.Settings, error) } finalSettings := &types.Settings{} + if settings.CloudMetadata != nil { + clCfg := settings.CloudMetadata + finalCfg := &types.CloudMetadata{} + + if clCfg.Network != nil && *clCfg.Network != "" { + finalCfg.Network = clCfg.Network + } + if clCfg.SubNetwork != nil && *clCfg.SubNetwork != "" { + finalCfg.SubNetwork = clCfg.SubNetwork + } + + if finalCfg.Network != nil || finalCfg.SubNetwork != nil { + finalSettings.CloudMetadata = finalCfg + } + } + if settings.Namespace.ListPolicy != types.AllowList && settings.Namespace.ListPolicy != types.BlockList { // Probably we could revert to using a default value here, but I think // it's better not to confuse the user with unexpected behaviors and diff --git a/internal/utils/utils_test.go b/internal/utils/utils_test.go index 602fd89..b1dff6c 100644 --- a/internal/utils/utils_test.go +++ b/internal/utils/utils_test.go @@ -257,7 +257,7 @@ func TestParseAndValidateSettings(t *testing.T) { Namespace: types.NamespaceSettings{ ListPolicy: types.AllowList, }, - Service: *&types.ServiceSettings{ + Service: types.ServiceSettings{ Annotations: []string{"one", "two"}, }, ServiceRegistrySettings: &types.ServiceRegistrySettings{ @@ -273,7 +273,7 @@ func TestParseAndValidateSettings(t *testing.T) { Namespace: types.NamespaceSettings{ ListPolicy: types.AllowList, }, - Service: *&types.ServiceSettings{ + Service: types.ServiceSettings{ Annotations: []string{"one", "two"}, }, ServiceRegistrySettings: &types.ServiceRegistrySettings{ @@ -297,7 +297,7 @@ func TestParseAndValidateSettings(t *testing.T) { Namespace: types.NamespaceSettings{ ListPolicy: types.AllowList, }, - Service: *&types.ServiceSettings{ + Service: types.ServiceSettings{ Annotations: []string{"one", "two"}, }, ServiceRegistrySettings: &types.ServiceRegistrySettings{}, @@ -306,7 +306,7 @@ func TestParseAndValidateSettings(t *testing.T) { Namespace: types.NamespaceSettings{ ListPolicy: types.AllowList, }, - Service: *&types.ServiceSettings{ + Service: types.ServiceSettings{ Annotations: []string{"one", "two"}, }, ServiceRegistrySettings: &types.ServiceRegistrySettings{ @@ -329,7 +329,7 @@ func TestParseAndValidateSettings(t *testing.T) { Namespace: types.NamespaceSettings{ ListPolicy: types.AllowList, }, - Service: *&types.ServiceSettings{ + Service: types.ServiceSettings{ Annotations: []string{"one", "two"}, }, ServiceRegistrySettings: &types.ServiceRegistrySettings{ @@ -343,7 +343,7 @@ func TestParseAndValidateSettings(t *testing.T) { Namespace: types.NamespaceSettings{ ListPolicy: types.AllowList, }, - Service: *&types.ServiceSettings{ + Service: types.ServiceSettings{ Annotations: []string{"one", "two"}, }, ServiceRegistrySettings: &types.ServiceRegistrySettings{ @@ -360,7 +360,7 @@ func TestParseAndValidateSettings(t *testing.T) { Namespace: types.NamespaceSettings{ ListPolicy: types.AllowList, }, - Service: *&types.ServiceSettings{ + Service: types.ServiceSettings{ Annotations: []string{"one", "two"}, }, ServiceRegistrySettings: &types.ServiceRegistrySettings{ @@ -377,7 +377,7 @@ func TestParseAndValidateSettings(t *testing.T) { Namespace: types.NamespaceSettings{ ListPolicy: types.AllowList, }, - Service: *&types.ServiceSettings{ + Service: types.ServiceSettings{ Annotations: []string{"one", "two"}, }, ServiceRegistrySettings: &types.ServiceRegistrySettings{ @@ -400,7 +400,7 @@ func TestParseAndValidateSettings(t *testing.T) { Namespace: types.NamespaceSettings{ ListPolicy: types.AllowList, }, - Service: *&types.ServiceSettings{ + Service: types.ServiceSettings{ Annotations: []string{"one", "two"}, }, ServiceRegistrySettings: &types.ServiceRegistrySettings{ @@ -414,7 +414,7 @@ func TestParseAndValidateSettings(t *testing.T) { Namespace: types.NamespaceSettings{ ListPolicy: types.AllowList, }, - Service: *&types.ServiceSettings{ + Service: types.ServiceSettings{ Annotations: []string{"one", "two"}, }, ServiceRegistrySettings: &types.ServiceRegistrySettings{ @@ -425,6 +425,100 @@ func TestParseAndValidateSettings(t *testing.T) { }, }, }, + { + id: "successful-with-cloud-cfg", + arg: &types.Settings{ + Gcloud: &types.GcloudSettings{ + ServiceDirectory: &types.DeprecatedServiceDirectorySettings{ + ProjectName: "old", + DefaultRegion: "old", + }, + }, + Namespace: types.NamespaceSettings{ + ListPolicy: types.AllowList, + }, + Service: types.ServiceSettings{ + Annotations: []string{"one", "two"}, + }, + ServiceRegistrySettings: &types.ServiceRegistrySettings{ + ServiceDirectorySettings: &types.ServiceDirectorySettings{ + ProjectID: "new", + DefaultRegion: "new", + }, + }, + CloudMetadata: &types.CloudMetadata{ + SubNetwork: func() *string { + test := "subnetwork" + return &test + }(), + Network: func() *string { + test := "network" + return &test + }(), + }, + }, + expRes: &types.Settings{ + Namespace: types.NamespaceSettings{ + ListPolicy: types.AllowList, + }, + Service: types.ServiceSettings{ + Annotations: []string{"one", "two"}, + }, + ServiceRegistrySettings: &types.ServiceRegistrySettings{ + ServiceDirectorySettings: &types.ServiceDirectorySettings{ + ProjectID: "new", + DefaultRegion: "new", + }, + }, + CloudMetadata: func() *types.CloudMetadata { + nname := "network" + snname := "subnetwork" + return &types.CloudMetadata{ + SubNetwork: &snname, + Network: &nname, + } + }(), + }, + }, + { + id: "successful-with-empty-cloud-cfg", + arg: &types.Settings{ + Gcloud: &types.GcloudSettings{ + ServiceDirectory: &types.DeprecatedServiceDirectorySettings{ + ProjectName: "old", + DefaultRegion: "old", + }, + }, + Namespace: types.NamespaceSettings{ + ListPolicy: types.AllowList, + }, + Service: types.ServiceSettings{ + Annotations: []string{"one", "two"}, + }, + ServiceRegistrySettings: &types.ServiceRegistrySettings{ + ServiceDirectorySettings: &types.ServiceDirectorySettings{ + ProjectID: "new", + DefaultRegion: "new", + }, + }, + CloudMetadata: &types.CloudMetadata{}, + }, + expRes: &types.Settings{ + Namespace: types.NamespaceSettings{ + ListPolicy: types.AllowList, + }, + Service: types.ServiceSettings{ + Annotations: []string{"one", "two"}, + }, + ServiceRegistrySettings: &types.ServiceRegistrySettings{ + ServiceDirectorySettings: &types.ServiceDirectorySettings{ + ProjectID: "new", + DefaultRegion: "new", + }, + }, + CloudMetadata: nil, + }, + }, } for _, currCase := range cases { From 60728c1946c4ee1e6292ad03871e8d2e29fcdd39 Mon Sep 17 00:00:00 2001 From: Elis Lulja Date: Tue, 15 Jun 2021 08:59:00 +0200 Subject: [PATCH 2/6] Detect cluster manager This commit introduces the ability to detect if the operator is running inside a managed cluster. For now, it is able to detect whether we are in EKS or GKE. Signed-off-by: Elis Lulja --- go.mod | 2 + go.sum | 14 ++++ pkg/cluster/doc.go | 21 ++++++ pkg/cluster/network.go | 163 +++++++++++++++++++++++++++++++++++++++++ 4 files changed, 200 insertions(+) create mode 100644 pkg/cluster/doc.go create mode 100644 pkg/cluster/network.go diff --git a/go.mod b/go.mod index 6589723..3e0d174 100644 --- a/go.mod +++ b/go.mod @@ -4,6 +4,7 @@ go 1.13 require ( cloud.google.com/go v0.72.0 + github.com/aws/aws-sdk-go v1.38.60 github.com/go-logr/logr v0.1.0 github.com/googleapis/gax-go v1.0.3 github.com/grpc-ecosystem/grpc-gateway v1.14.6 // indirect @@ -14,6 +15,7 @@ require ( go.etcd.io/etcd v0.0.0-20191023171146-3cf2f69b5738 go.uber.org/zap v1.10.0 golang.org/x/oauth2 v0.0.0-20201208152858-08078c50e5b5 // indirect + golang.org/x/tools v0.1.0 // indirect google.golang.org/api v0.36.0 google.golang.org/genproto v0.0.0-20201210142538-e3217bee35cc google.golang.org/grpc v1.34.0 diff --git a/go.sum b/go.sum index c2fbf3b..cf5515c 100644 --- a/go.sum +++ b/go.sum @@ -63,6 +63,8 @@ github.com/armon/go-metrics v0.0.0-20180917152333-f0300d1749da/go.mod h1:Q73ZrmV github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310/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/aws/aws-sdk-go v1.38.60 h1:MgyEsX0IMwivwth1VwEnesBpH0vxbjp5a0w1lurMOXY= +github.com/aws/aws-sdk-go v1.38.60/go.mod h1:hcU610XS61/+aQV88ixoOzUoG7v3b31pl2zKMmprdro= github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= github.com/beorn7/perks v1.0.0 h1:HWo1m869IqiPhD389kmkxeTalrjNbbJTC8LXupb+sl0= github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8= @@ -313,6 +315,10 @@ github.com/imdario/mergo v0.3.5/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJ 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/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8= +github.com/jmespath/go-jmespath v0.4.0 h1:BEgLn5cpjn8UN1mAw4NjwDrS35OdebyEtFe+9YPoQUg= +github.com/jmespath/go-jmespath v0.4.0/go.mod h1:T8mJZnbsbmF+m6zOOFylbeCJqk5+pHWvzYPziyZiYoo= +github.com/jmespath/go-jmespath/internal/testify v1.5.1 h1:shLQSRRSCCPj3f2gpwzGwWFoC7ycTf1rcQZHOlsJ6N8= +github.com/jmespath/go-jmespath/internal/testify v1.5.1/go.mod h1:L3OGu8Wl2/fWfCI6z80xFu9LTZmf1ZRjMHUOPmWr69U= 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/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= @@ -402,6 +408,8 @@ github.com/peterbourgon/diskv v2.0.1+incompatible/go.mod h1:uqqh8zWWbv1HBMNONnaR github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.8.1 h1:iURUrRGxPUNPdy5/HRSm+Yj6okJ6UtLINN0Q9M4+h3I= 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 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= @@ -605,6 +613,8 @@ golang.org/x/net v0.0.0-20201006153459-a7d1128ccaa0/go.mod h1:sp8m0HH+o8qH0wwXwY golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= golang.org/x/net v0.0.0-20201031054903-ff519b6c9102 h1:42cLlJJdEh+ySyeUUbEQ5bsTiq8voBeTuweGVkY6Puw= golang.org/x/net v0.0.0-20201031054903-ff519b6c9102/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= +golang.org/x/net v0.0.0-20201110031124-69a78807bb2b h1:uwuIcX0g4Yl1NC5XAz37xsr2lTtcqevgzYNVt49waME= +golang.org/x/net v0.0.0-20201110031124-69a78807bb2b/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/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-20190604053449-0f29369cfe45 h1:SVwTIAaPC2U/AvvLNZ2a7OVsmBpC8L5BlwK1whH3hm0= @@ -676,6 +686,8 @@ golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f h1:+Nyd8tzPX9R7BWHguqsrbFdRx golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201201145000-ef89a241ccb3 h1:kzM6+9dur93BcC2kVlYl34cHU+TYZLanmpSJHVMmL64= golang.org/x/sys v0.0.0-20201201145000-ef89a241ccb3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210119212857-b64e53b001e4 h1:myAQVi0cGEoqQVR5POX+8RR2mrocKqNN1hmeMqhX27k= +golang.org/x/sys v0.0.0-20210119212857-b64e53b001e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/text v0.0.0-20160726164857-2910a502d2bf/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= 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= @@ -745,6 +757,8 @@ golang.org/x/tools v0.0.0-20200904185747-39188db58858/go.mod h1:Cj7w3i3Rnn0Xh82u golang.org/x/tools v0.0.0-20201110124207-079ba7bd75cd/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.0.0-20201201161351-ac6f37ff4c2a h1:+77BOOi9CMFjpy3D2P/OnfSSmC/Hx/fGAQJUAQaM2gc= golang.org/x/tools v0.0.0-20201201161351-ac6f37ff4c2a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= +golang.org/x/tools v0.1.0 h1:po9/4sTYwZU9lPhi1tOrb4hCv3qrhiQ77LZfGa2OjwY= +golang.org/x/tools v0.1.0/go.mod h1:xkSsbof2nBLbhDlRMhhhyNLN/zl3eTqcnHD5viDpcZ0= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7 h1:9zdDQZ7Thm29KFXgAX/+yaf3eVbP7djjWp/dXAppNCc= 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= diff --git a/pkg/cluster/doc.go b/pkg/cluster/doc.go new file mode 100644 index 0000000..3903a68 --- /dev/null +++ b/pkg/cluster/doc.go @@ -0,0 +1,21 @@ +// Copyright © 2021 Cisco +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +// All rights reserved. + +// Package cluster contains code that gets information about the cluster where +// we are running and if it is a managed cluster, e.g. GKE or EKS. +// +// Code gets information like VPC, SubNetwork, Cluster Name, etc. +package cluster diff --git a/pkg/cluster/network.go b/pkg/cluster/network.go new file mode 100644 index 0000000..2785625 --- /dev/null +++ b/pkg/cluster/network.go @@ -0,0 +1,163 @@ +// Copyright © 2021 Cisco +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +// All rights reserved. + +package cluster + +import ( + "context" + "fmt" + "time" + + gcpmetadata "cloud.google.com/go/compute/metadata" + "github.com/aws/aws-sdk-go/aws" + "github.com/aws/aws-sdk-go/aws/ec2metadata" + awssess "github.com/aws/aws-sdk-go/aws/session" + "github.com/aws/aws-sdk-go/service/ec2" + gccontainer "google.golang.org/api/container/v1" + gcoption "google.golang.org/api/option" +) + +type ClusterManager string + +const ( + GKECluster ClusterManager = "GKE" + EKSCluster ClusterManager = "EKS" + UnknownCluster ClusterManager = "UNKNOWN" + + gkeClusterNameAttr string = "cluster-name" + eksInstanceIDAttr string = "instance-id" +) + +type NetworkConfiguration struct { + NetworkName string + SubNetworkName string +} + +var ( + iAmIn ClusterManager +) + +func init() { + iAmIn = WhereAmIRunning() +} + +func WhereAmIRunning() ClusterManager { + if iAmIn != "" { + return iAmIn + } + + if amIInGKE() { + return GKECluster + } + + if amIInEKS() { + return EKSCluster + } + + return UnknownCluster +} + +func amIInEKS() bool { + sess := awssess.Must(awssess.NewSession()) + + ec2m := ec2metadata.New(sess) + return ec2m.AvailableWithContext(context.Background()) +} + +func amIInGKE() bool { + return gcpmetadata.OnGCE() +} + +func GetNetworkFromGKE(ctx context.Context, opts ...gcoption.ClientOption) (*NetworkConfiguration, error) { + if iAmIn != GKECluster { + return nil, fmt.Errorf("not running in GKE or no permissions to get metadata from GKE") + } + + projectID, err := gcpmetadata.ProjectID() + if err != nil { + return nil, err + } + + zone, err := gcpmetadata.Zone() + if err != nil { + return nil, err + } + + clusterName, err := gcpmetadata.InstanceAttributeValue(gkeClusterNameAttr) + if err != nil { + return nil, err + } + + clctx, canc := context.WithTimeout(ctx, time.Minute) + defer canc() + + clientopts := opts + if len(clientopts) == 0 { + clientopts = []gcoption.ClientOption{gcoption.WithScopes(gccontainer.CloudPlatformScope)} + } + + cli, err := gccontainer.NewService(clctx, clientopts...) + if err != nil { + return nil, err + } + + cluster, err := cli.Projects.Zones.Clusters.Get(projectID, zone, clusterName).Do() + if err != nil { + return nil, err + } + + return &NetworkConfiguration{cluster.Network, cluster.Subnetwork}, nil +} + +func GetNetworkFromEKS(ctx context.Context, cfgs ...*aws.Config) (*NetworkConfiguration, error) { + if iAmIn != EKSCluster { + return nil, fmt.Errorf("not running in EKS or no permissions to get metadata from EKS") + } + + sess := awssess.Must(awssess.NewSession()) + var metcli *ec2metadata.EC2Metadata + + if len(cfgs) > 0 { + metcli = ec2metadata.New(sess) + } else { + metcli = ec2metadata.New(sess, cfgs...) + } + + instanceID, err := metcli.GetMetadataWithContext(ctx, "instance-id") + if err != nil { + return nil, err + } + + region, err := metcli.RegionWithContext(ctx) + if err != nil { + return nil, err + } + + ec2cli := ec2.New(sess, aws.NewConfig().WithRegion(region)) + out, err := ec2cli.DescribeInstancesWithContext(ctx, &ec2.DescribeInstancesInput{ + InstanceIds: aws.StringSlice([]string{instanceID}), + }) + if err != nil { + return nil, err + } + + if len(out.Reservations) == 0 || (len(out.Reservations) > 0 && len(out.Reservations[0].Instances) == 0) { + return nil, fmt.Errorf("could not find currently running instance") + } + + inst := out.Reservations[0].Instances[0] + return &NetworkConfiguration{aws.StringValue(inst.VpcId), aws.StringValue(inst.SubnetId)}, nil +} From c9609ac5cc89895034c1021f94743c701f86f2ed Mon Sep 17 00:00:00 2001 From: Elis Lulja Date: Wed, 16 Jun 2021 11:06:14 +0200 Subject: [PATCH 3/6] Update broker to have persistent metadata Persistent metadata are metadata that will always be registered to a service, regardless of what annotations they have. Signed-off-by: Elis Lulja --- .gitignore | 3 +++ main.go | 2 +- pkg/servregistry/broker.go | 33 +++++++++++++++--------- pkg/servregistry/broker_test.go | 14 +++++------ pkg/servregistry/endpoint.go | 4 +-- pkg/servregistry/endpoint_test.go | 40 +++++++++++++++--------------- pkg/servregistry/namespace.go | 8 +++--- pkg/servregistry/namespace_test.go | 38 ++++++++++++++-------------- pkg/servregistry/service.go | 8 +++--- pkg/servregistry/service_test.go | 34 ++++++++++++------------- pkg/servregistry/utils.go | 4 +-- 11 files changed, 100 insertions(+), 88 deletions(-) diff --git a/.gitignore b/.gitignore index 2d97657..9f988bc 100644 --- a/.gitignore +++ b/.gitignore @@ -24,3 +24,6 @@ bin *~ deploy/settings/*.json deploy/*_generated.yaml + +# All backup file, including bak1, bak2 and whatever +*.bak* diff --git a/main.go b/main.go index 998c6c1..1fcd437 100644 --- a/main.go +++ b/main.go @@ -158,7 +158,7 @@ func main() { runtime.Goexit() } - srBroker, err := sr.NewBroker(servreg, opKey, opVal) + srBroker, err := sr.NewBroker(servreg, sr.MetadataPair{Key: opKey, Value: opVal}) if err != nil { setupLog.Error(err, "fatal error encountered") returnCode = 6 diff --git a/pkg/servregistry/broker.go b/pkg/servregistry/broker.go index fd4fdc1..ecccf01 100644 --- a/pkg/servregistry/broker.go +++ b/pkg/servregistry/broker.go @@ -40,16 +40,25 @@ type Broker struct { Reg ServiceRegistry log logr.Logger - opKey string - opVal string - lock sync.Mutex + opMetaPair MetadataPair + persistentMeta []MetadataPair + lock sync.Mutex +} + +// MetadataPair represents a key-value pair that is/will be registered in a +// service registry. +type MetadataPair struct { + // Key of the metadata + Key string + // Value of the metadata + Value string } // NewBroker returns a new instance of service registry broker. // // An error is returned in case no service registry where to perform operations // is provided. -func NewBroker(reg ServiceRegistry, opKey, opVal string) (*Broker, error) { +func NewBroker(reg ServiceRegistry, opMetaPair MetadataPair, persMeta ...MetadataPair) (*Broker, error) { // Validation and inits l := zap.New(zap.UseDevMode(true)).WithName("ServiceRegistryBroker") @@ -57,17 +66,17 @@ func NewBroker(reg ServiceRegistry, opKey, opVal string) (*Broker, error) { return nil, ErrServRegNotProvided } - if len(opKey) == 0 { - opKey = defOpKey + if opMetaPair.Key == "" { + opMetaPair.Key = defOpKey } - if len(opVal) == 0 { - opVal = defOpVal + if opMetaPair.Value == "" { + opMetaPair.Value = defOpVal } return &Broker{ - log: l, - Reg: reg, - opKey: opKey, - opVal: opVal, + log: l, + Reg: reg, + opMetaPair: opMetaPair, + persistentMeta: persMeta, }, nil } diff --git a/pkg/servregistry/broker_test.go b/pkg/servregistry/broker_test.go index fe3ee1b..4fb2d42 100644 --- a/pkg/servregistry/broker_test.go +++ b/pkg/servregistry/broker_test.go @@ -323,18 +323,18 @@ func TestNewBroker(t *testing.T) { // prepare var f *fakeServReg assert := a.New(t) - b, err := NewBroker(nil, "", "") + b, err := NewBroker(nil, MetadataPair{}) assert.Nil(b) assert.Equal(ErrServRegNotProvided, err) - b, err = NewBroker(f, "", "") + b, err = NewBroker(f, MetadataPair{}) assert.NotNil(b) assert.NoError(err) - assert.Equal(b.opKey, defOpKey) - assert.Equal(b.opVal, defOpVal) + assert.Equal(b.opMetaPair.Key, defOpKey) + assert.Equal(b.opMetaPair.Value, defOpVal) - b, err = NewBroker(f, "test", "testing") - assert.Equal(b.opKey, "test") - assert.Equal(b.opVal, "testing") + b, err = NewBroker(f, MetadataPair{Key: "test", Value: "testing"}) + assert.Equal(b.opMetaPair.Key, "test") + assert.Equal(b.opMetaPair.Value, "testing") } diff --git a/pkg/servregistry/endpoint.go b/pkg/servregistry/endpoint.go index 43177f8..633b8a7 100644 --- a/pkg/servregistry/endpoint.go +++ b/pkg/servregistry/endpoint.go @@ -69,7 +69,7 @@ func (b *Broker) ManageServEndps(nsName, servName string, endpsData []*Endpoint) if endpsMap[endp.Name].Metadata == nil { endpsMap[endp.Name].Metadata = map[string]string{} } - endpsMap[endp.Name].Metadata[b.opKey] = b.opVal + endpsMap[endp.Name].Metadata[b.opMetaPair.Key] = b.opMetaPair.Value } endpErrs = map[string]error{} @@ -88,7 +88,7 @@ func (b *Broker) ManageServEndps(nsName, servName string, endpsData []*Endpoint) endpData, exists := endpsMap[regEndp.Name] - if owner, ownerExists := regEndp.Metadata[b.opKey]; owner != b.opVal || !ownerExists { + if owner, ownerExists := regEndp.Metadata[b.opMetaPair.Key]; owner != b.opMetaPair.Value || !ownerExists { l.V(0).Info("endpoint is not managed by the cnwan operator and is going to be ignored") endpErrs[regEndp.Name] = ErrEndpNotOwnedByOp delete(endpsMap, regEndp.Name) diff --git a/pkg/servregistry/endpoint_test.go b/pkg/servregistry/endpoint_test.go index b03d5cc..9033907 100644 --- a/pkg/servregistry/endpoint_test.go +++ b/pkg/servregistry/endpoint_test.go @@ -26,7 +26,7 @@ func TestManageServEndps(t *testing.T) { // prepare nsName, servName := "ns", "serv" var f *fakeServReg - b, _ := NewBroker(f, "", "") + b, _ := NewBroker(f, MetadataPair{}) resetFake := func() { f = newFakeStruct() @@ -73,10 +73,10 @@ func TestManageServEndps(t *testing.T) { defer resetFake() assert := a.New(tt) - oneNotOwned := &Endpoint{Name: "one", NsName: nsName, ServName: servName, Metadata: map[string]string{b.opKey: "someone-else", "key": "val"}} + oneNotOwned := &Endpoint{Name: "one", NsName: nsName, ServName: servName, Metadata: map[string]string{b.opMetaPair.Key: "someone-else", "key": "val"}} twoNotOwned := &Endpoint{Name: "two", NsName: nsName, ServName: servName, Metadata: map[string]string{"key": "val"}} - oneChange := &Endpoint{Name: "one", NsName: nsName, ServName: servName, Metadata: map[string]string{b.opKey: b.opVal, "key": "val"}} - twoChange := &Endpoint{Name: "two", NsName: nsName, ServName: servName, Metadata: map[string]string{b.opKey: b.opVal, "key": "val"}} + oneChange := &Endpoint{Name: "one", NsName: nsName, ServName: servName, Metadata: map[string]string{b.opMetaPair.Key: b.opMetaPair.Value, "key": "val"}} + twoChange := &Endpoint{Name: "two", NsName: nsName, ServName: servName, Metadata: map[string]string{b.opMetaPair.Key: b.opMetaPair.Value, "key": "val"}} f.endpList[oneNotOwned.Name] = oneNotOwned f.endpList[twoNotOwned.Name] = twoNotOwned @@ -97,8 +97,8 @@ func TestManageServEndps(t *testing.T) { assert := a.New(tt) // an error occurs while deleting one of them - oneOwned := &Endpoint{Name: "one-owned", NsName: nsName, ServName: servName, Metadata: map[string]string{b.opKey: b.opVal, "key": "val"}} - errored := &Endpoint{Name: "delete-error", NsName: nsName, ServName: servName, Metadata: map[string]string{b.opKey: b.opVal, "key": "val"}} + oneOwned := &Endpoint{Name: "one-owned", NsName: nsName, ServName: servName, Metadata: map[string]string{b.opMetaPair.Key: b.opMetaPair.Value, "key": "val"}} + errored := &Endpoint{Name: "delete-error", NsName: nsName, ServName: servName, Metadata: map[string]string{b.opMetaPair.Key: b.opMetaPair.Value, "key": "val"}} f.endpList[oneOwned.Name] = oneOwned f.endpList[errored.Name] = errored @@ -121,28 +121,28 @@ func TestManageServEndps(t *testing.T) { // an error occurs while updating one of them no := &Endpoint{Name: "no", NsName: nsName, ServName: servName, Address: "1.1.1.1", Port: 1010, - Metadata: map[string]string{b.opKey: b.opVal, "key": "val"}, + Metadata: map[string]string{b.opMetaPair.Key: b.opMetaPair.Value, "key": "val"}, } metad := &Endpoint{Name: "metad", NsName: nsName, ServName: servName, Address: "10.10.10.10", Port: 8080, - Metadata: map[string]string{b.opKey: b.opVal, "key": "val"}, + Metadata: map[string]string{b.opMetaPair.Key: b.opMetaPair.Value, "key": "val"}, } adr := &Endpoint{Name: "adr", NsName: nsName, ServName: servName, Address: "11.11.11.11", Port: 8181, - Metadata: map[string]string{b.opKey: b.opVal, "key": "val"}, + Metadata: map[string]string{b.opMetaPair.Key: b.opMetaPair.Value, "key": "val"}, } por := &Endpoint{Name: "por", NsName: nsName, ServName: servName, Address: "12.12.12.12", Port: 8282, - Metadata: map[string]string{b.opKey: b.opVal, "key": "val"}, + Metadata: map[string]string{b.opMetaPair.Key: b.opMetaPair.Value, "key": "val"}, } metadChange := &Endpoint{Name: "metad", NsName: nsName, ServName: servName, Address: "10.10.10.10", Port: 8080, - Metadata: map[string]string{b.opKey: b.opVal, "key": "val-1"}, + Metadata: map[string]string{b.opMetaPair.Key: b.opMetaPair.Value, "key": "val-1"}, } adrChange := &Endpoint{Name: "adr", NsName: nsName, ServName: servName, Address: "12.12.12.12", Port: 8181, - Metadata: map[string]string{b.opKey: b.opVal, "key": "val"}, + Metadata: map[string]string{b.opMetaPair.Key: b.opMetaPair.Value, "key": "val"}, } porChange := &Endpoint{Name: "por", NsName: nsName, ServName: servName, Address: "12.12.12.12", Port: 2828, - Metadata: map[string]string{b.opKey: b.opVal, "key": "val"}, + Metadata: map[string]string{b.opMetaPair.Key: b.opMetaPair.Value, "key": "val"}, } - errored := &Endpoint{Name: "update-error", NsName: nsName, ServName: servName, Metadata: map[string]string{b.opKey: b.opVal, "key": "val"}} - erroredChange := &Endpoint{Name: "update-error", NsName: nsName, ServName: servName, Metadata: map[string]string{b.opKey: b.opVal, "key": "val-1"}} + errored := &Endpoint{Name: "update-error", NsName: nsName, ServName: servName, Metadata: map[string]string{b.opMetaPair.Key: b.opMetaPair.Value, "key": "val"}} + erroredChange := &Endpoint{Name: "update-error", NsName: nsName, ServName: servName, Metadata: map[string]string{b.opMetaPair.Key: b.opMetaPair.Value, "key": "val-1"}} f.endpList[no.Name] = no f.endpList[metad.Name] = metad @@ -177,9 +177,9 @@ func TestManageServEndps(t *testing.T) { create := &Endpoint{Name: "create", NsName: nsName, ServName: servName, Address: "1.1.1.1", Port: 1010, Metadata: map[string]string{"key": "val"}, } - createErr := &Endpoint{Name: "create-error", Metadata: map[string]string{b.opKey: b.opVal, "key": "val"}} - exists := &Endpoint{Name: "exists", NsName: nsName, ServName: servName, Metadata: map[string]string{b.opKey: b.opVal, "key": "val"}} - del := &Endpoint{Name: "del", NsName: nsName, ServName: servName, Metadata: map[string]string{b.opKey: b.opVal, "key": "val"}} + createErr := &Endpoint{Name: "create-error", Metadata: map[string]string{b.opMetaPair.Key: b.opMetaPair.Value, "key": "val"}} + exists := &Endpoint{Name: "exists", NsName: nsName, ServName: servName, Metadata: map[string]string{b.opMetaPair.Key: b.opMetaPair.Value, "key": "val"}} + del := &Endpoint{Name: "del", NsName: nsName, ServName: servName, Metadata: map[string]string{b.opMetaPair.Key: b.opMetaPair.Value, "key": "val"}} f.endpList[exists.Name] = exists f.endpList[del.Name] = del @@ -195,10 +195,10 @@ func TestManageServEndps(t *testing.T) { assert.Contains(f.createdEndp, createNil.Name) assert.Equal(create.Name, f.endpList[create.Name].Name) assert.Equal(create.ServName, f.endpList[create.Name].ServName) - assert.Equal(map[string]string{b.opKey: b.opVal, "key": "val"}, f.endpList[create.Name].Metadata) + assert.Equal(map[string]string{b.opMetaPair.Key: b.opMetaPair.Value, "key": "val"}, f.endpList[create.Name].Metadata) assert.Equal(createNil.Name, f.endpList[createNil.Name].Name) assert.Equal(createNil.ServName, f.endpList[createNil.Name].ServName) - assert.Equal(map[string]string{b.opKey: b.opVal}, f.endpList[createNil.Name].Metadata) + assert.Equal(map[string]string{b.opMetaPair.Key: b.opMetaPair.Value}, f.endpList[createNil.Name].Metadata) assert.Equal(create.NsName, f.endpList[create.Name].NsName) // assert that nothing was updated diff --git a/pkg/servregistry/namespace.go b/pkg/servregistry/namespace.go index 32f7634..5a9514e 100644 --- a/pkg/servregistry/namespace.go +++ b/pkg/servregistry/namespace.go @@ -49,7 +49,7 @@ func (b *Broker) ManageNs(nsData *Namespace) (regNs *Namespace, err error) { if nsData.Metadata == nil { nsData.Metadata = map[string]string{} } - nsData.Metadata[b.opKey] = b.opVal + nsData.Metadata[b.opMetaPair.Key] = b.opMetaPair.Value l := b.log.WithName("ManageNs").WithValues("ns-name", nsData.Name) // -- Do stuff @@ -75,7 +75,7 @@ func (b *Broker) ManageNs(nsData *Namespace) (regNs *Namespace, err error) { regNs = nsData } - if by, exists := regNs.Metadata[b.opKey]; by != b.opVal || !exists { + if by, exists := regNs.Metadata[b.opMetaPair.Key]; by != b.opMetaPair.Value || !exists { // If the namespace is not owned (as in, managed by) us, then it's // better not to touch it. l.V(0).Info("namespace is not owned by the operator and thus will not be updated") @@ -152,7 +152,7 @@ func (b *Broker) RemoveNs(nsName string, forceNotEmpty bool) (err error) { servs := []string{} hasNotOwned := false for _, serv := range listServ { - if by, exists := serv.Metadata[b.opKey]; by != b.opVal || !exists { + if by, exists := serv.Metadata[b.opMetaPair.Key]; by != b.opMetaPair.Value || !exists { l.V(0).Info("namespace contains services not owned by the operator") hasNotOwned = true continue @@ -174,7 +174,7 @@ func (b *Broker) RemoveNs(nsName string, forceNotEmpty bool) (err error) { return ErrNsNotOwnedServs } - if by, exists := regNs.Metadata[b.opKey]; by != b.opVal || !exists { + if by, exists := regNs.Metadata[b.opMetaPair.Key]; by != b.opMetaPair.Value || !exists { // If the namespace is not owned (as in, managed by) us, then it's // better not to touch it. l.V(0).Info("WARNING: namespace is not owned by the operator and will not be removed from service registry") diff --git a/pkg/servregistry/namespace_test.go b/pkg/servregistry/namespace_test.go index 3728467..933d096 100644 --- a/pkg/servregistry/namespace_test.go +++ b/pkg/servregistry/namespace_test.go @@ -25,7 +25,7 @@ import ( func TestManageNs(t *testing.T) { // prepare var f *fakeServReg - b, _ := NewBroker(f, "", "") + b, _ := NewBroker(f, MetadataPair{}) resetFake := func() { f = newFakeStruct() @@ -85,11 +85,11 @@ func TestManageNs(t *testing.T) { defer resetFake() assert := a.New(tt) - one := &Namespace{Name: "one", Metadata: map[string]string{b.opKey: "someone-else", "key": "val"}} + one := &Namespace{Name: "one", Metadata: map[string]string{b.opMetaPair.Key: "someone-else", "key": "val"}} two := &Namespace{Name: "two", Metadata: map[string]string{"key": "val"}} - oneChange := &Namespace{Name: "one", Metadata: map[string]string{b.opKey: b.opVal, "key": "val-1"}} - twoChange := &Namespace{Name: "two", Metadata: map[string]string{b.opKey: b.opVal, "key": "val-1"}} + oneChange := &Namespace{Name: "one", Metadata: map[string]string{b.opMetaPair.Key: b.opMetaPair.Value, "key": "val-1"}} + twoChange := &Namespace{Name: "two", Metadata: map[string]string{b.opMetaPair.Key: b.opMetaPair.Value, "key": "val-1"}} f.nsList[one.Name] = one f.nsList[two.Name] = two @@ -111,8 +111,8 @@ func TestManageNs(t *testing.T) { assert := a.New(tt) // should return nil because an error in updating - shouldErr := &Namespace{Name: "update-error", Metadata: map[string]string{b.opKey: b.opVal, "key": "val"}} - changeErr := &Namespace{Name: "update-error", Metadata: map[string]string{b.opKey: b.opVal, "key": "val-1"}} + shouldErr := &Namespace{Name: "update-error", Metadata: map[string]string{b.opMetaPair.Key: b.opMetaPair.Value, "key": "val"}} + changeErr := &Namespace{Name: "update-error", Metadata: map[string]string{b.opMetaPair.Key: b.opMetaPair.Value, "key": "val-1"}} f.nsList[shouldErr.Name] = shouldErr regNs, err := b.ManageNs(changeErr) @@ -120,8 +120,8 @@ func TestManageNs(t *testing.T) { assert.Error(err) // no error so it should return the new value - shouldOk := &Namespace{Name: "update", Metadata: map[string]string{b.opKey: b.opVal, "key": "val"}} - changeOk := &Namespace{Name: "update", Metadata: map[string]string{b.opKey: b.opVal, "key": "val-1"}} + shouldOk := &Namespace{Name: "update", Metadata: map[string]string{b.opMetaPair.Key: b.opMetaPair.Value, "key": "val"}} + changeOk := &Namespace{Name: "update", Metadata: map[string]string{b.opMetaPair.Key: b.opMetaPair.Value, "key": "val-1"}} f.nsList[shouldOk.Name] = shouldOk regNs, err = b.ManageNs(changeOk) @@ -138,7 +138,7 @@ func TestManageNs(t *testing.T) { // should return nil because an error in creating // (this also happens if someone else creates this) - create := &Namespace{Name: "create-error", Metadata: map[string]string{b.opKey: b.opVal, "key": "val"}} + create := &Namespace{Name: "create-error", Metadata: map[string]string{b.opMetaPair.Key: b.opMetaPair.Value, "key": "val"}} regNs, err := b.ManageNs(create) assert.Nil(regNs) assert.Error(err) @@ -147,7 +147,7 @@ func TestManageNs(t *testing.T) { create = &Namespace{Name: "create", Metadata: map[string]string{"key": "val"}} regNs, err = b.ManageNs(create) assert.Equal(create.Name, regNs.Name) - assert.Equal(map[string]string{b.opKey: b.opVal, "key": "val"}, regNs.Metadata) + assert.Equal(map[string]string{b.opMetaPair.Key: b.opMetaPair.Value, "key": "val"}, regNs.Metadata) assert.NoError(err) assert.Empty(f.updatedNs) @@ -164,7 +164,7 @@ func TestRemoveNs(t *testing.T) { // prepare nsName := "ns" var f *fakeServReg - b, _ := NewBroker(f, "", "") + b, _ := NewBroker(f, MetadataPair{}) resetFake := func() { f = newFakeStruct() @@ -209,7 +209,7 @@ func TestRemoveNs(t *testing.T) { defer resetFake() assert := a.New(tt) - one := &Namespace{Name: "not-owned", Metadata: map[string]string{b.opKey: "someone-else", "key": "val"}} + one := &Namespace{Name: "not-owned", Metadata: map[string]string{b.opMetaPair.Key: "someone-else", "key": "val"}} two := &Namespace{Name: "not-owned", Metadata: map[string]string{"key": "val"}} f.nsList[one.Name] = one f.nsList[two.Name] = two @@ -233,14 +233,14 @@ func TestRemoveNs(t *testing.T) { assert.NoError(err) // unknown error - toDel := &Namespace{Name: "delete-error", Metadata: map[string]string{b.opKey: b.opVal, "key": "val"}} + toDel := &Namespace{Name: "delete-error", Metadata: map[string]string{b.opMetaPair.Key: b.opMetaPair.Value, "key": "val"}} f.nsList[toDel.Name] = toDel err = b.RemoveNs("delete-error", false) assert.NotEqual(ErrServRegNotProvided, err) assert.NotEqual(ErrNsNameNotProvided, err) // successful - present := &Namespace{Name: "owned", Metadata: map[string]string{b.opKey: b.opVal, "key": "val"}} + present := &Namespace{Name: "owned", Metadata: map[string]string{b.opMetaPair.Key: b.opMetaPair.Value, "key": "val"}} f.nsList[present.Name] = present err = b.RemoveNs("owned", false) assert.NoError(err) @@ -254,20 +254,20 @@ func TestRemoveNs(t *testing.T) { oneOwned := &Service{ Name: "one", - Metadata: map[string]string{b.opKey: b.opVal, "key": "val"}, + Metadata: map[string]string{b.opMetaPair.Key: b.opMetaPair.Value, "key": "val"}, NsName: nsName, } twoOwned := &Service{ Name: "two", - Metadata: map[string]string{b.opKey: b.opVal, "key": "val"}, + Metadata: map[string]string{b.opMetaPair.Key: b.opMetaPair.Value, "key": "val"}, NsName: nsName, } threeNotOwned := &Service{ Name: "three", - Metadata: map[string]string{b.opKey: "someone-else", "key": "val"}, + Metadata: map[string]string{b.opMetaPair.Key: "someone-else", "key": "val"}, NsName: nsName, } - nsDel := &Namespace{Name: nsName, Metadata: map[string]string{b.opKey: b.opVal, "key": "val"}} + nsDel := &Namespace{Name: nsName, Metadata: map[string]string{b.opMetaPair.Key: b.opMetaPair.Value, "key": "val"}} f.nsList[nsDel.Name] = nsDel // error in listing @@ -293,7 +293,7 @@ func TestRemoveNs(t *testing.T) { assert.Contains(f.deletedServ, twoOwned.Name) // error occurs in deleting namespace - shouldErr := &Namespace{Name: "delete-error", Metadata: map[string]string{b.opKey: b.opVal, "key": "val"}} + shouldErr := &Namespace{Name: "delete-error", Metadata: map[string]string{b.opMetaPair.Key: b.opMetaPair.Value, "key": "val"}} f.nsList[shouldErr.Name] = shouldErr f.deletedServ = []string{} f.deletedNs = []string{} diff --git a/pkg/servregistry/service.go b/pkg/servregistry/service.go index f89f8b4..f84bc11 100644 --- a/pkg/servregistry/service.go +++ b/pkg/servregistry/service.go @@ -58,7 +58,7 @@ func (b *Broker) ManageServ(servData *Service) (regServ *Service, err error) { if servData.Metadata == nil { servData.Metadata = map[string]string{} } - servData.Metadata[b.opKey] = b.opVal + servData.Metadata[b.opMetaPair.Key] = b.opMetaPair.Value l := b.log.WithName("ManageServ").WithValues("serv-name", servData.Name) // -- Do stuff @@ -84,7 +84,7 @@ func (b *Broker) ManageServ(servData *Service) (regServ *Service, err error) { regServ = servData } - if by, exists := regServ.Metadata[b.opKey]; by != b.opVal || !exists { + if by, exists := regServ.Metadata[b.opMetaPair.Key]; by != b.opMetaPair.Value || !exists { // If the service is not owned (as in, managed by) us, then it's // better not to touch it. l.V(0).Info("service is not owned by the operator and thus will not be updated") @@ -163,7 +163,7 @@ func (b *Broker) RemoveServ(nsName, servName string, forceNotEmpty bool) (err er endps := []string{} hasNotOwned := false for _, endp := range listEndp { - if by, exists := endp.Metadata[b.opKey]; by != b.opVal || !exists { + if by, exists := endp.Metadata[b.opMetaPair.Key]; by != b.opMetaPair.Value || !exists { hasNotOwned = true continue } @@ -184,7 +184,7 @@ func (b *Broker) RemoveServ(nsName, servName string, forceNotEmpty bool) (err er return ErrServNotOwnedEndps } - if by, exists := regServ.Metadata[b.opKey]; by != b.opVal || !exists { + if by, exists := regServ.Metadata[b.opMetaPair.Key]; by != b.opMetaPair.Value || !exists { // If the service is not owned (as in, managed by) us, then it's // better not to touch it. l.V(0).Info("WARNING: service is not owned by the operator and will not be removed from service registry") diff --git a/pkg/servregistry/service_test.go b/pkg/servregistry/service_test.go index 59b1086..66cb31c 100644 --- a/pkg/servregistry/service_test.go +++ b/pkg/servregistry/service_test.go @@ -26,7 +26,7 @@ func TestManageServ(t *testing.T) { // prepare nsName, servName := "ns", "serv" var f *fakeServReg - b, _ := NewBroker(f, "", "") + b, _ := NewBroker(f, MetadataPair{}) resetFake := func() { f = newFakeStruct() @@ -93,11 +93,11 @@ func TestManageServ(t *testing.T) { defer resetFake() assert := a.New(tt) - one := &Service{Name: "one", NsName: nsName, Metadata: map[string]string{b.opKey: "someone-else", "key": "val"}} + one := &Service{Name: "one", NsName: nsName, Metadata: map[string]string{b.opMetaPair.Key: "someone-else", "key": "val"}} two := &Service{Name: "two", NsName: nsName, Metadata: map[string]string{"key": "val"}} f.servList = map[string]*Service{one.Name: one, two.Name: two} - oneChange := &Service{Name: "one", NsName: nsName, Metadata: map[string]string{b.opKey: b.opVal, "key": "val-1"}} + oneChange := &Service{Name: "one", NsName: nsName, Metadata: map[string]string{b.opMetaPair.Key: b.opMetaPair.Value, "key": "val-1"}} twoChange := &Service{Name: "two", NsName: nsName, Metadata: map[string]string{"key": "val-1"}} regServ, err := b.ManageServ(oneChange) @@ -118,8 +118,8 @@ func TestManageServ(t *testing.T) { assert := a.New(tt) // should return nil because an error in updating - shouldErr := &Service{Name: "update-error", NsName: nsName, Metadata: map[string]string{b.opKey: b.opVal, "key": "val"}} - changeErr := &Service{Name: "update-error", NsName: nsName, Metadata: map[string]string{b.opKey: b.opVal, "key": "val-1"}} + shouldErr := &Service{Name: "update-error", NsName: nsName, Metadata: map[string]string{b.opMetaPair.Key: b.opMetaPair.Value, "key": "val"}} + changeErr := &Service{Name: "update-error", NsName: nsName, Metadata: map[string]string{b.opMetaPair.Key: b.opMetaPair.Value, "key": "val-1"}} f.servList[shouldErr.Name] = shouldErr regServ, err := b.ManageServ(changeErr) @@ -128,8 +128,8 @@ func TestManageServ(t *testing.T) { assert.Empty(f.updatedServ) // no error so it should return the new value - shouldOk := &Service{Name: "update", NsName: nsName, Metadata: map[string]string{b.opKey: b.opVal, "key": "val"}} - okChange := &Service{Name: "update", NsName: nsName, Metadata: map[string]string{b.opKey: b.opVal, "key": "val-1"}} + shouldOk := &Service{Name: "update", NsName: nsName, Metadata: map[string]string{b.opMetaPair.Key: b.opMetaPair.Value, "key": "val"}} + okChange := &Service{Name: "update", NsName: nsName, Metadata: map[string]string{b.opMetaPair.Key: b.opMetaPair.Value, "key": "val-1"}} f.servList[shouldOk.Name] = shouldOk regServ, err = b.ManageServ(okChange) @@ -147,7 +147,7 @@ func TestManageServ(t *testing.T) { // should return nil because an error in creating // (this also happens if someone else creates this) - shouldErr := &Service{Name: "create-error", NsName: nsName, Metadata: map[string]string{b.opKey: b.opVal, "key": "val"}} + shouldErr := &Service{Name: "create-error", NsName: nsName, Metadata: map[string]string{b.opMetaPair.Key: b.opMetaPair.Value, "key": "val"}} regServ, err := b.ManageServ(shouldErr) assert.Nil(regServ) assert.Error(err) @@ -158,7 +158,7 @@ func TestManageServ(t *testing.T) { regServ, err = b.ManageServ(shouldOk) assert.Equal(shouldOk.Name, regServ.Name) assert.Equal(shouldOk.NsName, regServ.NsName) - assert.Equal(map[string]string{b.opKey: b.opVal, "key": "val"}, regServ.Metadata) + assert.Equal(map[string]string{b.opMetaPair.Key: b.opMetaPair.Value, "key": "val"}, regServ.Metadata) assert.NoError(err) assert.Empty(f.updatedServ) @@ -176,7 +176,7 @@ func TestRemoveServ(t *testing.T) { // prepare nsName, servName := "ns", "serv" var f *fakeServReg - b, _ := NewBroker(f, "", "") + b, _ := NewBroker(f, MetadataPair{}) resetFake := func() { f = newFakeStruct() @@ -225,7 +225,7 @@ func TestRemoveServ(t *testing.T) { defer resetFake() assert := a.New(tt) - one := &Service{Name: "one", NsName: nsName, Metadata: map[string]string{b.opKey: "someone-else", "key": "val"}} + one := &Service{Name: "one", NsName: nsName, Metadata: map[string]string{b.opMetaPair.Key: "someone-else", "key": "val"}} two := &Service{Name: "two", NsName: nsName, Metadata: map[string]string{"key": "val"}} f.servList[one.Name] = one f.servList[two.Name] = two @@ -253,7 +253,7 @@ func TestRemoveServ(t *testing.T) { assert.NoError(err) // successful - toDel := &Service{Name: "to-del", NsName: nsName, Metadata: map[string]string{b.opKey: b.opVal, "key": "val"}} + toDel := &Service{Name: "to-del", NsName: nsName, Metadata: map[string]string{b.opMetaPair.Key: b.opMetaPair.Value, "key": "val"}} f.servList[toDel.Name] = toDel err = b.RemoveServ(nsName, "to-del", false) assert.NoError(err) @@ -269,21 +269,21 @@ func TestRemoveServ(t *testing.T) { Name: "one", ServName: servName, NsName: nsName, - Metadata: map[string]string{b.opKey: b.opVal, "key": "val"}, + Metadata: map[string]string{b.opMetaPair.Key: b.opMetaPair.Value, "key": "val"}, } twoOwned := &Endpoint{ Name: "two", ServName: servName, NsName: nsName, - Metadata: map[string]string{b.opKey: b.opVal, "key": "val"}, + Metadata: map[string]string{b.opMetaPair.Key: b.opMetaPair.Value, "key": "val"}, } threeNotOwned := &Endpoint{ Name: "three", ServName: servName, NsName: nsName, - Metadata: map[string]string{b.opKey: "someone-else", "key": "val"}, + Metadata: map[string]string{b.opMetaPair.Key: "someone-else", "key": "val"}, } - servDel := &Service{Name: servName, NsName: nsName, Metadata: map[string]string{b.opKey: b.opVal, "key": "val"}} + servDel := &Service{Name: servName, NsName: nsName, Metadata: map[string]string{b.opMetaPair.Key: b.opMetaPair.Value, "key": "val"}} f.servList[servDel.Name] = servDel // error in listing @@ -320,7 +320,7 @@ func TestRemoveServ(t *testing.T) { assert.NoError(err) // error occurs in deleting service - shouldErr := &Service{Name: "delete-error", NsName: nsName, Metadata: map[string]string{b.opKey: b.opVal, "key": "val"}} + shouldErr := &Service{Name: "delete-error", NsName: nsName, Metadata: map[string]string{b.opMetaPair.Key: b.opMetaPair.Value, "key": "val"}} f.servList[shouldErr.Name] = shouldErr f.deletedEndp = []string{} f.deletedServ = []string{} diff --git a/pkg/servregistry/utils.go b/pkg/servregistry/utils.go index 9366ffa..623b585 100644 --- a/pkg/servregistry/utils.go +++ b/pkg/servregistry/utils.go @@ -28,7 +28,7 @@ func (b *Broker) deepEqualMetadata(src, dst map[string]string) bool { de := map[string]string{} for key, val := range src { - if key == b.opKey && val == b.opVal { + if key == b.opMetaPair.Key && val == b.opMetaPair.Value { // Don't copy this one continue } @@ -36,7 +36,7 @@ func (b *Broker) deepEqualMetadata(src, dst map[string]string) bool { } for key, val := range dst { - if key == b.opKey && val == b.opVal { + if key == b.opMetaPair.Key && val == b.opMetaPair.Value { // Don't copy this one continue } From e08f7d5b234eacd99f9cd69d9e35a3b54b9dec63 Mon Sep 17 00:00:00 2001 From: Elis Lulja Date: Thu, 17 Jun 2021 11:11:36 +0200 Subject: [PATCH 4/6] Get google service account secret from k8s This commit implements a function to retrieve a secret containing the google service account without having it mounted on the pod's volume. It will be used in future to get the service account for service directory as well. Unit tests are included. Signed-off-by: Elis Lulja --- go.mod | 1 + pkg/cluster/doc.go | 4 +- pkg/cluster/kubernetes.go | 85 ++++++++++++++++++++++++++ pkg/cluster/kubernetes_test.go | 107 +++++++++++++++++++++++++++++++++ 4 files changed, 196 insertions(+), 1 deletion(-) create mode 100644 pkg/cluster/kubernetes.go create mode 100644 pkg/cluster/kubernetes_test.go diff --git a/go.mod b/go.mod index 3e0d174..c796055 100644 --- a/go.mod +++ b/go.mod @@ -8,6 +8,7 @@ require ( github.com/go-logr/logr v0.1.0 github.com/googleapis/gax-go v1.0.3 github.com/grpc-ecosystem/grpc-gateway v1.14.6 // indirect + github.com/jmespath/go-jmespath/internal/testify v1.5.1 github.com/onsi/ginkgo v1.14.2 github.com/onsi/gomega v1.10.3 github.com/spf13/viper v1.7.1 diff --git a/pkg/cluster/doc.go b/pkg/cluster/doc.go index 3903a68..b996ae5 100644 --- a/pkg/cluster/doc.go +++ b/pkg/cluster/doc.go @@ -16,6 +16,8 @@ // Package cluster contains code that gets information about the cluster where // we are running and if it is a managed cluster, e.g. GKE or EKS. +// For example: VPC, SubNetwork, Cluster Name, etc. // -// Code gets information like VPC, SubNetwork, Cluster Name, etc. +// Additionally, it also retrieves common objects from Kubernetes, e.g.: +// ConfigMap and Secrets. package cluster diff --git a/pkg/cluster/kubernetes.go b/pkg/cluster/kubernetes.go new file mode 100644 index 0000000..fef7a1d --- /dev/null +++ b/pkg/cluster/kubernetes.go @@ -0,0 +1,85 @@ +// Copyright © 2021 Cisco +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +// All rights reserved. + +package cluster + +import ( + "context" + "fmt" + + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + + "k8s.io/client-go/kubernetes" + ctrl "sigs.k8s.io/controller-runtime" +) + +const ( + defaultK8sNamespace string = "cnwan-operator-system" + defaultGoogleServiceAccountSecretName string = "google-service-account" +) + +var ( + kcli kubernetes.Interface +) + +func getK8sClientSet() (kubernetes.Interface, error) { + if kcli != nil { + return kcli, nil + } + + k8sconf, err := ctrl.GetConfig() + if err != nil { + return nil, err + } + + kcli, err = kubernetes.NewForConfig(k8sconf) + if err != nil { + return nil, err + } + + return kcli, nil +} + +// GetGoogleServiceAccountSecret tries to retrieve the Google Service Account +// secret from Kubernetes, so that it could be used to login to Google Cloud +// services such as Service Directory or to pull cloud metadata/configuration. +func GetGoogleServiceAccountSecret(ctx context.Context) ([]byte, error) { + cli, err := getK8sClientSet() + if err != nil { + return nil, err + } + + // TODO: May change this on future to use a different namespace. + secret, err := cli.CoreV1().Secrets(defaultK8sNamespace).Get(ctx, defaultGoogleServiceAccountSecretName, metav1.GetOptions{}) + if err != nil { + return nil, err + } + + switch l := len(secret.Data); { + case l == 0: + return nil, fmt.Errorf(`secret %s/%s has no data`, defaultK8sNamespace, defaultGoogleServiceAccountSecretName) + case l > 1: + return nil, fmt.Errorf(`secrets %s/%s has multiple data`, defaultK8sNamespace, defaultGoogleServiceAccountSecretName) + } + + var data []byte + for _, d := range secret.Data { + data = d + break + } + + return data, nil +} diff --git a/pkg/cluster/kubernetes_test.go b/pkg/cluster/kubernetes_test.go new file mode 100644 index 0000000..3d6ff4d --- /dev/null +++ b/pkg/cluster/kubernetes_test.go @@ -0,0 +1,107 @@ +// Copyright © 2021 Cisco +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +// All rights reserved. + +package cluster + +import ( + "context" + "fmt" + "testing" + + "github.com/stretchr/testify/assert" + corev1 "k8s.io/api/core/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/client-go/kubernetes" + "k8s.io/client-go/kubernetes/fake" +) + +func TestGetGoogleServiceAccountSecret(t *testing.T) { + + anyErr := fmt.Errorf("any") + cases := []struct { + kcli kubernetes.Interface + expRes []byte + expErr error + }{ + { + kcli: fake.NewSimpleClientset(), + expErr: anyErr, + }, + { + kcli: func() kubernetes.Interface { + sec := &corev1.Secret{ + ObjectMeta: metav1.ObjectMeta{ + Name: defaultGoogleServiceAccountSecretName, + Namespace: defaultK8sNamespace, + }, + } + return fake.NewSimpleClientset(sec) + }(), + expErr: fmt.Errorf(`secret %s/%s has no data`, defaultK8sNamespace, defaultGoogleServiceAccountSecretName), + }, + { + kcli: func() kubernetes.Interface { + sec := &corev1.Secret{ + ObjectMeta: metav1.ObjectMeta{ + Name: defaultGoogleServiceAccountSecretName, + Namespace: defaultK8sNamespace, + }, + Data: map[string][]byte{ + "test": []byte("test"), + "test-1": []byte("test-1"), + }, + } + return fake.NewSimpleClientset(sec) + }(), + expErr: fmt.Errorf(`secrets %s/%s has multiple data`, defaultK8sNamespace, defaultGoogleServiceAccountSecretName), + }, + { + kcli: func() kubernetes.Interface { + sec := &corev1.Secret{ + ObjectMeta: metav1.ObjectMeta{ + Name: defaultGoogleServiceAccountSecretName, + Namespace: defaultK8sNamespace, + }, + Data: map[string][]byte{ + "test": []byte("test"), + }, + } + return fake.NewSimpleClientset(sec) + }(), + expRes: []byte("test"), + }, + } + + for i, currCase := range cases { + a := assert.New(t) + kcli = currCase.kcli + res, err := GetGoogleServiceAccountSecret(context.Background()) + + if currCase.expErr == anyErr { + if err == nil { + a.FailNow("case failed: was expecting error but no error occurred", "i", i) + } + + continue + } + + if !a.Equal(currCase.expRes, res) || !a.Equal(currCase.expErr, err) { + a.FailNow("case failed", "i", i) + } + + kcli = nil + } +} From 30b21c033f1f34ff5a32a17338c18357736c1b23 Mon Sep 17 00:00:00 2001 From: Elis Lulja Date: Thu, 17 Jun 2021 13:39:22 +0200 Subject: [PATCH 5/6] Get network data Network configuration data is now pulled from the cluster and entered to the broker as persistent metadata. Signed-off-by: Elis Lulja --- go.mod | 1 - main.go | 68 ++++++++++++++++++++++++++++++++++++- pkg/servregistry/service.go | 4 +++ 3 files changed, 71 insertions(+), 2 deletions(-) diff --git a/go.mod b/go.mod index c796055..3e0d174 100644 --- a/go.mod +++ b/go.mod @@ -8,7 +8,6 @@ require ( github.com/go-logr/logr v0.1.0 github.com/googleapis/gax-go v1.0.3 github.com/grpc-ecosystem/grpc-gateway v1.14.6 // indirect - github.com/jmespath/go-jmespath/internal/testify v1.5.1 github.com/onsi/ginkgo v1.14.2 github.com/onsi/gomega v1.10.3 github.com/spf13/viper v1.7.1 diff --git a/main.go b/main.go index 1fcd437..bedc151 100644 --- a/main.go +++ b/main.go @@ -22,17 +22,20 @@ import ( "io/ioutil" "os" "runtime" + "strings" "time" "github.com/CloudNativeSDWAN/cnwan-operator/controllers" "github.com/CloudNativeSDWAN/cnwan-operator/internal/types" "github.com/CloudNativeSDWAN/cnwan-operator/internal/utils" + "github.com/CloudNativeSDWAN/cnwan-operator/pkg/cluster" sr "github.com/CloudNativeSDWAN/cnwan-operator/pkg/servregistry" "github.com/CloudNativeSDWAN/cnwan-operator/pkg/servregistry/etcd" sd "github.com/CloudNativeSDWAN/cnwan-operator/pkg/servregistry/gcloud/servicedirectory" "github.com/spf13/viper" "go.etcd.io/etcd/clientv3" "go.uber.org/zap/zapcore" + "google.golang.org/api/option" "gopkg.in/yaml.v3" corev1 "k8s.io/api/core/v1" v1 "k8s.io/apimachinery/pkg/apis/meta/v1" @@ -130,6 +133,27 @@ func main() { } viper.Set(types.AllowedAnnotationsMap, allowedAnnotations) + persistentMeta := []sr.MetadataPair{} + if settings.CloudMetadata != nil { + // No need to check for network and subnetwork nil as it was already + // validate previously. + netCfg, err := getNetworkCfg(settings.CloudMetadata.Network, settings.CloudMetadata.SubNetwork) + if err != nil { + setupLog.Error(err, "could not get cloud network information, skipping...") + } else { + setupLog.Info("got network configuration", "cnwan.io/network", netCfg.NetworkName, "cnwan.io/sub-network", netCfg.SubNetworkName) + if runningIn := cluster.WhereAmIRunning(); runningIn != cluster.UnknownCluster { + persistentMeta = append(persistentMeta, sr.MetadataPair{Key: "cnwan.io/platform", Value: string(runningIn)}) + } + if netCfg.NetworkName != "" { + persistentMeta = append(persistentMeta, sr.MetadataPair{Key: "cnwan.io/network", Value: netCfg.NetworkName}) + } + if netCfg.NetworkName != "" { + persistentMeta = append(persistentMeta, sr.MetadataPair{Key: "cnwan.io/sub-network", Value: netCfg.SubNetworkName}) + } + } + } + //-------------------------------------- // Get the service registry //-------------------------------------- @@ -158,7 +182,7 @@ func main() { runtime.Goexit() } - srBroker, err := sr.NewBroker(servreg, sr.MetadataPair{Key: opKey, Value: opVal}) + srBroker, err := sr.NewBroker(servreg, sr.MetadataPair{Key: opKey, Value: opVal}, persistentMeta...) if err != nil { setupLog.Error(err, "fatal error encountered") returnCode = 6 @@ -331,3 +355,45 @@ func getEtcdConfWithCredentials(clientset *kubernetes.Clientset) (*clientv3.Conf return cfg, nil } + +func getNetworkCfg(network, subnetwork *string) (netCfg *cluster.NetworkConfiguration, err error) { + netCfg = &cluster.NetworkConfiguration{} + if network != nil { + netCfg.NetworkName = *network + } + if subnetwork != nil { + netCfg.SubNetworkName = *subnetwork + } + + if strings.ToLower(netCfg.NetworkName) == "auto" || strings.ToLower(netCfg.SubNetworkName) == "auto" { + var res *cluster.NetworkConfiguration + runningIn := cluster.WhereAmIRunning() + if runningIn == cluster.UnknownCluster { + return nil, fmt.Errorf("could not get information about the managed cluster: unsupported or no permissions to do so") + } + + if runningIn == cluster.GKECluster { + sa, err := cluster.GetGoogleServiceAccountSecret(context.Background()) + if err != nil { + return nil, err + } + + res, err = cluster.GetNetworkFromGKE(context.Background(), option.WithCredentialsJSON(sa)) + if err != nil { + return nil, err + } + } + + // TODO: implement EKS on future versions. Code is ready but just not + // included in this iteration. + + if strings.ToLower(netCfg.NetworkName) == "auto" { + netCfg.NetworkName = res.NetworkName + } + if strings.ToLower(netCfg.SubNetworkName) == "auto" { + netCfg.SubNetworkName = res.SubNetworkName + } + } + + return +} diff --git a/pkg/servregistry/service.go b/pkg/servregistry/service.go index f84bc11..ba94a5f 100644 --- a/pkg/servregistry/service.go +++ b/pkg/servregistry/service.go @@ -59,6 +59,10 @@ func (b *Broker) ManageServ(servData *Service) (regServ *Service, err error) { servData.Metadata = map[string]string{} } servData.Metadata[b.opMetaPair.Key] = b.opMetaPair.Value + for _, metaPair := range b.persistentMeta { + servData.Metadata[metaPair.Key] = metaPair.Value + } + l := b.log.WithName("ManageServ").WithValues("serv-name", servData.Name) // -- Do stuff From c5e5fe8d55e920b97c95b038d0b1a173301e09bf Mon Sep 17 00:00:00 2001 From: Elis Lulja Date: Fri, 18 Jun 2021 10:56:04 +0200 Subject: [PATCH 6/6] Update documentation Documentation is updated to include Cloud Metadata. Signed-off-by: Elis Lulja --- docs/concepts.md | 9 +++++++++ docs/configuration.md | 35 +++++++++++++++++++++++++++++++++++ 2 files changed, 44 insertions(+) diff --git a/docs/concepts.md b/docs/concepts.md index e689289..2c635a5 100644 --- a/docs/concepts.md +++ b/docs/concepts.md @@ -10,6 +10,7 @@ * [Namespace Lists](#namespace-lists) * [Namespace List Policy](#namespace-list-policy) * [Allowed Annotations](#allowed-annotations) +* [Cloud Metadata](#cloud-metadata) * [Deploy](#deploy) ## How it Works @@ -130,6 +131,14 @@ If a service does not have **at least** one of the allowed annotations, then it You can define which annotations are allowed by setting up [configurations](./configuration.md#allow-annotations). +## Cloud Metadata + +As the name suggests, *Cloud Metadata* are data that contain information about the Kubernetes cluster that is hosting the operator and the services that are going to be registered. +Such data can be the *Network*, *Subnetwork*, etc. The operator is able to retrieve some values automatically, depending on the Kubernetes platform, e.g. *GKE* or *EKS* but you can also provide some values manually through configuration. +These values will be stored in all registered services to be consumed by anyone interested in them, e.g. the CN-WAN Reader and the CN-WAN Adaptor. + +To learn how to define them look at this [section](./configuration.md#cloud-metadata). + ## Deploy There are two ways to deploy the operator, according to your use case and knowledge of Kubernetes: diff --git a/docs/configuration.md b/docs/configuration.md index 6d362aa..03ec5b0 100644 --- a/docs/configuration.md +++ b/docs/configuration.md @@ -7,6 +7,7 @@ This section will guide you through the steps you need to take to configure the * [Format](#format) * [Set the Namespace List Policy](#set-the-namespace-list-policy) * [Allow Annotations](#allow-annotations) +* [Cloud Metadata](#cloud-metadata) * [Service registry settings](#service-registry-settings) * [Deploy settings](#deploy-settings) * [Update settings](#update-settings) @@ -32,6 +33,9 @@ serviceRegistry: gcpServiceDirectory: defaultRegion: projectID: +cloudMetadata: + network: auto + subNetwork: auto ``` ## Set the Namespace List Policy @@ -98,6 +102,37 @@ name-with-no-prefix: simple-value Finally, if you leave this empty - as `annotations: []`, then no service will match this and, therefore, no service will be registered. +## Cloud Metadata + +Cloud Metadata can be registered automatically through the `cloudMetadata` setting. + +You can provide manual values by entering the information you want like this: + +```yaml +cloudMetadata: + network: my-vpc-id + subNetwork: my-subnet-id +``` + +or automatically as: + +```yaml +cloudMetadata: + network: auto + subNetwork: auto +``` + +and the Operator will try to detect such information on its own. You can remove a field, e.g. `subNetwork`, from the settings if you don't want that to be registered. + +These values will be registered on a service metadata as: + +```text +cnwan.io/network: +cnwan.io/sub-network: +``` + +Additionally, `cnwan.io/platform: ` will also be included if the operator detects you are running in a managed cluster. + ## Service registry settings Under `serviceRegistry` you define which service registry to use and how the operator should connect to it or manage its objects.