-
Notifications
You must be signed in to change notification settings - Fork 94
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Update settings api to use ResourceContext
over ModificationInfo
#1633
base: main
Are you sure you want to change the base?
Changes from all commits
2af6ac3
1f66165
45340bd
7442a1e
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -24,6 +24,7 @@ import ( | |
"fmt" | ||
"net/http" | ||
"net/url" | ||
"slices" | ||
"strings" | ||
|
||
"github.com/google/go-cmp/cmp" | ||
|
@@ -41,6 +42,13 @@ import ( | |
"github.com/dynatrace/dynatrace-configuration-as-code/v2/pkg/config/coordinate" | ||
) | ||
|
||
// SettingsResourceContext.Operations possibilities | ||
const ( | ||
DeleteOperation = "delete" | ||
WriteOperation = "write" | ||
//ReadOperation = "read" | ||
) | ||
|
||
// DownloadSettingsObject is the response type for the ListSettings operation | ||
type DownloadSettingsObject struct { | ||
ExternalId string `json:"externalId"` | ||
|
@@ -50,6 +58,55 @@ type DownloadSettingsObject struct { | |
Scope string `json:"scope"` | ||
Value json.RawMessage `json:"value"` | ||
ModificationInfo *SettingsModificationInfo `json:"modificationInfo"` | ||
ResourceContext *SettingsResourceContext `json:"resourceContext"` | ||
} | ||
|
||
func (settingObject *DownloadSettingsObject) IsDeletable() bool { | ||
if settingObject.ResourceContext != nil { | ||
return slices.Contains(settingObject.ResourceContext.Operations, DeleteOperation) | ||
} | ||
|
||
if settingObject.ModificationInfo != nil { | ||
return settingObject.ModificationInfo.Deletable | ||
} | ||
|
||
return true | ||
} | ||
|
||
func (settingObject *DownloadSettingsObject) IsModifiable() bool { | ||
if settingObject.ResourceContext != nil { | ||
return slices.Contains(settingObject.ResourceContext.Operations, WriteOperation) | ||
} | ||
|
||
if settingObject.ModificationInfo != nil { | ||
return settingObject.ModificationInfo.Modifiable | ||
} | ||
|
||
return true | ||
} | ||
|
||
func (settingObject *DownloadSettingsObject) IsMovable() bool { | ||
if settingObject.ResourceContext != nil { | ||
//API allows the parameter to be optional, so more logic is needed to handle it | ||
if settingObject.ResourceContext.Movable != nil { | ||
return *settingObject.ResourceContext.Movable | ||
} | ||
return true | ||
} | ||
|
||
if settingObject.ModificationInfo != nil { | ||
return settingObject.ModificationInfo.Movable | ||
} | ||
|
||
return true | ||
} | ||
|
||
func (settingObject *DownloadSettingsObject) GetModifiablePaths() []interface{} { | ||
if settingObject.ResourceContext != nil { | ||
return settingObject.ResourceContext.ModifiablePaths | ||
} | ||
|
||
return settingObject.ModificationInfo.ModifiablePaths | ||
} | ||
|
||
type SettingsModificationInfo struct { | ||
|
@@ -60,6 +117,13 @@ type SettingsModificationInfo struct { | |
NonModifiablePaths []interface{} `json:"nonModifiablePaths"` | ||
} | ||
|
||
type SettingsResourceContext struct { | ||
Operations []string `json:"operations"` | ||
Movable *bool `json:"modifications:movable"` | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. To the reviewer. I chose a pointer over its own If preferred, I could change it to a There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. By now, I wasn't aware of the NullBool type in GO. But as I see it, it is part of the SQL library and for that reason wouldn't it even consider. For me pointer is just enough |
||
ModifiablePaths []interface{} `json:"modifications:modifiablePaths"` | ||
NonModifiablePaths []interface{} `json:"modifications:nonModifiablePaths"` | ||
} | ||
|
||
type UpsertSettingsOptions struct { | ||
OverrideRetry *RetrySetting | ||
InsertAfter string | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -50,14 +50,14 @@ func Delete(ctx context.Context, c client.SettingsClient, entries []pointer.Dele | |
continue | ||
} | ||
|
||
objects, err := c.List(ctx, e.Type, dtclient.ListSettingsOptions{DiscardValue: true, Filter: filterFunc}) | ||
settingsObjects, err := c.List(ctx, e.Type, dtclient.ListSettingsOptions{DiscardValue: true, Filter: filterFunc}) | ||
if err != nil { | ||
logger.Error("Could not fetch settings object: %v", err) | ||
deleteErrs++ | ||
continue | ||
} | ||
|
||
if len(objects) == 0 { | ||
if len(settingsObjects) == 0 { | ||
if e.OriginObjectId != "" { | ||
logger.Debug("No settings object found to delete. Could not find object with matching object id.") | ||
continue | ||
|
@@ -66,16 +66,16 @@ func Delete(ctx context.Context, c client.SettingsClient, entries []pointer.Dele | |
continue | ||
} | ||
|
||
for _, obj := range objects { | ||
if obj.ModificationInfo != nil && !obj.ModificationInfo.Deletable { | ||
logger.WithFields(field.F("object", obj)).Warn("Requested settings object with ID %s is not deletable.", obj.ObjectId) | ||
for _, settingsObject := range settingsObjects { | ||
if !settingsObject.IsDeletable() { | ||
logger.WithFields(field.F("object", settingsObject)).Warn("Requested settings object with ID %s is not deletable.", settingsObject.ObjectId) | ||
continue | ||
} | ||
|
||
logger.Debug("Deleting settings object with objectId %q.", obj.ObjectId) | ||
err := c.Delete(ctx, obj.ObjectId) | ||
logger.Debug("Deleting settings object with objectId %q.", settingsObject.ObjectId) | ||
err := c.Delete(ctx, settingsObject.ObjectId) | ||
if err != nil { | ||
logger.Error("Failed to delete settings object with object ID %s: %v", obj.ObjectId, err) | ||
logger.Error("Failed to delete settings object with object ID %s: %v", settingsObject.ObjectId, err) | ||
deleteErrs++ | ||
} | ||
} | ||
|
@@ -129,23 +129,24 @@ func DeleteAll(ctx context.Context, c client.SettingsClient) error { | |
logger := logger.WithFields(field.Type(s)) | ||
logger.Info("Collecting objects of type %q...", s) | ||
|
||
settings, err := c.List(ctx, s, dtclient.ListSettingsOptions{DiscardValue: true}) | ||
settingsObjects, err := c.List(ctx, s, dtclient.ListSettingsOptions{DiscardValue: true}) | ||
if err != nil { | ||
logger.WithFields(field.Error(err)).Error("Failed to collect object for schema %q: %v", s, err) | ||
errs++ | ||
continue | ||
} | ||
|
||
logger.Info("Deleting %d objects of type %q...", len(settings), s) | ||
for _, setting := range settings { | ||
if setting.ModificationInfo != nil && !setting.ModificationInfo.Deletable { | ||
logger.Info("Deleting %d objects of type %q...", len(settingsObjects), s) | ||
for _, settingsObject := range settingsObjects { | ||
if !settingsObject.IsDeletable() { | ||
//@Reviewer should here also be a log as it is in the Delete() method | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. For consistency, it can be added. But if you doesn't see the purpose, I wouldn't |
||
continue | ||
} | ||
|
||
logger.WithFields(field.F("object", setting)).Debug("Deleting settings object with objectId %q...", setting.ObjectId) | ||
err := c.Delete(ctx, setting.ObjectId) | ||
logger.WithFields(field.F("object", settingsObject)).Debug("Deleting settingsObjects object with objectId %q...", settingsObject.ObjectId) | ||
err := c.Delete(ctx, settingsObject.ObjectId) | ||
if err != nil { | ||
logger.Error("Failed to delete settings object with object ID %s: %v", setting.ObjectId, err) | ||
logger.Error("Failed to delete settingsObjects object with object ID %s: %v", settingsObject.ObjectId, err) | ||
errs++ | ||
} | ||
} | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -182,50 +182,49 @@ func asConcurrentErrMsg(err coreapi.APIError) string { | |
return fmt.Sprintf("%s\n%s", err.Error(), additionalMessage) | ||
} | ||
|
||
func convertAllObjects(objects []dtclient.DownloadSettingsObject, projectName string, ordered bool, filters Filters) []config.Config { | ||
result := make([]config.Config, 0, len(objects)) | ||
func convertAllObjects(settingsObjects []dtclient.DownloadSettingsObject, projectName string, ordered bool, filters Filters) []config.Config { | ||
result := make([]config.Config, 0, len(settingsObjects)) | ||
var previousConfig *config.Config = nil | ||
for _, o := range objects { | ||
|
||
if shouldFilterUnmodifiableSettings() && o.ModificationInfo != nil && !o.ModificationInfo.Modifiable && len(o.ModificationInfo.ModifiablePaths) == 0 { | ||
log.WithFields(field.Type(o.SchemaId), field.F("object", o)).Debug("Discarded settings object %q (%s). Reason: Unmodifiable default setting.", o.ObjectId, o.SchemaId) | ||
for _, settingsObject := range settingsObjects { | ||
if shouldFilterUnmodifiableSettings() && !settingsObject.IsModifiable() && len(settingsObject.GetModifiablePaths()) == 0 { | ||
log.WithFields(field.Type(settingsObject.SchemaId), field.F("object", settingsObject)).Debug("Discarded settings object %q (%s). Reason: Unmodifiable default setting.", settingsObject.ObjectId, settingsObject.SchemaId) | ||
continue | ||
} | ||
|
||
// try to unmarshall settings value | ||
var contentUnmarshalled map[string]interface{} | ||
if err := json.Unmarshal(o.Value, &contentUnmarshalled); err != nil { | ||
log.WithFields(field.Type(o.SchemaId), field.F("object", o)).Error("Unable to unmarshal JSON value of settings 2.0 object: %v", err) | ||
if err := json.Unmarshal(settingsObject.Value, &contentUnmarshalled); err != nil { | ||
log.WithFields(field.Type(settingsObject.SchemaId), field.F("object", settingsObject)).Error("Unable to unmarshal JSON value of settings 2.0 object: %v", err) | ||
return result | ||
} | ||
// skip discarded settings objects | ||
if shouldDiscard, reason := filters.Get(o.SchemaId).ShouldDiscard(contentUnmarshalled); shouldFilterSettings() && shouldDiscard { | ||
log.WithFields(field.Type(o.SchemaId), field.F("object", o)).Debug("Discarded setting object %q (%s). Reason: %s", o.ObjectId, o.SchemaId, reason) | ||
// skip discarded settings settingsObjects | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. to much of renaming :) |
||
if shouldDiscard, reason := filters.Get(settingsObject.SchemaId).ShouldDiscard(contentUnmarshalled); shouldFilterSettings() && shouldDiscard { | ||
log.WithFields(field.Type(settingsObject.SchemaId), field.F("object", settingsObject)).Debug("Discarded setting object %q (%s). Reason: %s", settingsObject.ObjectId, settingsObject.SchemaId, reason) | ||
continue | ||
} | ||
|
||
indentedJson := jsonutils.MarshalIndent(o.Value) | ||
indentedJson := jsonutils.MarshalIndent(settingsObject.Value) | ||
// construct config object with generated config ID | ||
configId := idutils.GenerateUUIDFromString(o.ObjectId) | ||
configId := idutils.GenerateUUIDFromString(settingsObject.ObjectId) | ||
c := config.Config{ | ||
Template: template.NewInMemoryTemplate(configId, string(indentedJson)), | ||
Coordinate: coordinate.Coordinate{ | ||
Project: projectName, | ||
Type: o.SchemaId, | ||
Type: settingsObject.SchemaId, | ||
ConfigId: configId, | ||
}, | ||
Type: config.SettingsType{ | ||
SchemaId: o.SchemaId, | ||
SchemaVersion: o.SchemaVersion, | ||
SchemaId: settingsObject.SchemaId, | ||
SchemaVersion: settingsObject.SchemaVersion, | ||
}, | ||
Parameters: map[string]parameter.Parameter{ | ||
config.ScopeParameter: &value.ValueParameter{Value: o.Scope}, | ||
config.ScopeParameter: &value.ValueParameter{Value: settingsObject.Scope}, | ||
}, | ||
Skip: false, | ||
OriginObjectId: o.ObjectId, | ||
OriginObjectId: settingsObject.ObjectId, | ||
} | ||
|
||
if o.ModificationInfo != nil && o.ModificationInfo.Movable && ordered && (previousConfig != nil) { | ||
if settingsObject.IsMovable() && ordered && (previousConfig != nil) { | ||
c.Parameters[config.InsertAfterParameter] = reference.NewWithCoordinate(previousConfig.Coordinate, "id") | ||
} | ||
result = append(result, c) | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why not move to a separate file