diff --git a/pact/custom_metrics_test.go b/pact/custom_metrics_test.go index 0e761bc6..ce27517b 100644 --- a/pact/custom_metrics_test.go +++ b/pact/custom_metrics_test.go @@ -13,7 +13,10 @@ import ( "github.com/pact-foundation/pact-go/dsl" "github.com/replicatedhq/kotskinds/apis/kots/v1beta1" "github.com/replicatedhq/replicated-sdk/pkg/handlers" + "github.com/replicatedhq/replicated-sdk/pkg/k8sutil" "github.com/replicatedhq/replicated-sdk/pkg/store" + "github.com/replicatedhq/replicated-sdk/pkg/util" + "k8s.io/client-go/kubernetes/fake" ) func TestSendCustomAppMetrics(t *testing.T) { @@ -63,6 +66,11 @@ func TestSendCustomAppMetrics(t *testing.T) { Status: http.StatusOK, }) } + fakeClientSet := fake.NewSimpleClientset( + k8sutil.CreateTestDeployment(util.GetReplicatedDeploymentName(), "default", "1", map[string]string{"app": "replicated"}), + k8sutil.CreateTestReplicaSet("replicated-sdk-instance-replicaset", "default", "1"), + k8sutil.CreateTestPod("replicated-sdk-instance-pod", "default", "replicated-sdk-instance-replicaset", map[string]string{"app": "replicated"}), + ) t.Run("Send valid custom app metrics", func(t *testing.T) { pactInteraction() @@ -72,11 +80,13 @@ func TestSendCustomAppMetrics(t *testing.T) { ReplicatedAppEndpoint: license.Spec.Endpoint, ChannelID: license.Spec.ChannelID, ChannelSequence: channelSequence, + Namespace: "default", } store.InitInMemory(storeOptions) defer store.SetStore(nil) if err := pact.Verify(func() error { + handlers.SetTestClientSet(fakeClientSet) handlers.SendCustomAppMetrics(clientWriter, clientRequest) if clientWriter.Code != http.StatusOK { return fmt.Errorf("expected status code %d but got %d", http.StatusOK, clientWriter.Code) diff --git a/pkg/apiserver/server.go b/pkg/apiserver/server.go index 06e46222..24cb3fd8 100644 --- a/pkg/apiserver/server.go +++ b/pkg/apiserver/server.go @@ -66,7 +66,8 @@ func Start(params APIServerParams) { r.HandleFunc("/api/v1/app/info", handlers.GetCurrentAppInfo).Methods("GET") r.HandleFunc("/api/v1/app/updates", handlers.GetAppUpdates).Methods("GET") r.HandleFunc("/api/v1/app/history", handlers.GetAppHistory).Methods("GET") - r.HandleFunc("/api/v1/app/custom-metrics", handlers.SendCustomAppMetrics).Methods("POST") + r.HandleFunc("/api/v1/app/custom-metrics", handlers.SendCustomAppMetrics).Methods("POST", "PATCH") + r.HandleFunc("/api/v1/app/custom-metrics/{key}", handlers.DeleteCustomAppMetricsKey).Methods("DELETE") r.HandleFunc("/api/v1/app/instance-tags", handlers.SendAppInstanceTags).Methods("POST") // integration diff --git a/pkg/handlers/app.go b/pkg/handlers/app.go index 936ee359..d9999d24 100644 --- a/pkg/handlers/app.go +++ b/pkg/handlers/app.go @@ -9,6 +9,7 @@ import ( "strings" "time" + "github.com/gorilla/mux" "github.com/pkg/errors" appstatetypes "github.com/replicatedhq/replicated-sdk/pkg/appstate/types" "github.com/replicatedhq/replicated-sdk/pkg/config" @@ -18,15 +19,16 @@ import ( "github.com/replicatedhq/replicated-sdk/pkg/k8sutil" sdklicense "github.com/replicatedhq/replicated-sdk/pkg/license" "github.com/replicatedhq/replicated-sdk/pkg/logger" + "github.com/replicatedhq/replicated-sdk/pkg/meta" + "github.com/replicatedhq/replicated-sdk/pkg/meta/types" "github.com/replicatedhq/replicated-sdk/pkg/report" "github.com/replicatedhq/replicated-sdk/pkg/store" - "github.com/replicatedhq/replicated-sdk/pkg/tags" - "github.com/replicatedhq/replicated-sdk/pkg/tags/types" "github.com/replicatedhq/replicated-sdk/pkg/upstream" upstreamtypes "github.com/replicatedhq/replicated-sdk/pkg/upstream/types" "github.com/replicatedhq/replicated-sdk/pkg/util" helmrelease "helm.sh/helm/v3/pkg/release" "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" + "k8s.io/client-go/kubernetes" "k8s.io/client-go/kubernetes/scheme" ) @@ -352,6 +354,12 @@ func mockReleaseToAppRelease(mockRelease integrationtypes.MockRelease) AppReleas return appRelease } +var testClientSet kubernetes.Interface + +func SetTestClientSet(clientset kubernetes.Interface) { + testClientSet = clientset +} + func SendCustomAppMetrics(w http.ResponseWriter, r *http.Request) { request := SendCustomAppMetricsRequest{} if err := json.NewDecoder(r.Body).Decode(&request); err != nil { @@ -366,6 +374,43 @@ func SendCustomAppMetrics(w http.ResponseWriter, r *http.Request) { return } + var clientset kubernetes.Interface + if testClientSet != nil { + clientset = testClientSet + } else { + var err error + clientset, err = k8sutil.GetClientset() + if err != nil { + logger.Error(errors.Wrap(err, "failed to get clientset")) + w.WriteHeader(http.StatusInternalServerError) + return + } + } + + overwrite := true + if r.Method == http.MethodPatch { + overwrite = false + } + + if err := report.SendCustomAppMetrics(clientset, store.GetStore(), request.Data, overwrite); err != nil { + logger.Error(errors.Wrap(err, "set application data")) + w.WriteHeader(http.StatusBadRequest) + return + } + + JSON(w, http.StatusOK, "") +} + +func DeleteCustomAppMetricsKey(w http.ResponseWriter, r *http.Request) { + key, ok := mux.Vars(r)["key"] + + if !ok || key == "" { + w.WriteHeader(http.StatusBadRequest) + fmt.Fprintf(w, "key cannot be empty") + logger.Errorf("cannot delete custom metrics key - key cannot be empty") + return + } + clientset, err := k8sutil.GetClientset() if err != nil { logger.Error(errors.Wrap(err, "failed to get clientset")) @@ -373,15 +418,16 @@ func SendCustomAppMetrics(w http.ResponseWriter, r *http.Request) { return } - if err := report.SendCustomAppMetrics(clientset, store.GetStore(), request.Data); err != nil { - logger.Error(errors.Wrap(err, "set application data")) + data := map[string]interface{}{key: nil} + + if err := report.SendCustomAppMetrics(clientset, store.GetStore(), data, false); err != nil { + logger.Error(errors.Wrapf(err, "failed to delete custom merics key: %s", key)) w.WriteHeader(http.StatusBadRequest) return } - JSON(w, http.StatusOK, "") + JSON(w, http.StatusNoContent, "") } - func validateCustomAppMetricsData(data CustomAppMetricsData) error { if len(data) == 0 { return errors.New("no data provided") @@ -429,7 +475,7 @@ func SendAppInstanceTags(w http.ResponseWriter, r *http.Request) { return } - if err := tags.Save(r.Context(), clientset, store.GetStore().GetNamespace(), request.Data); err != nil { + if err := meta.SaveInstanceTag(r.Context(), clientset, store.GetStore().GetNamespace(), request.Data); err != nil { logger.Errorf("failed to save instance tags: %v", err) w.WriteHeader(http.StatusInternalServerError) return diff --git a/pkg/k8sutil/fake.go b/pkg/k8sutil/fake.go index 9368ee6c..d76cf219 100644 --- a/pkg/k8sutil/fake.go +++ b/pkg/k8sutil/fake.go @@ -14,6 +14,7 @@ func CreateTestDeployment(name string, namespace string, revision string, matchL Annotations: map[string]string{ "deployment.kubernetes.io/revision": revision, }, + UID: "test-deployment-uid", }, Spec: appsv1.DeploymentSpec{ Selector: &metav1.LabelSelector{ @@ -31,6 +32,7 @@ func CreateTestReplicaSet(name string, namespace string, revision string) *appsv Annotations: map[string]string{ "deployment.kubernetes.io/revision": revision, }, + UID: "test-deployment-uid", }, } } @@ -38,6 +40,7 @@ func CreateTestReplicaSet(name string, namespace string, revision string) *appsv func CreateTestPod(name string, namespace string, replicaSetName string, labels map[string]string) *corev1.Pod { return &corev1.Pod{ ObjectMeta: metav1.ObjectMeta{ + UID: "test-deployment-uid", Name: name, Namespace: namespace, Labels: labels, diff --git a/pkg/meta/instance_tags.go b/pkg/meta/instance_tags.go new file mode 100644 index 00000000..f82eb4ee --- /dev/null +++ b/pkg/meta/instance_tags.go @@ -0,0 +1,28 @@ +package meta + +import ( + "context" + + "github.com/pkg/errors" + "github.com/replicatedhq/replicated-sdk/pkg/meta/types" + "k8s.io/client-go/kubernetes" +) + +const ( + instanceTagSecretKey replicatedMetadataSecretKey = "instance-tag-data" +) + +func SaveInstanceTag(ctx context.Context, clientset kubernetes.Interface, namespace string, tdata types.InstanceTagData) error { + return save(ctx, clientset, namespace, instanceTagSecretKey, tdata) +} + +func GetInstanceTag(ctx context.Context, clientset kubernetes.Interface, namespace string) (*types.InstanceTagData, error) { + t := types.InstanceTagData{} + + if err := get(ctx, clientset, namespace, instanceTagSecretKey, &t); err != nil { + return nil, errors.Wrapf(err, "failed to get instance tag data") + } + + return &t, nil + +} diff --git a/pkg/meta/latest_custom_metrics.go b/pkg/meta/latest_custom_metrics.go new file mode 100644 index 00000000..55bf8fbc --- /dev/null +++ b/pkg/meta/latest_custom_metrics.go @@ -0,0 +1,59 @@ +package meta + +import ( + "context" + "maps" + + "github.com/pkg/errors" + "k8s.io/client-go/kubernetes" +) + +const ( + customMetricsSecretKey replicatedMetadataSecretKey = "latest-custom-metrics" +) + +func SyncCustomAppMetrics(ctx context.Context, clientset kubernetes.Interface, namespace string, inboundMetrics map[string]interface{}, overwrite bool) (map[string]interface{}, error) { + existing := map[string]interface{}{} + + err := get(ctx, clientset, namespace, customMetricsSecretKey, &existing) + if err != nil && errors.Cause(err) != ErrReplicatedMetadataSecretNotFound { + return nil, errors.Wrapf(err, "failed to get custom metrics data") + } + + modified := mergeCustomAppMetrics(existing, inboundMetrics, overwrite) + + if err := save(ctx, clientset, namespace, customMetricsSecretKey, modified); err != nil { + return nil, errors.Wrap(err, "failed to save custom metrics") + } + + return modified, nil +} + +func mergeCustomAppMetrics(existingMetrics map[string]interface{}, inboundMetrics map[string]interface{}, overwrite bool) map[string]interface{} { + if existingMetrics == nil { + existingMetrics = map[string]interface{}{} + } + + if inboundMetrics == nil { + inboundMetrics = map[string]interface{}{} + } + + if overwrite { + return inboundMetrics + } + + if len(inboundMetrics) == 0 || maps.Equal(existingMetrics, inboundMetrics) { + return existingMetrics + } + + for k, v := range inboundMetrics { + if v == nil { + delete(existingMetrics, k) + continue + } + + existingMetrics[k] = v + } + + return existingMetrics +} diff --git a/pkg/meta/latest_custom_metrics_test.go b/pkg/meta/latest_custom_metrics_test.go new file mode 100644 index 00000000..99bcc21d --- /dev/null +++ b/pkg/meta/latest_custom_metrics_test.go @@ -0,0 +1,83 @@ +package meta + +import ( + "testing" + + "github.com/stretchr/testify/assert" +) + +func Test_mergeCustomAppMetrics(tst *testing.T) { + tests := []struct { + name string + existingMetrics map[string]interface{} + inboundMetrics map[string]interface{} + overwrite bool + assertFn func(*testing.T, map[string]interface{}) + }{ + { + name: "should return empty if both are empty", + existingMetrics: map[string]interface{}{}, + inboundMetrics: map[string]interface{}{}, + overwrite: false, + assertFn: func(t *testing.T, actual map[string]interface{}) { + assert.NotNil(t, actual) + assert.Empty(t, actual) + }, + }, + { + name: "should tolerate nil value on existingMetrics", + existingMetrics: nil, + inboundMetrics: map[string]interface{}{"numProjects": 10}, + overwrite: false, + assertFn: func(t *testing.T, actual map[string]interface{}) { + expected := map[string]interface{}{"numProjects": 10} + assert.Equal(t, expected, actual) + }, + }, + { + name: "should tolerate nil value on inboundMetrics", + existingMetrics: map[string]interface{}{"numProjects": 10}, + inboundMetrics: nil, + overwrite: false, + assertFn: func(t *testing.T, actual map[string]interface{}) { + expected := map[string]interface{}{"numProjects": 10} + assert.Equal(t, expected, actual) + }, + }, + { + name: "should return inboundMetrics when overwrite is true", + existingMetrics: map[string]interface{}{"numProjects": 10, "token": "1234"}, + inboundMetrics: map[string]interface{}{"newProjects": 100, "newToken": 10}, + overwrite: true, // overwrites existing metric data with inbound metrics data + assertFn: func(t *testing.T, actual map[string]interface{}) { + expected := map[string]interface{}{"newProjects": 100, "newToken": 10} + assert.Equal(t, expected, actual) + }, + }, + { + name: "should return merged data when overwrite is false", + existingMetrics: map[string]interface{}{"numProjects": 10, "token": "1234"}, + inboundMetrics: map[string]interface{}{"numProjects": 66666, "numPeople": 100}, + overwrite: false, + assertFn: func(t *testing.T, actual map[string]interface{}) { + expected := map[string]interface{}{"numPeople": 100, "numProjects": 66666, "token": "1234"} + assert.Equal(t, expected, actual) + }, + }, + { + name: "should delete existing metric key when the corresponding inboundMetrics value is nil", + existingMetrics: map[string]interface{}{"numProjects": 10, "token": "1234"}, + inboundMetrics: map[string]interface{}{"numProjects": nil}, // delete numProjects + overwrite: false, + assertFn: func(t *testing.T, actual map[string]interface{}) { + expected := map[string]interface{}{"token": "1234"} + assert.Equal(t, expected, actual) + }, + }, + } + + for _, tt := range tests { + m := mergeCustomAppMetrics(tt.existingMetrics, tt.inboundMetrics, tt.overwrite) + tt.assertFn(tst, m) + } +} diff --git a/pkg/tags/instance_tag_data.go b/pkg/meta/meta.go similarity index 52% rename from pkg/tags/instance_tag_data.go rename to pkg/meta/meta.go index bc4c8e4a..24465804 100644 --- a/pkg/tags/instance_tag_data.go +++ b/pkg/meta/meta.go @@ -1,11 +1,11 @@ -package tags +package meta import ( "context" + "encoding/json" "sync" "github.com/pkg/errors" - "github.com/replicatedhq/replicated-sdk/pkg/tags/types" "github.com/replicatedhq/replicated-sdk/pkg/util" corev1 "k8s.io/api/core/v1" kuberneteserrors "k8s.io/apimachinery/pkg/api/errors" @@ -13,24 +13,29 @@ import ( "k8s.io/client-go/kubernetes" ) +type replicatedMetadataSecretKey string + +func (m replicatedMetadataSecretKey) String() string { + return string(m) +} + const ( - InstanceMetadataSecretName = "replicated-meta-data" - InstanceTagSecretKey = "instance-tag-data" + ReplicatedMetadataSecretName string = "replicated-meta-data" ) var replicatedSecretLock = sync.Mutex{} -func Save(ctx context.Context, clientset kubernetes.Interface, namespace string, tdata types.InstanceTagData) error { +func save(ctx context.Context, clientset kubernetes.Interface, namespace string, key replicatedMetadataSecretKey, data interface{}) error { replicatedSecretLock.Lock() defer replicatedSecretLock.Unlock() - encodedTagData, err := tdata.MarshalBase64() + encodedData, err := json.Marshal(data) if err != nil { return errors.Wrap(err, "failed to marshal instance tags") } - existingSecret, err := clientset.CoreV1().Secrets(namespace).Get(ctx, InstanceMetadataSecretName, metav1.GetOptions{}) + existingSecret, err := clientset.CoreV1().Secrets(namespace).Get(ctx, ReplicatedMetadataSecretName, metav1.GetOptions{}) if err != nil && !kuberneteserrors.IsNotFound(err) { return errors.Wrap(err, "failed to get instance-tags secret") } @@ -47,7 +52,7 @@ func Save(ctx context.Context, clientset kubernetes.Interface, namespace string, Kind: "Secret", }, ObjectMeta: metav1.ObjectMeta{ - Name: InstanceMetadataSecretName, + Name: string(ReplicatedMetadataSecretName), Namespace: namespace, OwnerReferences: []metav1.OwnerReference{ { @@ -59,13 +64,13 @@ func Save(ctx context.Context, clientset kubernetes.Interface, namespace string, }, }, Data: map[string][]byte{ - InstanceTagSecretKey: encodedTagData, + string(key): encodedData, }, } _, err = clientset.CoreV1().Secrets(namespace).Create(ctx, secret, metav1.CreateOptions{}) if err != nil { - return errors.Wrap(err, "failed to create report secret") + return errors.Wrap(err, "failed to create meta secret") } return nil } @@ -74,44 +79,43 @@ func Save(ctx context.Context, clientset kubernetes.Interface, namespace string, existingSecret.Data = map[string][]byte{} } - existingSecret.Data[InstanceTagSecretKey] = encodedTagData + existingSecret.Data[string(key)] = encodedData _, err = clientset.CoreV1().Secrets(namespace).Update(ctx, existingSecret, metav1.UpdateOptions{}) if err != nil { - return errors.Wrap(err, "failed to update instance-tags secret") + return errors.Wrapf(err, "failed to update replicated-meta-data secret with key %s", key) } return nil } var ( - ErrInstanceTagDataIsEmpty = errors.New("instance tag data is empty") - ErrInstanceTagDataSecretNotFound = errors.New("instance tag secret not found") + ErrReplicatedMetadataSecretEmpty = errors.New("replicated metadata secret is empty") + ErrReplicatedMetadataSecretNotFound = errors.New("replicated metadata secret not found") ) -func Get(ctx context.Context, clientset kubernetes.Interface, namespace string) (*types.InstanceTagData, error) { - secret, err := clientset.CoreV1().Secrets(namespace).Get(ctx, InstanceMetadataSecretName, metav1.GetOptions{}) +func get(ctx context.Context, clientset kubernetes.Interface, namespace string, key replicatedMetadataSecretKey, v interface{}) error { + secret, err := clientset.CoreV1().Secrets(namespace).Get(ctx, ReplicatedMetadataSecretName, metav1.GetOptions{}) if err != nil && !kuberneteserrors.IsNotFound(err) { - return nil, errors.Wrap(err, "failed to get instance-tags secret") + return errors.Wrap(err, "failed to get replicated-meta-data secret") } if kuberneteserrors.IsNotFound(err) { - return nil, ErrInstanceTagDataSecretNotFound + return ErrReplicatedMetadataSecretNotFound } if len(secret.Data) == 0 { - return nil, ErrInstanceTagDataIsEmpty + return ErrReplicatedMetadataSecretEmpty } - tagDataBytes, ok := secret.Data[InstanceTagSecretKey] - if !ok || len(tagDataBytes) == 0 { - return nil, ErrInstanceTagDataIsEmpty + dataBytes, ok := secret.Data[string(key)] + if !ok || len(dataBytes) == 0 { + return errors.Wrapf(ErrReplicatedMetadataSecretEmpty, "key (%s) not found in secret", key) } - tagData := &types.InstanceTagData{} - if err := tagData.UnmarshalBase64(tagDataBytes); err != nil { - return nil, errors.Wrap(err, "failed to unmarshal instance tags") + if err := json.Unmarshal(dataBytes, v); err != nil { + return errors.Wrapf(err, "failed to unmarshal secret data for key %s", key) } - return tagData, nil + return nil } diff --git a/pkg/tags/types/types.go b/pkg/meta/types/types.go similarity index 100% rename from pkg/tags/types/types.go rename to pkg/meta/types/types.go diff --git a/pkg/tags/types/types_test.go b/pkg/meta/types/types_test.go similarity index 100% rename from pkg/tags/types/types_test.go rename to pkg/meta/types/types_test.go diff --git a/pkg/report/custom_app_metrics.go b/pkg/report/custom_app_metrics.go index b44aac17..5484cc09 100644 --- a/pkg/report/custom_app_metrics.go +++ b/pkg/report/custom_app_metrics.go @@ -2,6 +2,7 @@ package report import ( "bytes" + "context" "encoding/json" "fmt" "io" @@ -10,16 +11,23 @@ import ( "time" "github.com/pkg/errors" + "github.com/replicatedhq/replicated-sdk/pkg/meta" "github.com/replicatedhq/replicated-sdk/pkg/store" "github.com/replicatedhq/replicated-sdk/pkg/util" "k8s.io/client-go/kubernetes" ) -func SendCustomAppMetrics(clientset kubernetes.Interface, sdkStore store.Store, data map[string]interface{}) error { +func SendCustomAppMetrics(clientset kubernetes.Interface, sdkStore store.Store, data map[string]interface{}, overwrite bool) error { + + syncedMetrics, err := meta.SyncCustomAppMetrics(context.Background(), clientset, sdkStore.GetNamespace(), data, overwrite) + if err != nil { + return errors.Wrap(err, "failed to sync custom app metrics") + } + if util.IsAirgap() { - return SendAirgapCustomAppMetrics(clientset, sdkStore, data) + return SendAirgapCustomAppMetrics(clientset, sdkStore, syncedMetrics) } - return SendOnlineCustomAppMetrics(sdkStore, data) + return SendOnlineCustomAppMetrics(sdkStore, syncedMetrics) } func SendAirgapCustomAppMetrics(clientset kubernetes.Interface, sdkStore store.Store, data map[string]interface{}) error { diff --git a/pkg/report/instance.go b/pkg/report/instance.go index 92fca726..a4e10d33 100644 --- a/pkg/report/instance.go +++ b/pkg/report/instance.go @@ -15,9 +15,9 @@ import ( "github.com/replicatedhq/replicated-sdk/pkg/buildversion" "github.com/replicatedhq/replicated-sdk/pkg/k8sutil" "github.com/replicatedhq/replicated-sdk/pkg/logger" + meta "github.com/replicatedhq/replicated-sdk/pkg/meta" "github.com/replicatedhq/replicated-sdk/pkg/report/types" "github.com/replicatedhq/replicated-sdk/pkg/store" - "github.com/replicatedhq/replicated-sdk/pkg/tags" "github.com/replicatedhq/replicated-sdk/pkg/util" "k8s.io/client-go/kubernetes" ) @@ -150,7 +150,7 @@ func GetInstanceData(sdkStore store.Store) *types.InstanceData { r.K8sDistribution = distribution.String() } - if tdata, err := tags.Get(context.TODO(), clientset, sdkStore.GetNamespace()); err != nil { + if tdata, err := meta.GetInstanceTag(context.TODO(), clientset, sdkStore.GetNamespace()); err != nil { logger.Debugf("failed to get instance tag data: %v", err.Error()) } else { r.Tags = *tdata diff --git a/pkg/report/types/types.go b/pkg/report/types/types.go index a4a8c9aa..5d56ff35 100644 --- a/pkg/report/types/types.go +++ b/pkg/report/types/types.go @@ -2,7 +2,7 @@ package types import ( appstatetypes "github.com/replicatedhq/replicated-sdk/pkg/appstate/types" - tagstypes "github.com/replicatedhq/replicated-sdk/pkg/tags/types" + metatypes "github.com/replicatedhq/replicated-sdk/pkg/meta/types" ) type Distribution int64 @@ -35,7 +35,7 @@ type InstanceData struct { ResourceStates appstatetypes.ResourceStates `json:"resource_states"` K8sVersion string `json:"k8s_version"` K8sDistribution string `json:"k8s_distribution"` - Tags tagstypes.InstanceTagData `json:"tags"` + Tags metatypes.InstanceTagData `json:"tags"` } func (d Distribution) String() string { diff --git a/pkg/report/util_test.go b/pkg/report/util_test.go index 98498d2a..e1d07785 100644 --- a/pkg/report/util_test.go +++ b/pkg/report/util_test.go @@ -5,8 +5,8 @@ import ( appstatetypes "github.com/replicatedhq/replicated-sdk/pkg/appstate/types" "github.com/replicatedhq/replicated-sdk/pkg/k8sutil" + metatypes "github.com/replicatedhq/replicated-sdk/pkg/meta/types" "github.com/replicatedhq/replicated-sdk/pkg/report/types" - tagstypes "github.com/replicatedhq/replicated-sdk/pkg/tags/types" "github.com/replicatedhq/replicated-sdk/pkg/util" "github.com/stretchr/testify/assert" "k8s.io/client-go/kubernetes/fake" @@ -71,7 +71,7 @@ func TestGetInstanceDataHeaders(t *testing.T) { ChannelSequence: 42, K8sVersion: "v1.20.2+k3s1", K8sDistribution: "k3s", - Tags: tagstypes.InstanceTagData{Force: true, Tags: map[string]string{"key": "value"}}, + Tags: metatypes.InstanceTagData{Force: true, Tags: map[string]string{"key": "value"}}, } headers := GetInstanceDataHeaders(instanceData)