diff --git a/api/constants/constants.go b/api/constants/constants.go index 0ec2102df..4c00744f7 100644 --- a/api/constants/constants.go +++ b/api/constants/constants.go @@ -17,6 +17,54 @@ var ( EulaMessage string ) +const ( + FullGroupName = "symphony" + + // system annotations, reserved and should not be modified by client. + AzureCorrelationIdKey = "management.azure.com/correlationId" + AzureEdgeLocationKey = "management.azure.com/customLocation" + AzureOperationIdKey = "management.azure.com/operationId" + AzureNameIdKey = "management.azure.com/azureName" + AzureResourceIdKey = "management.azure.com/resourceId" + AzureSystemDataKey = "management.azure.com/systemData" + AzureTenantIdKey = "management.azure.com/tenantId" // Not used + RunningAzureCorrelationIdKey = "management.azure.com/runningCorrelationId" + SummaryJobIdKey = "SummaryJobIdKey" + OperationStartTimeKeyPostfix = FullGroupName + "/started-at" // instance/target + + ProviderName = "management.azure.com/provider-name" +) + +func SystemReservedAnnotations() []string { + return []string{ + AzureCorrelationIdKey, + AzureEdgeLocationKey, + AzureOperationIdKey, + AzureNameIdKey, + AzureResourceIdKey, + AzureSystemDataKey, + AzureTenantIdKey, + RunningAzureCorrelationIdKey, + SummaryJobIdKey, + OperationStartTimeKeyPostfix, + } +} + +func SystemReservedLabels() []string { + return []string{ + Campaign, + DisplayName, + ProviderName, + ManagerMetaKey, + ParentName, + RootResource, + Solution, + StagedTarget, + StatusMessage, + Target, + } +} + const ( DefaultScope = "default" SATokenPath = "/var/run/secrets/tokens/symphony-api-token" @@ -33,6 +81,7 @@ const ( Solution = "solution" Target = "target" Campaign = "campaign" + StagedTarget = "staged_target" ) // Environment variables keys diff --git a/api/pkg/apis/v1alpha1/managers/activations/activations-manager.go b/api/pkg/apis/v1alpha1/managers/activations/activations-manager.go index b0bfb2f0e..6f04d5812 100644 --- a/api/pkg/apis/v1alpha1/managers/activations/activations-manager.go +++ b/api/pkg/apis/v1alpha1/managers/activations/activations-manager.go @@ -93,15 +93,16 @@ func (m *ActivationsManager) GetState(ctx context.Context, name string, namespac return model.ActivationState{}, err } var ret model.ActivationState - ret, err = getActivationState(entry.Body, entry.ETag) + ret, err = getActivationState(entry.Body) if err != nil { log.ErrorfCtx(ctx, "Failed to convert to activation state for %s in namespace %s: %v", name, namespace, err) return model.ActivationState{}, err } + ret.ObjectMeta.UpdateEtag(entry.ETag) return ret, nil } -func getActivationState(body interface{}, etag string) (model.ActivationState, error) { +func getActivationState(body interface{}) (model.ActivationState, error) { var activationState model.ActivationState bytes, _ := json.Marshal(body) err := json.Unmarshal(bytes, &activationState) @@ -111,7 +112,6 @@ func getActivationState(body interface{}, etag string) (model.ActivationState, e if activationState.Spec == nil { activationState.Spec = &model.ActivationSpec{} } - activationState.ObjectMeta.ETag = etag if activationState.Status == nil { activationState.Status = &model.ActivationStatus{} } @@ -134,6 +134,11 @@ func (m *ActivationsManager) UpsertState(ctx context.Context, name string, state } state.ObjectMeta.FixNames(name) + oldState, getStateErr := m.GetState(ctx, state.ObjectMeta.Name, state.ObjectMeta.Namespace) + if getStateErr == nil { + state.ObjectMeta.PreserveSystemMetadata(oldState.ObjectMeta) + } + if m.needValidate { if state.ObjectMeta.Labels == nil { state.ObjectMeta.Labels = make(map[string]string) @@ -141,7 +146,7 @@ func (m *ActivationsManager) UpsertState(ctx context.Context, name string, state if state.Spec != nil { state.ObjectMeta.Labels[constants.Campaign] = state.Spec.Campaign } - if err = m.ValidateCreateOrUpdate(ctx, state); err != nil { + if err = validation.ValidateCreateOrUpdateWrapper(ctx, &m.Validator, state, oldState, getStateErr); err != nil { return err } } @@ -221,10 +226,11 @@ func (t *ActivationsManager) ListState(ctx context.Context, namespace string) ([ ret := make([]model.ActivationState, 0) for _, t := range activations { var rt model.ActivationState - rt, err = getActivationState(t.Body, t.ETag) + rt, err = getActivationState(t.Body) if err != nil { return nil, err } + rt.ObjectMeta.UpdateEtag(t.ETag) ret = append(ret, rt) } log.InfofCtx(ctx, "List activation state for namespace %s get total count %d", namespace, len(ret)) @@ -259,6 +265,7 @@ func (t *ActivationsManager) ReportStatus(ctx context.Context, name string, name var entry states.StateEntry entry.ID = activationState.ObjectMeta.Name entry.Body = activationState + entry.ETag = activationState.ObjectMeta.ETag // We need to set the ETag here because we need to update the labels and status upsertRequest := states.UpsertRequest{ Value: entry, @@ -312,6 +319,7 @@ func (t *ActivationsManager) ReportStageStatus(ctx context.Context, name string, var entry states.StateEntry entry.ID = activationState.ObjectMeta.Name entry.Body = activationState + entry.ETag = activationState.ObjectMeta.ETag // We need to set the ETag here because we need to update the labels and status upsertRequest := states.UpsertRequest{ Value: entry, @@ -417,11 +425,6 @@ func mergeStageStatus(ctx context.Context, activationState *model.ActivationStat return nil } -func (t *ActivationsManager) ValidateCreateOrUpdate(ctx context.Context, state model.ActivationState) error { - old, err := t.GetState(ctx, state.ObjectMeta.Name, state.ObjectMeta.Namespace) - return validation.ValidateCreateOrUpdateWrapper(ctx, &t.Validator, state, old, err) -} - func (t *ActivationsManager) CampaignLookup(ctx context.Context, name string, namespace string) (interface{}, error) { return states.GetObjectState(ctx, t.StateProvider, validation.Campaign, name, namespace) } diff --git a/api/pkg/apis/v1alpha1/managers/campaigncontainers/campaign-container-manager.go b/api/pkg/apis/v1alpha1/managers/campaigncontainers/campaign-container-manager.go index c6d646e90..2a3ea824f 100644 --- a/api/pkg/apis/v1alpha1/managers/campaigncontainers/campaign-container-manager.go +++ b/api/pkg/apis/v1alpha1/managers/campaigncontainers/campaign-container-manager.go @@ -78,6 +78,11 @@ func (t *CampaignContainersManager) UpsertState(ctx context.Context, name string } state.ObjectMeta.FixNames(name) + oldState, getStateErr := t.GetState(ctx, state.ObjectMeta.Name, state.ObjectMeta.Namespace) + if getStateErr == nil { + state.ObjectMeta.PreserveSystemMetadata(oldState.ObjectMeta) + } + body := map[string]interface{}{ "apiVersion": model.WorkflowGroup + "/v1", "kind": "CampaignContainer", @@ -89,7 +94,7 @@ func (t *CampaignContainersManager) UpsertState(ctx context.Context, name string Value: states.StateEntry{ ID: name, Body: body, - ETag: "", + ETag: state.ObjectMeta.ETag, }, Metadata: map[string]interface{}{ "namespace": state.ObjectMeta.Namespace, @@ -131,16 +136,17 @@ func (t *CampaignContainersManager) ListState(ctx context.Context, namespace str ret := make([]model.CampaignContainerState, 0) for _, t := range campaigncontainers { var rt model.CampaignContainerState - rt, err = getCampaignContainerState(t.Body, t.ETag) + rt, err = getCampaignContainerState(t.Body) if err != nil { return nil, err } + rt.ObjectMeta.UpdateEtag(t.ETag) ret = append(ret, rt) } return ret, nil } -func getCampaignContainerState(body interface{}, etag string) (model.CampaignContainerState, error) { +func getCampaignContainerState(body interface{}) (model.CampaignContainerState, error) { var CampaignContainerState model.CampaignContainerState bytes, _ := json.Marshal(body) err := json.Unmarshal(bytes, &CampaignContainerState) @@ -177,9 +183,10 @@ func (t *CampaignContainersManager) GetState(ctx context.Context, id string, nam return model.CampaignContainerState{}, err } var ret model.CampaignContainerState - ret, err = getCampaignContainerState(Campaign.Body, Campaign.ETag) + ret, err = getCampaignContainerState(Campaign.Body) if err != nil { return model.CampaignContainerState{}, err } + ret.ObjectMeta.UpdateEtag(Campaign.ETag) return ret, nil } diff --git a/api/pkg/apis/v1alpha1/managers/campaigns/campaigns-manager.go b/api/pkg/apis/v1alpha1/managers/campaigns/campaigns-manager.go index 4a7993b14..1334b245c 100644 --- a/api/pkg/apis/v1alpha1/managers/campaigns/campaigns-manager.go +++ b/api/pkg/apis/v1alpha1/managers/campaigns/campaigns-manager.go @@ -85,6 +85,7 @@ func (m *CampaignsManager) GetState(ctx context.Context, name string, namespace log.ErrorfCtx(ctx, "Failed to convert to campaign state for %s in namespace %s: %v", name, namespace, err) return model.CampaignState{}, err } + ret.ObjectMeta.UpdateEtag(entry.ETag) return ret, nil } @@ -115,6 +116,11 @@ func (m *CampaignsManager) UpsertState(ctx context.Context, name string, state m } state.ObjectMeta.FixNames(name) + oldState, getStateErr := m.GetState(ctx, state.ObjectMeta.Name, state.ObjectMeta.Namespace) + if getStateErr == nil { + state.ObjectMeta.PreserveSystemMetadata(oldState.ObjectMeta) + } + if m.needValidate { if state.ObjectMeta.Labels == nil { state.ObjectMeta.Labels = make(map[string]string) @@ -122,7 +128,7 @@ func (m *CampaignsManager) UpsertState(ctx context.Context, name string, state m if state.Spec != nil { state.ObjectMeta.Labels[constants.RootResource] = state.Spec.RootResource } - if err = m.ValidateCreateOrUpdate(ctx, state); err != nil { + if err = validation.ValidateCreateOrUpdateWrapper(ctx, &m.CampaignValidator, state, oldState, getStateErr); err != nil { return err } } @@ -136,6 +142,7 @@ func (m *CampaignsManager) UpsertState(ctx context.Context, name string, state m "metadata": state.ObjectMeta, "spec": state.Spec, }, + ETag: state.ObjectMeta.ETag, }, Metadata: map[string]interface{}{ "namespace": state.ObjectMeta.Namespace, @@ -207,17 +214,13 @@ func (t *CampaignsManager) ListState(ctx context.Context, namespace string) ([]m if err != nil { return nil, err } + rt.ObjectMeta.UpdateEtag(t.ETag) ret = append(ret, rt) } log.InfofCtx(ctx, "List campaign state for namespace %s get total count %d", namespace, len(ret)) return ret, nil } -func (t *CampaignsManager) ValidateCreateOrUpdate(ctx context.Context, state model.CampaignState) error { - old, err := t.GetState(ctx, state.ObjectMeta.Name, state.ObjectMeta.Namespace) - return validation.ValidateCreateOrUpdateWrapper(ctx, &t.CampaignValidator, state, old, err) -} - func (t *CampaignsManager) ValidateDelete(ctx context.Context, name string, namespace string) error { state, err := t.GetState(ctx, name, namespace) return validation.ValidateDeleteWrapper(ctx, &t.CampaignValidator, state, err) diff --git a/api/pkg/apis/v1alpha1/managers/catalogcontainers/catalog-container-manager.go b/api/pkg/apis/v1alpha1/managers/catalogcontainers/catalog-container-manager.go index 244693d46..5163d9238 100644 --- a/api/pkg/apis/v1alpha1/managers/catalogcontainers/catalog-container-manager.go +++ b/api/pkg/apis/v1alpha1/managers/catalogcontainers/catalog-container-manager.go @@ -78,6 +78,11 @@ func (t *CatalogContainersManager) UpsertState(ctx context.Context, name string, } state.ObjectMeta.FixNames(name) + oldState, getStateErr := t.GetState(ctx, state.ObjectMeta.Name, state.ObjectMeta.Namespace) + if getStateErr == nil { + state.ObjectMeta.PreserveSystemMetadata(oldState.ObjectMeta) + } + body := map[string]interface{}{ "apiVersion": model.FederationGroup + "/v1", "kind": "CatalogContainer", @@ -89,7 +94,7 @@ func (t *CatalogContainersManager) UpsertState(ctx context.Context, name string, Value: states.StateEntry{ ID: name, Body: body, - ETag: "", + ETag: state.ObjectMeta.ETag, }, Metadata: map[string]interface{}{ "namespace": state.ObjectMeta.Namespace, @@ -131,16 +136,17 @@ func (t *CatalogContainersManager) ListState(ctx context.Context, namespace stri ret := make([]model.CatalogContainerState, 0) for _, t := range catalogcontainers { var rt model.CatalogContainerState - rt, err = getCatalogContainerState(t.Body, t.ETag) + rt, err = getCatalogContainerState(t.Body) if err != nil { return nil, err } + rt.ObjectMeta.UpdateEtag(t.ETag) ret = append(ret, rt) } return ret, nil } -func getCatalogContainerState(body interface{}, etag string) (model.CatalogContainerState, error) { +func getCatalogContainerState(body interface{}) (model.CatalogContainerState, error) { var CatalogContainerState model.CatalogContainerState bytes, _ := json.Marshal(body) err := json.Unmarshal(bytes, &CatalogContainerState) @@ -171,15 +177,16 @@ func (t *CatalogContainersManager) GetState(ctx context.Context, id string, name "kind": "CatalogContainer", }, } - var Campaign states.StateEntry - Campaign, err = t.StateProvider.Get(ctx, getRequest) + var entry states.StateEntry + entry, err = t.StateProvider.Get(ctx, getRequest) if err != nil { return model.CatalogContainerState{}, err } var ret model.CatalogContainerState - ret, err = getCatalogContainerState(Campaign.Body, Campaign.ETag) + ret, err = getCatalogContainerState(entry.Body) if err != nil { return model.CatalogContainerState{}, err } + ret.ObjectMeta.UpdateEtag(entry.ETag) return ret, nil } diff --git a/api/pkg/apis/v1alpha1/managers/catalogs/catalogs-manager.go b/api/pkg/apis/v1alpha1/managers/catalogs/catalogs-manager.go index c857147ec..623d2ca64 100644 --- a/api/pkg/apis/v1alpha1/managers/catalogs/catalogs-manager.go +++ b/api/pkg/apis/v1alpha1/managers/catalogs/catalogs-manager.go @@ -85,14 +85,15 @@ func (s *CatalogsManager) GetState(ctx context.Context, name string, namespace s return model.CatalogState{}, err } var ret model.CatalogState - ret, err = getCatalogState(entry.Body, entry.ETag) + ret, err = getCatalogState(entry.Body) if err != nil { return model.CatalogState{}, err } + ret.ObjectMeta.UpdateEtag(entry.ETag) return ret, nil } -func getCatalogState(body interface{}, etag string) (model.CatalogState, error) { +func getCatalogState(body interface{}) (model.CatalogState, error) { var catalogState model.CatalogState bytes, _ := json.Marshal(body) err := json.Unmarshal(bytes, &catalogState) @@ -102,7 +103,6 @@ func getCatalogState(body interface{}, etag string) (model.CatalogState, error) if catalogState.Spec == nil { catalogState.Spec = &model.CatalogSpec{} } - catalogState.ObjectMeta.ETag = etag if catalogState.Status == nil { catalogState.Status = &model.CatalogStatus{} } @@ -122,6 +122,11 @@ func (m *CatalogsManager) UpsertState(ctx context.Context, name string, state mo } state.ObjectMeta.FixNames(name) + oldState, getStateErr := m.GetState(ctx, state.ObjectMeta.Name, state.ObjectMeta.Namespace) + if getStateErr == nil { + state.ObjectMeta.PreserveSystemMetadata(oldState.ObjectMeta) + } + if m.needValidate { if state.ObjectMeta.Labels == nil { state.ObjectMeta.Labels = make(map[string]string) @@ -132,7 +137,7 @@ func (m *CatalogsManager) UpsertState(ctx context.Context, name string, state mo state.ObjectMeta.Labels[constants.ParentName] = validation.ConvertReferenceToObjectName(state.Spec.ParentName) } } - if err = m.ValidateCreateOrUpdate(ctx, state); err != nil { + if err = validation.ValidateCreateOrUpdateWrapper(ctx, &m.CatalogValidator, state, oldState, getStateErr); err != nil { return err } } @@ -229,10 +234,11 @@ func (t *CatalogsManager) ListState(ctx context.Context, namespace string, filte ret := make([]model.CatalogState, 0) for _, t := range catalogs { var rt model.CatalogState - rt, err = getCatalogState(t.Body, t.ETag) + rt, err = getCatalogState(t.Body) if err != nil { return nil, err } + rt.ObjectMeta.UpdateEtag(t.ETag) ret = append(ret, rt) } return ret, nil @@ -303,11 +309,6 @@ func (g *CatalogsManager) GetTrees(ctx context.Context, filter string, namespace return res, nil } -func (t *CatalogsManager) ValidateCreateOrUpdate(ctx context.Context, state model.CatalogState) error { - old, err := t.GetState(ctx, state.ObjectMeta.Name, state.ObjectMeta.Namespace) - return validation.ValidateCreateOrUpdateWrapper(ctx, &t.CatalogValidator, state, old, err) -} - func (t *CatalogsManager) ValidateDelete(ctx context.Context, name string, namespace string) error { state, err := t.GetState(ctx, name, namespace) return validation.ValidateDeleteWrapper(ctx, &t.CatalogValidator, state, err) diff --git a/api/pkg/apis/v1alpha1/managers/devices/devices-manager.go b/api/pkg/apis/v1alpha1/managers/devices/devices-manager.go index 3e8a03dbf..d7f11cdc5 100644 --- a/api/pkg/apis/v1alpha1/managers/devices/devices-manager.go +++ b/api/pkg/apis/v1alpha1/managers/devices/devices-manager.go @@ -85,6 +85,11 @@ func (t *DevicesManager) UpsertState(ctx context.Context, name string, state mod } state.ObjectMeta.FixNames(name) + oldState, getStateErr := t.GetState(ctx, state.ObjectMeta.Name, state.ObjectMeta.Namespace) + if getStateErr == nil { + state.ObjectMeta.PreserveSystemMetadata(oldState.ObjectMeta) + } + upsertRequest := states.UpsertRequest{ Value: states.StateEntry{ ID: name, @@ -94,6 +99,7 @@ func (t *DevicesManager) UpsertState(ctx context.Context, name string, state mod "metadata": state.ObjectMeta, "spec": state.Spec, }, + ETag: state.ObjectMeta.ETag, }, Metadata: map[string]interface{}{ "namespace": state.ObjectMeta.Namespace, @@ -143,6 +149,7 @@ func (t *DevicesManager) ListState(ctx context.Context, namespace string) ([]mod log.ErrorfCtx(ctx, " M (Devices): ListState failed to get device state %s, error: %v", t.ID, err) return nil, err } + rt.ObjectMeta.UpdateEtag(t.ETag) ret = append(ret, rt) } return ret, nil @@ -192,5 +199,6 @@ func (t *DevicesManager) GetState(ctx context.Context, name string, namespace st log.ErrorfCtx(ctx, " M (Devices): GetSpec failed to get device state, error: %v", err) return model.DeviceState{}, err } + ret.ObjectMeta.UpdateEtag(entry.ETag) return ret, nil } diff --git a/api/pkg/apis/v1alpha1/managers/devices/devices-manager_test.go b/api/pkg/apis/v1alpha1/managers/devices/devices-manager_test.go index faf040867..c769cd7bb 100644 --- a/api/pkg/apis/v1alpha1/managers/devices/devices-manager_test.go +++ b/api/pkg/apis/v1alpha1/managers/devices/devices-manager_test.go @@ -97,6 +97,7 @@ func TestUpsertAndGet(t *testing.T) { assert.Nil(t, err) state, err := manager.GetState(context.Background(), "test", "default") assert.Nil(t, err) + deviceState.ObjectMeta.UpdateEtag(state.ObjectMeta.ETag) assert.Equal(t, deviceState, state) states, err := manager.ListState(context.Background(), "default") assert.Nil(t, err) diff --git a/api/pkg/apis/v1alpha1/managers/instances/instances-manager.go b/api/pkg/apis/v1alpha1/managers/instances/instances-manager.go index 8a3a8858e..b65babf16 100644 --- a/api/pkg/apis/v1alpha1/managers/instances/instances-manager.go +++ b/api/pkg/apis/v1alpha1/managers/instances/instances-manager.go @@ -20,11 +20,14 @@ import ( "github.com/eclipse-symphony/symphony/coa/pkg/apis/v1alpha2/providers" "github.com/eclipse-symphony/symphony/coa/pkg/apis/v1alpha2/providers/states" "github.com/eclipse-symphony/symphony/coa/pkg/apis/v1alpha2/utils" + "github.com/eclipse-symphony/symphony/coa/pkg/logger" observability "github.com/eclipse-symphony/symphony/coa/pkg/apis/v1alpha2/observability" observ_utils "github.com/eclipse-symphony/symphony/coa/pkg/apis/v1alpha2/observability/utils" ) +var log = logger.NewLogger("coa.runtime") + type InstancesManager struct { managers.Manager StateProvider states.IStateProvider @@ -86,6 +89,11 @@ func (t *InstancesManager) UpsertState(ctx context.Context, name string, state m } state.ObjectMeta.FixNames(name) + oldState, getStateErr := t.GetState(ctx, state.ObjectMeta.Name, state.ObjectMeta.Namespace) + if getStateErr == nil { + state.ObjectMeta.PreserveSystemMetadata(oldState.ObjectMeta) + } + if t.needValidate { if state.ObjectMeta.Labels == nil { state.ObjectMeta.Labels = make(map[string]string) @@ -95,7 +103,7 @@ func (t *InstancesManager) UpsertState(ctx context.Context, name string, state m state.ObjectMeta.Labels[constants.Solution] = state.Spec.Solution state.ObjectMeta.Labels[constants.Target] = state.Spec.Target.Name } - if err = t.ValidateCreateOrUpdate(ctx, state); err != nil { + if err = validation.ValidateCreateOrUpdateWrapper(ctx, &t.InstanceValidator, state, oldState, getStateErr); err != nil { return err } } @@ -153,16 +161,17 @@ func (t *InstancesManager) ListState(ctx context.Context, namespace string) ([]m ret := make([]model.InstanceState, 0) for _, t := range instances { var rt model.InstanceState - rt, err = getInstanceState(t.Body, t.ETag) + rt, err = getInstanceState(t.Body) if err != nil { return nil, err } + rt.ObjectMeta.UpdateEtag(t.ETag) ret = append(ret, rt) } return ret, nil } -func getInstanceState(body interface{}, etag string) (model.InstanceState, error) { +func getInstanceState(body interface{}) (model.InstanceState, error) { var instanceState model.InstanceState bytes, _ := json.Marshal(body) err := json.Unmarshal(bytes, &instanceState) @@ -172,7 +181,6 @@ func getInstanceState(body interface{}, etag string) (model.InstanceState, error if instanceState.Spec == nil { instanceState.Spec = &model.InstanceSpec{} } - instanceState.ObjectMeta.ETag = etag return instanceState, nil } @@ -200,18 +208,14 @@ func (t *InstancesManager) GetState(ctx context.Context, id string, namespace st return model.InstanceState{}, err } var ret model.InstanceState - ret, err = getInstanceState(instance.Body, instance.ETag) + ret, err = getInstanceState(instance.Body) if err != nil { return model.InstanceState{}, err } + ret.ObjectMeta.UpdateEtag(instance.ETag) return ret, nil } -func (t *InstancesManager) ValidateCreateOrUpdate(ctx context.Context, state model.InstanceState) error { - old, err := t.GetState(ctx, state.ObjectMeta.Name, state.ObjectMeta.Namespace) - return validation.ValidateCreateOrUpdateWrapper(ctx, &t.InstanceValidator, state, old, err) -} - func (t *InstancesManager) instanceUniqueNameLookup(ctx context.Context, displayName string, namespace string) (interface{}, error) { return states.GetObjectStateWithUniqueName(ctx, t.StateProvider, validation.Instance, displayName, namespace) } diff --git a/api/pkg/apis/v1alpha1/managers/models/models-manager.go b/api/pkg/apis/v1alpha1/managers/models/models-manager.go index a7848d713..c2b005296 100644 --- a/api/pkg/apis/v1alpha1/managers/models/models-manager.go +++ b/api/pkg/apis/v1alpha1/managers/models/models-manager.go @@ -81,6 +81,11 @@ func (t *ModelsManager) UpsertState(ctx context.Context, name string, state mode } state.ObjectMeta.FixNames(name) + oldState, getStateErr := t.GetState(ctx, state.ObjectMeta.Name, state.ObjectMeta.Namespace) + if getStateErr == nil { + state.ObjectMeta.PreserveSystemMetadata(oldState.ObjectMeta) + } + upsertRequest := states.UpsertRequest{ Value: states.StateEntry{ ID: name, @@ -90,6 +95,7 @@ func (t *ModelsManager) UpsertState(ctx context.Context, name string, state mode "metadata": state.ObjectMeta, "spec": state.Spec, }, + ETag: state.ObjectMeta.ETag, }, Metadata: map[string]interface{}{ "namespace": state.ObjectMeta.Namespace, @@ -139,6 +145,7 @@ func (t *ModelsManager) ListState(ctx context.Context, namespace string) ([]mode log.ErrorfCtx(ctx, " M (Models): failed to getModelState, err: %v", err) return nil, err } + rt.ObjectMeta.UpdateEtag(t.ETag) ret = append(ret, rt) } return ret, nil @@ -189,5 +196,6 @@ func (t *ModelsManager) GetState(ctx context.Context, name string, namespace str log.ErrorfCtx(ctx, " M (Models): failed to getModelState, name: %s, err: %v", name, err) return model.ModelState{}, err } + ret.ObjectMeta.UpdateEtag(m.ETag) return ret, nil } diff --git a/api/pkg/apis/v1alpha1/managers/models/models-manager_test.go b/api/pkg/apis/v1alpha1/managers/models/models-manager_test.go index b70869aeb..a1c99cb71 100644 --- a/api/pkg/apis/v1alpha1/managers/models/models-manager_test.go +++ b/api/pkg/apis/v1alpha1/managers/models/models-manager_test.go @@ -233,9 +233,9 @@ func TestUpsertAndListSpecFail(t *testing.T) { }) assert.Nil(t, err) - err = manager.UpsertState(context.Background(), "mockJsonError", model.ModelState{ + err = manager.UpsertState(context.Background(), "mockJsonErrorUpsert", model.ModelState{ ObjectMeta: model.ObjectMeta{ - Name: "mockJsonError", + Name: "mockJsonErrorUpsert", }, Spec: &model.ModelSpec{ DisplayName: "device", @@ -264,7 +264,7 @@ func (m *MemoryStateProviderFail) Upsert(ctx context.Context, request states.Ups if request.Value.ID == "mockError" { return "", assert.AnError } else { - if request.Value.ID == "mockJsonError" { + if request.Value.ID == "mockJsonErrorUpsert" { request.Value.Body = map[string]interface{}{ "spec": []byte("invalid json"), } diff --git a/api/pkg/apis/v1alpha1/managers/skills/skills-manager.go b/api/pkg/apis/v1alpha1/managers/skills/skills-manager.go index 8d030fd23..300306177 100644 --- a/api/pkg/apis/v1alpha1/managers/skills/skills-manager.go +++ b/api/pkg/apis/v1alpha1/managers/skills/skills-manager.go @@ -79,6 +79,11 @@ func (t *SkillsManager) UpsertState(ctx context.Context, name string, state mode } state.ObjectMeta.FixNames(name) + oldState, getStateErr := t.GetState(ctx, state.ObjectMeta.Name, state.ObjectMeta.Namespace) + if getStateErr == nil { + state.ObjectMeta.PreserveSystemMetadata(oldState.ObjectMeta) + } + upsertRequest := states.UpsertRequest{ Value: states.StateEntry{ ID: name, @@ -88,6 +93,7 @@ func (t *SkillsManager) UpsertState(ctx context.Context, name string, state mode "metadata": state.ObjectMeta, "spec": state.Spec, }, + ETag: state.ObjectMeta.ETag, }, Metadata: map[string]interface{}{ "namespace": state.ObjectMeta.Namespace, @@ -137,6 +143,7 @@ func (t *SkillsManager) ListState(ctx context.Context, namespace string) ([]mode log.ErrorfCtx(ctx, " M (Models): failed to get skill state, err: %v", err) return nil, err } + rt.ObjectMeta.UpdateEtag(t.ETag) ret = append(ret, rt) } return ret, nil @@ -186,5 +193,6 @@ func (t *SkillsManager) GetState(ctx context.Context, name string, namespace str log.ErrorfCtx(ctx, " M (Skills): failed to get skill state, name: %s, err: %v", name, err) return model.SkillState{}, err } + ret.ObjectMeta.UpdateEtag(m.ETag) return ret, nil } diff --git a/api/pkg/apis/v1alpha1/managers/solutioncontainers/solution-container-manager.go b/api/pkg/apis/v1alpha1/managers/solutioncontainers/solution-container-manager.go index 7b5947bbe..2831008ea 100644 --- a/api/pkg/apis/v1alpha1/managers/solutioncontainers/solution-container-manager.go +++ b/api/pkg/apis/v1alpha1/managers/solutioncontainers/solution-container-manager.go @@ -78,6 +78,11 @@ func (t *SolutionContainersManager) UpsertState(ctx context.Context, name string } state.ObjectMeta.FixNames(name) + oldState, getStateErr := t.GetState(ctx, state.ObjectMeta.Name, state.ObjectMeta.Namespace) + if getStateErr == nil { + state.ObjectMeta.PreserveSystemMetadata(oldState.ObjectMeta) + } + body := map[string]interface{}{ "apiVersion": model.SolutionGroup + "/v1", "kind": "SolutionContainer", @@ -89,7 +94,7 @@ func (t *SolutionContainersManager) UpsertState(ctx context.Context, name string Value: states.StateEntry{ ID: name, Body: body, - ETag: "", + ETag: state.ObjectMeta.ETag, }, Metadata: map[string]interface{}{ "namespace": state.ObjectMeta.Namespace, @@ -131,16 +136,17 @@ func (t *SolutionContainersManager) ListState(ctx context.Context, namespace str ret := make([]model.SolutionContainerState, 0) for _, t := range solutioncontainers { var rt model.SolutionContainerState - rt, err = getSolutionContainerState(t.Body, t.ETag) + rt, err = getSolutionContainerState(t.Body) if err != nil { return nil, err } + rt.ObjectMeta.UpdateEtag(t.ETag) ret = append(ret, rt) } return ret, nil } -func getSolutionContainerState(body interface{}, etag string) (model.SolutionContainerState, error) { +func getSolutionContainerState(body interface{}) (model.SolutionContainerState, error) { var SolutionContainerState model.SolutionContainerState bytes, _ := json.Marshal(body) err := json.Unmarshal(bytes, &SolutionContainerState) @@ -177,9 +183,10 @@ func (t *SolutionContainersManager) GetState(ctx context.Context, id string, nam return model.SolutionContainerState{}, err } var ret model.SolutionContainerState - ret, err = getSolutionContainerState(Solution.Body, Solution.ETag) + ret, err = getSolutionContainerState(Solution.Body) if err != nil { return model.SolutionContainerState{}, err } + ret.ObjectMeta.UpdateEtag(Solution.ETag) return ret, nil } diff --git a/api/pkg/apis/v1alpha1/managers/solutions/solutions-manager.go b/api/pkg/apis/v1alpha1/managers/solutions/solutions-manager.go index 553ae5434..a777fabfb 100644 --- a/api/pkg/apis/v1alpha1/managers/solutions/solutions-manager.go +++ b/api/pkg/apis/v1alpha1/managers/solutions/solutions-manager.go @@ -20,11 +20,14 @@ import ( "github.com/eclipse-symphony/symphony/coa/pkg/apis/v1alpha2/providers" "github.com/eclipse-symphony/symphony/coa/pkg/apis/v1alpha2/providers/states" "github.com/eclipse-symphony/symphony/coa/pkg/apis/v1alpha2/utils" + "github.com/eclipse-symphony/symphony/coa/pkg/logger" observability "github.com/eclipse-symphony/symphony/coa/pkg/apis/v1alpha2/observability" observ_utils "github.com/eclipse-symphony/symphony/coa/pkg/apis/v1alpha2/observability/utils" ) +var log = logger.NewLogger("coa.runtime") + type SolutionsManager struct { managers.Manager StateProvider states.IStateProvider @@ -92,6 +95,11 @@ func (t *SolutionsManager) UpsertState(ctx context.Context, name string, state m } state.ObjectMeta.FixNames(name) + oldState, getStateErr := t.GetState(ctx, state.ObjectMeta.Name, state.ObjectMeta.Namespace) + if getStateErr == nil { + state.ObjectMeta.PreserveSystemMetadata(oldState.ObjectMeta) + } + if t.needValidate { if state.ObjectMeta.Labels == nil { state.ObjectMeta.Labels = make(map[string]string) @@ -100,7 +108,7 @@ func (t *SolutionsManager) UpsertState(ctx context.Context, name string, state m state.ObjectMeta.Labels[constants.DisplayName] = utils.ConvertStringToValidLabel(state.Spec.DisplayName) state.ObjectMeta.Labels[constants.RootResource] = state.Spec.RootResource } - if err = t.ValidateCreateOrUpdate(ctx, state); err != nil { + if err = validation.ValidateCreateOrUpdateWrapper(ctx, &t.SolutionValidator, state, oldState, getStateErr); err != nil { return err } } @@ -115,6 +123,7 @@ func (t *SolutionsManager) UpsertState(ctx context.Context, name string, state m Value: states.StateEntry{ ID: name, Body: body, + ETag: state.ObjectMeta.ETag, }, Metadata: map[string]interface{}{ "namespace": state.ObjectMeta.Namespace, @@ -158,6 +167,7 @@ func (t *SolutionsManager) ListState(ctx context.Context, namespace string) ([]m if err != nil { return nil, err } + rt.ObjectMeta.UpdateEtag(t.ETag) ret = append(ret, rt) } return ret, nil @@ -194,24 +204,20 @@ func (t *SolutionsManager) GetState(ctx context.Context, id string, namespace st "kind": "Solution", }, } - var target states.StateEntry - target, err = t.StateProvider.Get(ctx, getRequest) + var entry states.StateEntry + entry, err = t.StateProvider.Get(ctx, getRequest) if err != nil { return model.SolutionState{}, err } var ret model.SolutionState - ret, err = getSolutionState(target.Body) + ret, err = getSolutionState(entry.Body) if err != nil { return model.SolutionState{}, err } + ret.ObjectMeta.UpdateEtag(entry.ETag) return ret, nil } -func (t *SolutionsManager) ValidateCreateOrUpdate(ctx context.Context, state model.SolutionState) error { - old, err := t.GetState(ctx, state.ObjectMeta.Name, state.ObjectMeta.Namespace) - return validation.ValidateCreateOrUpdateWrapper(ctx, &t.SolutionValidator, state, old, err) -} - func (t *SolutionsManager) ValidateDelete(ctx context.Context, name string, namespace string) error { state, err := t.GetState(ctx, name, namespace) return validation.ValidateDeleteWrapper(ctx, &t.SolutionValidator, state, err) diff --git a/api/pkg/apis/v1alpha1/managers/targets/targets-manager.go b/api/pkg/apis/v1alpha1/managers/targets/targets-manager.go index b27813b59..ba882a2e5 100644 --- a/api/pkg/apis/v1alpha1/managers/targets/targets-manager.go +++ b/api/pkg/apis/v1alpha1/managers/targets/targets-manager.go @@ -22,10 +22,13 @@ import ( "github.com/eclipse-symphony/symphony/coa/pkg/apis/v1alpha2/providers/registry" "github.com/eclipse-symphony/symphony/coa/pkg/apis/v1alpha2/providers/states" "github.com/eclipse-symphony/symphony/coa/pkg/apis/v1alpha2/utils" + "github.com/eclipse-symphony/symphony/coa/pkg/logger" observ_utils "github.com/eclipse-symphony/symphony/coa/pkg/apis/v1alpha2/observability/utils" ) +var log = logger.NewLogger("coa.runtime") + type TargetsManager struct { managers.Manager StateProvider states.IStateProvider @@ -94,6 +97,11 @@ func (t *TargetsManager) UpsertState(ctx context.Context, name string, state mod } state.ObjectMeta.FixNames(name) + oldState, getStateErr := t.GetState(ctx, state.ObjectMeta.Name, state.ObjectMeta.Namespace) + if getStateErr == nil { + state.ObjectMeta.PreserveSystemMetadata(oldState.ObjectMeta) + } + if t.needValidate { if state.ObjectMeta.Labels == nil { state.ObjectMeta.Labels = make(map[string]string) @@ -101,7 +109,7 @@ func (t *TargetsManager) UpsertState(ctx context.Context, name string, state mod if state.Spec != nil { state.ObjectMeta.Labels[constants.DisplayName] = utils.ConvertStringToValidLabel(state.Spec.DisplayName) } - if err = t.ValidateCreateOrUpdate(ctx, state); err != nil { + if err = validation.ValidateCreateOrUpdateWrapper(ctx, &t.TargetValidator, state, oldState, getStateErr); err != nil { return err } } @@ -219,16 +227,17 @@ func (t *TargetsManager) ListState(ctx context.Context, namespace string) ([]mod ret := make([]model.TargetState, 0) for _, t := range targets { var rt model.TargetState - rt, err = getTargetState(t.Body, t.ETag) + rt, err = getTargetState(t.Body) if err != nil { return nil, err } + rt.ObjectMeta.UpdateEtag(t.ETag) ret = append(ret, rt) } return ret, nil } -func getTargetState(body interface{}, etag string) (model.TargetState, error) { +func getTargetState(body interface{}) (model.TargetState, error) { var targetState model.TargetState bytes, _ := json.Marshal(body) err := json.Unmarshal(bytes, &targetState) @@ -238,7 +247,6 @@ func getTargetState(body interface{}, etag string) (model.TargetState, error) { if targetState.Spec == nil { targetState.Spec = &model.TargetSpec{} } - targetState.ObjectMeta.ETag = etag return targetState, nil } @@ -267,18 +275,14 @@ func (t *TargetsManager) GetState(ctx context.Context, id string, namespace stri } var ret model.TargetState - ret, err = getTargetState(target.Body, target.ETag) + ret, err = getTargetState(target.Body) if err != nil { return model.TargetState{}, err } + ret.ObjectMeta.UpdateEtag(target.ETag) return ret, nil } -func (t *TargetsManager) ValidateCreateOrUpdate(ctx context.Context, state model.TargetState) error { - old, err := t.GetState(ctx, state.ObjectMeta.Name, state.ObjectMeta.Namespace) - return validation.ValidateCreateOrUpdateWrapper(ctx, &t.TargetValidator, state, old, err) -} - func (t *TargetsManager) ValidateDelete(ctx context.Context, name string, namespace string) error { state, err := t.GetState(ctx, name, namespace) return validation.ValidateDeleteWrapper(ctx, &t.TargetValidator, state, err) diff --git a/api/pkg/apis/v1alpha1/managers/targets/targets-manager_test.go b/api/pkg/apis/v1alpha1/managers/targets/targets-manager_test.go index d021ea87f..07652c49c 100644 --- a/api/pkg/apis/v1alpha1/managers/targets/targets-manager_test.go +++ b/api/pkg/apis/v1alpha1/managers/targets/targets-manager_test.go @@ -10,6 +10,7 @@ import ( "context" "testing" + "github.com/eclipse-symphony/symphony/api/constants" "github.com/eclipse-symphony/symphony/api/pkg/apis/v1alpha1/model" "github.com/eclipse-symphony/symphony/api/pkg/apis/v1alpha1/validation" "github.com/eclipse-symphony/symphony/coa/pkg/apis/v1alpha2/providers/states/memorystate" @@ -71,6 +72,46 @@ func TestUpdateTargetStatus(t *testing.T) { assert.Equal(t, "test", state.Status.Properties["label"]) } +func TestUpdateExistingTarget(t *testing.T) { + stateProvider := &memorystate.MemoryStateProvider{} + stateProvider.Init(memorystate.MemoryStateProviderConfig{}) + manager := TargetsManager{ + StateProvider: stateProvider, + } + + targetName := "test123" + state := model.TargetState{ + ObjectMeta: model.ObjectMeta{ + Name: targetName, + Namespace: "default", + Annotations: map[string]string{ + constants.SummaryJobIdKey: "1", + }, + }, + Spec: &model.TargetSpec{ + DisplayName: targetName, + }, + } + err := manager.UpsertState(context.Background(), targetName, state) + assert.Nil(t, err) + + state = model.TargetState{ + ObjectMeta: model.ObjectMeta{ + Name: targetName, + Namespace: "default", + }, + Spec: &model.TargetSpec{ + DisplayName: targetName, + IsDryRun: true, + }, + } + + state, err = manager.GetState(context.Background(), targetName, "default") + assert.Nil(t, err) + assert.Equal(t, targetName, state.ObjectMeta.Name) + assert.Equal(t, "1", state.ObjectMeta.Annotations[constants.SummaryJobIdKey]) +} + func TestCreateTargetWithSameDisplayName(t *testing.T) { stateProvider := &memorystate.MemoryStateProvider{} stateProvider.Init(memorystate.MemoryStateProviderConfig{}) diff --git a/api/pkg/apis/v1alpha1/model/objectmeta.go b/api/pkg/apis/v1alpha1/model/objectmeta.go index 539fa286b..edc516cb5 100644 --- a/api/pkg/apis/v1alpha1/model/objectmeta.go +++ b/api/pkg/apis/v1alpha1/model/objectmeta.go @@ -12,6 +12,7 @@ import ( "fmt" "strconv" + "github.com/eclipse-symphony/symphony/api/constants" "github.com/eclipse-symphony/symphony/coa/pkg/apis/v1alpha2" ) @@ -119,3 +120,33 @@ func (c *ObjectMeta) UpdateAnnotation(key string, value string) { c.Annotations[key] = value } + +func (c *ObjectMeta) UpdateEtag(etag string) { + c.ETag = etag +} + +func (c *ObjectMeta) PreserveSystemMetadata(metadata ObjectMeta) { + if c.Annotations == nil { + c.Annotations = make(map[string]string) + } + + for _, key := range constants.SystemReservedAnnotations() { + if _, exists := c.Annotations[key]; !exists { + if value, ok := metadata.Annotations[key]; ok { + c.Annotations[key] = value + } + } + } + + if c.Labels == nil { + c.Labels = make(map[string]string) + } + + for _, key := range constants.SystemReservedLabels() { + if _, exists := c.Labels[key]; !exists { + if value, ok := metadata.Labels[key]; ok { + c.Labels[key] = value + } + } + } +} diff --git a/api/pkg/apis/v1alpha1/providers/stage/create/create.go b/api/pkg/apis/v1alpha1/providers/stage/create/create.go index 7e35e7880..1774eac8b 100644 --- a/api/pkg/apis/v1alpha1/providers/stage/create/create.go +++ b/api/pkg/apis/v1alpha1/providers/stage/create/create.go @@ -324,9 +324,4 @@ func (i *CreateStageProvider) Process(ctx context.Context, mgrContext contexts.M ) return nil, false, err } - outputs["objectType"] = objectType - outputs["objectName"] = objectName - - mLog.InfofCtx(ctx, " P (Create Stage) process completed") - return outputs, false, nil } diff --git a/api/pkg/apis/v1alpha1/providers/states/k8s/k8s.go b/api/pkg/apis/v1alpha1/providers/states/k8s/k8s.go index 3f4d91205..bc665ff79 100644 --- a/api/pkg/apis/v1alpha1/providers/states/k8s/k8s.go +++ b/api/pkg/apis/v1alpha1/providers/states/k8s/k8s.go @@ -235,6 +235,7 @@ func (s *K8sStateProvider) Upsert(ctx context.Context, entry states.UpsertReques } //Note: state is ignored for new object } else { + // if there is no error, we are updating an existing object. j, _ := json.Marshal(entry.Value.Body) var dict map[string]interface{} err = json.Unmarshal(j, &dict) @@ -250,6 +251,7 @@ func (s *K8sStateProvider) Upsert(ctx context.Context, entry states.UpsertReques sLog.ErrorfCtx(ctx, " P (K8s State): failed to unmarshal object metadata: %v", err) return "", v1alpha2.NewCOAError(err, "failed to upsert state because failed to unmarshal object metadata", v1alpha2.BadRequest) } + item.SetName(metadata.Name) item.SetNamespace(metadata.Namespace) item.SetLabels(metadata.Labels) @@ -259,6 +261,8 @@ func (s *K8sStateProvider) Upsert(ctx context.Context, entry states.UpsertReques if v, ok := dict["spec"]; ok && !entry.Options.UpdateStatusOnly { item.Object["spec"] = v + // If we update the labels, annotations or spec, we should respect the resource version provided by client. + item.SetResourceVersion(entry.Value.ETag) _, err = s.DynamicClient.Resource(resourceId).Namespace(namespace).Update(ctx, item, metav1.UpdateOptions{}) if err != nil { sLog.ErrorfCtx(ctx, " P (K8s State): failed to update object: %v", err) @@ -412,6 +416,7 @@ func (s *K8sStateProvider) List(ctx context.Context, request states.ListRequest) Name: v.GetName(), Namespace: v.GetNamespace(), Labels: v.GetLabels(), + ETag: v.GetResourceVersion(), Annotations: v.GetAnnotations(), ObjGeneration: v.GetGeneration(), } @@ -513,6 +518,7 @@ func (s *K8sStateProvider) Get(ctx context.Context, request states.GetRequest) ( Name: item.GetName(), Namespace: item.GetNamespace(), Labels: item.GetLabels(), + ETag: item.GetResourceVersion(), Annotations: item.GetAnnotations(), ObjGeneration: item.GetGeneration(), } diff --git a/api/pkg/apis/v1alpha1/providers/states/k8s/k8s_test.go b/api/pkg/apis/v1alpha1/providers/states/k8s/k8s_test.go index ac7c327ee..755da6906 100644 --- a/api/pkg/apis/v1alpha1/providers/states/k8s/k8s_test.go +++ b/api/pkg/apis/v1alpha1/providers/states/k8s/k8s_test.go @@ -275,6 +275,20 @@ func TestActivationUpsertWithState(t *testing.T) { ConfigType: "path", }) assert.Nil(t, err) + + // Get current resource version + item, err := provider.Get(context.Background(), states.GetRequest{ + ID: "a1", + Metadata: map[string]interface{}{ + "namespace": "default", + "group": model.WorkflowGroup, + "version": "v1", + "resource": "activations", + "kind": "Activation", + }, + }) + assert.Nil(t, err) + activationStatus := model.ActivationStatus{ StageHistory: []model.StageStatus{ { @@ -300,6 +314,7 @@ func TestActivationUpsertWithState(t *testing.T) { }, "status": dict, }, + ETag: item.ETag, }, Metadata: map[string]interface{}{ "template": fmt.Sprintf(`{"apiVersion":"%s/v1", "kind": "Activation", "metadata": {"name": "${{$activation()}}"}}`, model.WorkflowGroup), @@ -644,6 +659,20 @@ func TestCatalogStatusFilter(t *testing.T) { }, }) assert.Nil(t, err) + + // Get current resource version + item, err := provider.Get(context.Background(), states.GetRequest{ + ID: "c2", + Metadata: map[string]interface{}{ + "namespace": "default", + "group": model.FederationGroup, + "version": "v1", + "resource": "catalogs", + "kind": "Catalog", + }, + }) + assert.Nil(t, err) + _, err = provider.Upsert(context.Background(), states.UpsertRequest{ // An update is issued as in initial insert status is ignored. TODO: Isn't that a bug? Value: states.StateEntry{ ID: "c2", @@ -664,6 +693,7 @@ func TestCatalogStatusFilter(t *testing.T) { }, }, }, + ETag: item.ETag, }, Metadata: map[string]interface{}{ "namespace": "default", diff --git a/api/pkg/apis/v1alpha1/providers/target/staging/staging.go b/api/pkg/apis/v1alpha1/providers/target/staging/staging.go index 0c5bba813..6b12c9d35 100644 --- a/api/pkg/apis/v1alpha1/providers/target/staging/staging.go +++ b/api/pkg/apis/v1alpha1/providers/target/staging/staging.go @@ -208,7 +208,7 @@ func (i *StagingTargetProvider) Apply(ctx context.Context, deployment model.Depl if catalog.ObjectMeta.Labels == nil { catalog.ObjectMeta.Labels = make(map[string]string) } - catalog.ObjectMeta.Labels["staged_target"] = i.Config.TargetName + catalog.ObjectMeta.Labels[constants.StagedTarget] = i.Config.TargetName var existing []model.ComponentSpec if v, ok := catalog.Spec.Properties["components"]; ok { diff --git a/api/pkg/apis/v1alpha1/utils/utils.go b/api/pkg/apis/v1alpha1/utils/utils.go index 91b92cfb2..b2c55659c 100644 --- a/api/pkg/apis/v1alpha1/utils/utils.go +++ b/api/pkg/apis/v1alpha1/utils/utils.go @@ -549,4 +549,4 @@ func FilterIncompleteDelete(ctx context.Context, apiclient *ApiClient, namespace remainingObjects = append(remainingObjects, objectName) } return remainingObjects -} +} \ No newline at end of file diff --git a/k8s/apis/federation/v1/catalog_eval_types.go b/k8s/apis/federation/v1/catalog_eval_types.go index 003ec3593..0378be97a 100644 --- a/k8s/apis/federation/v1/catalog_eval_types.go +++ b/k8s/apis/federation/v1/catalog_eval_types.go @@ -7,14 +7,15 @@ package v1 import ( + "gopls-workspace/constants" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/types" ) const ( // DefaultStopActionTimeout is default value of 1200 sec timeout period for stop action. - DefaultStopActionTimeout int64 = 1200 - AzureOperationIDAnnotationKey = "management.azure.com/operationId" + DefaultStopActionTimeout int64 = 1200 ) // CatalogEvalExpressionActionSpec defines the desired state of CatalogEvalExpressionActionSpec. @@ -46,7 +47,7 @@ func (a *CatalogEvalExpression) GetResourceNamespacedName() *types.NamespacedNam func (a *CatalogEvalExpression) GetOperationID() string { annotations := a.GetAnnotations() - return annotations[AzureOperationIDAnnotationKey] + return annotations[constants.AzureOperationIdKey] } // +kubebuilder:object:root=true diff --git a/k8s/constants/constants.go b/k8s/constants/constants.go index f412c647c..8fad9757c 100644 --- a/k8s/constants/constants.go +++ b/k8s/constants/constants.go @@ -9,29 +9,24 @@ package constants -import _ "embed" +import ( + _ "embed" + + api_constants "github.com/eclipse-symphony/symphony/api/constants" +) const ( - FullGroupName = "symphony" - AzureOperationIdKey = "management.azure.com/operationId" - AzureCorrelationIdKey = "management.azure.com/correlationId" - RunningAzureCorrelationIdKey = "management.azure.com/runningCorrelationId" - AzureResourceIdKey = "management.azure.com/resourceId" - AzureSystemDataKey = "management.azure.com/systemData" - AzureTenantIdKey = "management.azure.com/tenantId" - AzureLocationKey = "management.azure.com/location" - AzureEdgeLocationKey = "management.azure.com/customLocation" - SummaryJobIdKey = "SummaryJobIdKey" - AzureCreatedByKey = "createdBy" - DefaultScope = "default" - K8S = "symphony-k8s" - OperationStartTimeKeyPostfix = FullGroupName + "/started-at" - FinalizerPostfix = FullGroupName + "/finalizer" - ResourceSeperator = "-v-" - ReferenceSeparator = ":" - ActivityOperation_Write = "Write" - ActivityOperation_Read = "Read" - ActivityOperation_Delete = "Delete" + FullGroupName = api_constants.FullGroupName + AzureLocationKey = "management.azure.com/location" // diagnostic + AzureCreatedByKey = "createdBy" // systemDataMap + DefaultScope = "default" // Namespace + K8S = "symphony-k8s" // observable + FinalizerPostfix = FullGroupName + "/finalizer" // finalizerName, instance/target + ResourceSeperator = "-v-" + ReferenceSeparator = ":" + ActivityOperation_Write = "Write" + ActivityOperation_Read = "Read" + ActivityOperation_Delete = "Delete" SolutionContainerOperationNamePrefix = "solutioncontainers.solution." + FullGroupName SolutionOperationNamePrefix = "solutions.solution." + FullGroupName @@ -45,6 +40,19 @@ const ( DiagnosticsOperationNamePrefix = "diagnostics.monitor." + FullGroupName ) +// system annotations, reserved and should not be modified by client. +const ( + AzureCorrelationIdKey = api_constants.AzureCorrelationIdKey + AzureEdgeLocationKey = api_constants.AzureEdgeLocationKey + AzureOperationIdKey = api_constants.AzureOperationIdKey + AzureResourceIdKey = api_constants.AzureResourceIdKey + AzureSystemDataKey = api_constants.AzureSystemDataKey + AzureTenantIdKey = api_constants.AzureTenantIdKey + RunningAzureCorrelationIdKey = api_constants.RunningAzureCorrelationIdKey + SummaryJobIdKey = api_constants.SummaryJobIdKey + OperationStartTimeKeyPostfix = api_constants.OperationStartTimeKeyPostfix // instance/target +) + // Environment variables keys const ( SymphonyAPIUrlEnvName = "SYMPHONY_API_URL"