diff --git a/pkg/cloud/metadata/ack_cluster_profile.go b/pkg/cloud/metadata/ack_cluster_profile.go new file mode 100644 index 000000000..418779cdd --- /dev/null +++ b/pkg/cloud/metadata/ack_cluster_profile.go @@ -0,0 +1,49 @@ +package metadata + +import ( + "context" + + v1 "k8s.io/api/core/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/client-go/kubernetes" +) + +type ProfileMetadata struct { + profile *v1.ConfigMap +} + +var MetadataProfileDataKeys = map[MetadataKey]string{ + ClusterID: "clusterid", + AccountID: "uid", +} + +func NewProfileMetadata(client kubernetes.Interface) (*ProfileMetadata, error) { + profile, err := client.CoreV1().ConfigMaps("kube-system").Get(context.Background(), "ack-cluster-profile", metav1.GetOptions{}) + if err != nil { + return nil, err + } + return &ProfileMetadata{profile: profile}, nil +} + +func (m *ProfileMetadata) Get(key MetadataKey) (string, error) { + if key, ok := MetadataProfileDataKeys[key]; ok { + return m.profile.Data[key], nil + } + return "", ErrUnknownMetadataKey +} + +type ProfileFetcher struct { + client kubernetes.Interface +} + +func (f *ProfileFetcher) FetchFor(key MetadataKey) (MetadataProvider, error) { + _, ok := MetadataProfileDataKeys[key] + if !ok { + return nil, ErrUnknownMetadataKey + } + p, err := NewProfileMetadata(f.client) + if err != nil { + return nil, err + } + return newImmutableProvider(p, "ClusterProfile"), nil +} diff --git a/pkg/cloud/metadata/ack_cluster_profile_test.go b/pkg/cloud/metadata/ack_cluster_profile_test.go new file mode 100644 index 000000000..e70073e01 --- /dev/null +++ b/pkg/cloud/metadata/ack_cluster_profile_test.go @@ -0,0 +1,43 @@ +package metadata + +import ( + "testing" + + "github.com/stretchr/testify/assert" + v1 "k8s.io/api/core/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + fake "k8s.io/client-go/kubernetes/fake" +) + +var testProfile = v1.ConfigMap{ + ObjectMeta: metav1.ObjectMeta{ + Name: "ack-cluster-profile", + Namespace: "kube-system", + }, + Data: map[string]string{ + "clusterid": "c12345678", + "uid": "123456789", + }, +} + +func TestGetClusterProfile(t *testing.T) { + t.Parallel() + + client := fake.NewSimpleClientset(&testProfile) + m, err := NewProfileMetadata(client) + assert.NoError(t, err) + + expectedValues := map[MetadataKey]string{ + AccountID: "123456789", + ClusterID: "c12345678", + } + for k, v := range expectedValues { + t.Log(k, v) + value, err := m.Get(k) + assert.NoError(t, err, k) + assert.Equal(t, v, value) + } +} + +func TestGetClusterProfileNotFound(t *testing.T) { +} diff --git a/pkg/cloud/metadata/k8s.go b/pkg/cloud/metadata/k8s.go index ef57c6e8c..29da0a1dc 100644 --- a/pkg/cloud/metadata/k8s.go +++ b/pkg/cloud/metadata/k8s.go @@ -6,14 +6,12 @@ import ( "strings" v1 "k8s.io/api/core/v1" - apierrors "k8s.io/apimachinery/pkg/api/errors" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "k8s.io/client-go/kubernetes" + corev1 "k8s.io/client-go/kubernetes/typed/core/v1" ) -type KubernetesMetadata struct { - node *v1.Node - profile *v1.ConfigMap +type KubernetesNodeMetadata struct { + node *v1.Node } var ( @@ -48,10 +46,6 @@ var MetadataLabels = map[MetadataKey][]string{ InstanceID: InstanceIdLabels, } -var MetadataProfileDataKeys = map[MetadataKey]string{ - ClusterID: "clusterid", -} - func init() { envInstanceIdKey := os.Getenv("NODE_LABEL_ECS_ID_KEY") if envInstanceIdKey != "" { @@ -60,24 +54,15 @@ func init() { } } -func NewKubernetesMetadata(nodeName string, client kubernetes.Interface) (*KubernetesMetadata, error) { - node, err := client.CoreV1().Nodes().Get(context.Background(), nodeName, metav1.GetOptions{}) +func NewKubernetesNodeMetadata(nodeName string, nodeClient corev1.NodeInterface) (*KubernetesNodeMetadata, error) { + node, err := nodeClient.Get(context.Background(), nodeName, metav1.GetOptions{}) if err != nil { return nil, err } - profile, err := client.CoreV1().ConfigMaps("kube-system").Get(context.Background(), "ack-cluster-profile", metav1.GetOptions{}) - if err != nil && !apierrors.IsNotFound(err) { - return nil, err - } - return &KubernetesMetadata{node: node, profile: profile}, nil + return &KubernetesNodeMetadata{node: node}, nil } -func (m *KubernetesMetadata) Get(key MetadataKey) (string, error) { - - if key, ok := MetadataProfileDataKeys[key]; ok && m.profile != nil { - return m.profile.Data[key], nil - } - +func (m *KubernetesNodeMetadata) Get(key MetadataKey) (string, error) { labels := MetadataLabels[key] for _, label := range labels { if value, ok := m.node.Labels[label]; ok { @@ -98,18 +83,17 @@ func (m *KubernetesMetadata) Get(key MetadataKey) (string, error) { return "", ErrUnknownMetadataKey } -type KubernetesMetadataFetcher struct { - client kubernetes.Interface +type KubernetesNodeMetadataFetcher struct { + client corev1.NodeInterface nodeName string } -func (f *KubernetesMetadataFetcher) FetchFor(key MetadataKey) (MetadataProvider, error) { - _, ok1 := MetadataLabels[key] - _, ok2 := MetadataProfileDataKeys[key] - if !ok1 && !ok2 { +func (f *KubernetesNodeMetadataFetcher) FetchFor(key MetadataKey) (MetadataProvider, error) { + _, ok := MetadataLabels[key] + if !ok { return nil, ErrUnknownMetadataKey } - p, err := NewKubernetesMetadata(f.nodeName, f.client) + p, err := NewKubernetesNodeMetadata(f.nodeName, f.client) if err != nil { return nil, err } diff --git a/pkg/cloud/metadata/k8s_test.go b/pkg/cloud/metadata/k8s_test.go index 62803622a..9d43f6155 100644 --- a/pkg/cloud/metadata/k8s_test.go +++ b/pkg/cloud/metadata/k8s_test.go @@ -15,13 +15,6 @@ var testNode = v1.Node{ }, } -var testProfile = v1.ConfigMap{ - ObjectMeta: metav1.ObjectMeta{ - Name: "ack-cluster-profile", - Namespace: "kube-system", - }, -} - func TestGetK8s(t *testing.T) { t.Parallel() cases := []struct { @@ -29,7 +22,6 @@ func TestGetK8s(t *testing.T) { ProviderID string Labels map[string]string NotFound map[MetadataKey]bool - isACK bool }{ { name: "normal", @@ -39,7 +31,6 @@ func TestGetK8s(t *testing.T) { "topology.kubernetes.io/zone": "cn-hangzhou-a", "node.kubernetes.io/instance-type": "ecs.g7.xlarge", }, - isACK: true, }, { name: "beta", @@ -49,7 +40,6 @@ func TestGetK8s(t *testing.T) { "failure-domain.beta.kubernetes.io/zone": "cn-hangzhou-a", "beta.kubernetes.io/instance-type": "ecs.g7.xlarge", }, - isACK: true, }, { name: "sigma", @@ -59,7 +49,6 @@ func TestGetK8s(t *testing.T) { "sigma.ali/machine-model": "ecs.g7.xlarge", "sigma.ali/ecs-instance-id": "i-2zec1slzwdzrwmvlr4w2", }, - isACK: true, }, { name: "alibabacloud", @@ -72,17 +61,15 @@ func TestGetK8s(t *testing.T) { NotFound: map[MetadataKey]bool{ InstanceType: true, }, - isACK: true, }, { - name: "no label and non-ACK", + name: "no label", ProviderID: "alicloud://cn-hangzhou.i-2zec1slzwdzrwmvlr4w2", Labels: map[string]string{}, NotFound: map[MetadataKey]bool{ ZoneID: true, InstanceType: true, }, - isACK: false, }, } expectedValues := map[MetadataKey]string{ @@ -99,14 +86,8 @@ func TestGetK8s(t *testing.T) { node.Spec.ProviderID = c.ProviderID node.Labels = c.Labels - client := fake.NewSimpleClientset(node) - if c.isACK { - profile := testProfile.DeepCopy() - profile.Data = map[string]string{} - profile.Data["clusterid"] = "c12345678" - client = fake.NewSimpleClientset(node, profile) - } - m, err := NewKubernetesMetadata(node.Name, client) + client := fake.NewSimpleClientset(node).CoreV1().Nodes() + m, err := NewKubernetesNodeMetadata(node.Name, client) assert.NoError(t, err) for k, v := range expectedValues { @@ -119,14 +100,6 @@ func TestGetK8s(t *testing.T) { assert.Equal(t, v, value) } } - - value, err := m.Get(ClusterID) - if c.isACK { - assert.NoError(t, err) - assert.Equal(t, "c12345678", value) - } else { - assert.Equal(t, ErrUnknownMetadataKey, err) - } }) } } diff --git a/pkg/cloud/metadata/metadata.go b/pkg/cloud/metadata/metadata.go index a98699ed0..d9d717d35 100644 --- a/pkg/cloud/metadata/metadata.go +++ b/pkg/cloud/metadata/metadata.go @@ -148,13 +148,18 @@ func (m *Metadata) EnableEcs(httpRT http.RoundTripper) { func (m *Metadata) EnableKubernetes(client kubernetes.Interface) { nodeName := os.Getenv(KUBE_NODE_NAME_ENV) if nodeName == "" { - logrus.Warnf("%s environment variable is not set, skipping Kubernetes metadata", KUBE_NODE_NAME_ENV) - return + logrus.Warnf("%s environment variable is not set, skipping Kubernetes Node metadata", KUBE_NODE_NAME_ENV) + } else { + m.providers = append(m.providers, &lazyInitProvider{ + fetcher: &KubernetesNodeMetadataFetcher{ + client: client.CoreV1().Nodes(), + nodeName: nodeName, + }, + }) } m.providers = append(m.providers, &lazyInitProvider{ - fetcher: &KubernetesMetadataFetcher{ - client: client, - nodeName: nodeName, + fetcher: &ProfileFetcher{ + client: client, }, }) } diff --git a/pkg/cloud/metadata/metadata_test.go b/pkg/cloud/metadata/metadata_test.go index 30c58464f..b18695815 100644 --- a/pkg/cloud/metadata/metadata_test.go +++ b/pkg/cloud/metadata/metadata_test.go @@ -41,29 +41,33 @@ func TestCreateK8s(t *testing.T) { node.Labels = map[string]string{ "topology.kubernetes.io/region": "cn-beijing", } - profile := testProfile.DeepCopy() - profile.Data = map[string]string{} - profile.Data["clusterid"] = "c12345678" - client := fake.NewSimpleClientset(node, profile) + client := fake.NewSimpleClientset(node, &testProfile) t.Run("no node name", func(t *testing.T) { m.EnableKubernetes(client) _, err := m.Get(RegionID) assert.Equal(t, ErrUnknownMetadataKey, err) + assert.Equal(t, "c12345678", MustGet(m, ClusterID)) }) t.Run("ok", func(t *testing.T) { t.Setenv(KUBE_NODE_NAME_ENV, testNode.Name) m.EnableKubernetes(client) assert.Equal(t, "cn-beijing", MustGet(m, RegionID)) - }) - - t.Run("profile", func(t *testing.T) { - m.EnableKubernetes(client) assert.Equal(t, "c12345678", MustGet(m, ClusterID)) }) } +func TestK8sNoProfile(t *testing.T) { + m := NewMetadata() + + client := fake.NewSimpleClientset() + m.EnableKubernetes(client) + _, err := m.Get(ClusterID) + assert.ErrorContains(t, err, "ack-cluster-profile") + assert.ErrorContains(t, err, "not found") +} + func TestGetFromEnv(t *testing.T) { t.Setenv("REGION_ID", "cn-hangzhou") m := NewMetadata()