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
MGMT-14704: Provide info on custom/vs non custom manifest in manifest endpoint. #5278
MGMT-14704: Provide info on custom/vs non custom manifest in manifest endpoint. #5278
Conversation
@paul-maidment: This pull request references MGMT-14704 which is a valid jira issue. In response to this:
Instructions for interacting with me using PR comments are available here. If you have questions or suggestions related to my behavior, please file an issue against the kubernetes/test-infra repository. |
Skipping CI for Draft Pull Request. |
ffeeccf
to
f8cde49
Compare
/assign @carbonin |
Was this also tested with the service running with our S3 filesystem driver? When running as our online SaaS we store files in S3, not a filesystem, and I think this PR calls for some testing of that before we merge it. Alternatively, you can wait for it to go through integration/staging and then test it and hope it works before it reaches prod |
internal/cluster/cluster.go
Outdated
@@ -1415,7 +1415,7 @@ func (m *Manager) deleteClusterFiles(ctx context.Context, c *common.Cluster, obj | |||
var failedToDelete []string | |||
for _, file := range files { | |||
//skip log and manifests deletion when deleting cluster files | |||
if folder == "" && (strings.Contains(file, "logs") || strings.Contains(file, "manifests")) { | |||
if folder == "" && (strings.Contains(file, "logs") || strings.Contains(file, "manifests") || strings.Contains(file, "manifest-attributes")) { |
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.
Now that we can tell apart user manifests from our own service manifests, I think it's best that this function deletes the service manifests.
The original motivation for this skip was that we didn't want to destroy user uploaded manifests when the user resets their installation, but preserving the service generated ones is useless, and was just an unfortunate side-effect of protecting the user manifests. The service ones would anyway get regenerated when the user hits install again, there's no point in protecting them. If anything, clearing those manifests I think this might solve some edge case bugs I can think of
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.
I will create a ticket for this as I think it's not the primary focus of this ticket.
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.
Please link the ticket once you created it
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.
Codecov Report
Additional details and impacted files@@ Coverage Diff @@
## master #5278 +/- ##
==========================================
+ Coverage 67.48% 67.54% +0.05%
==========================================
Files 221 226 +5
Lines 33042 33272 +230
==========================================
+ Hits 22300 22475 +175
- Misses 8729 8773 +44
- Partials 2013 2024 +11
|
internal/controller/controllers/clusterdeployments_controller.go
Outdated
Show resolved
Hide resolved
b979dea
to
6cad9da
Compare
I'll test this in integration and take action if needed. I have not used any new API's so am not expecting problems in this area. |
/assign @carbonin |
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.
Do you think we could create a subsystem test to cover cases with generated manifests or even manifests that don't have the metadata file?
@@ -1156,7 +1156,8 @@ func (r *ClusterDeploymentsReconciler) syncManifests(ctx context.Context, log lo | |||
Content: swag.String(base64.StdEncoding.EncodeToString([]byte(manifest))), | |||
FileName: swag.String(filename), | |||
Folder: swag.String(models.ManifestFolderOpenshift), | |||
}}) | |||
}}, | |||
true) |
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.
Maybe create a type for this with some kind of string enum so it's more clear from the caller what this means.
That would also give us the flexibility to reference more than two options here.
internal/manifests/manifests.go
Outdated
@@ -34,6 +34,7 @@ var _ manifestsapi.ManifestsAPI = &Manifests{} | |||
|
|||
// ManifestFolder represents the manifests folder on s3 per cluster | |||
const ManifestFolder = "manifests" | |||
const ManifestMetadataFolder = "manifest-attributes" |
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.
Maybe use this in the delete cluster files function
internal/manifests/manifests.go
Outdated
func (m *Manifests) CreateClusterManifestInternal(ctx context.Context, params operations.V2CreateClusterManifestParams) (*models.Manifest, error) { | ||
const ( | ||
ManifestSourceCustomManifest string = "custom-manifest" | ||
ManifestSourceGenerated string = "generated" |
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.
This is pretty much what I was talking about in the bool -> enum comment. You just need a type definition like we do for auth here
swagger.yaml
Outdated
@@ -6655,6 +6655,10 @@ definitions: | |||
file_name: | |||
type: string | |||
description: The file name prefaced by the folder that contains it. | |||
is_custom_manifest: | |||
description: Indicates whether this is a manifest that was manually uploaded by the user, as opposed to being internally generated by the Assisted Service | |||
type: boolean |
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.
Maybe the best way to do this would be to define this as a string enum.
Then swagger will create the constants for you and you can use them in the function calls (and instead of defining them yourself).
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 should we return manifests that the user didn't generate at all? As a user, I expect to see only the manifests I created.
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.
I wondered the same - the reason is explained in the ticket - see the screenshot in that ticket:
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.
I think @avishayt asked the correct question in the ticket.
The distinction is if we want to communicate to the user where all these manifests are coming from or if we only care about showing them the ones they created. If it's the former I think a string enum is the choice, but if we only need to know if we're showing them or not then using a bool internally (not in the API) makes more sense to me.
internal/manifests/manifests.go
Outdated
|
||
func (m *Manifests) createMetadataForManifest(ctx context.Context, clusterID strfmt.UUID, path string, isCustomManifest bool) error { | ||
log := logutil.FromContext(ctx, m.log) | ||
log.Infof("Is custom manifest %t", isCustomManifest) |
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.
This message could be improved or removed.
internal/manifests/manifests.go
Outdated
log.Infof("Done deleting cluster manifest %s for cluster %s", path, params.ClusterID.String()) | ||
return nil | ||
} | ||
|
||
func (m *Manifests) UpdateClusterManifestInternal(ctx context.Context, params operations.V2UpdateClusterManifestParams) (*models.Manifest, error) { | ||
m.log.Infof("Call to update cluster manifest internal") |
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.
Clean up these logs, I don't think we need this.
internal/manifests/manifests.go
Outdated
m.log.Infof("srcFolder: %s, srcFileName: %s, srcPath: %s", srcFolder, srcFileName, srcPath) | ||
m.log.Infof("destFolder: %s, destFileName: %s, destPath: %s", destFolder, destFileName, destPath) |
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.
Same here, we can remove these debug-looking logs.
internal/manifests/manifests.go
Outdated
isCustomManifest := m.isCustomManifest(ctx, params.ClusterID.String(), srcFolder, srcFileName) | ||
if isCustomManifest != nil { | ||
err = m.createMetadataForManifest(ctx, params.ClusterID, destPath, *isCustomManifest) | ||
if err != nil { | ||
return nil, err | ||
} | ||
} |
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.
I think we only need this if src and dest path are different.
internal/manifests/manifests.go
Outdated
@@ -202,16 +282,30 @@ func (m *Manifests) UpdateClusterManifestInternal(ctx context.Context, params op | |||
return nil, err | |||
} | |||
|
|||
isCustomManifest := m.isCustomManifest(ctx, params.ClusterID.String(), srcFolder, srcFileName) |
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.
Does this mean that a user can update a generated manifest?
If not do we really need this?
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.
And even if a user updates a generated manifest, does that not make it a user manifest?
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.
I don't think there is really an opportunity to do this as manifest generation is one of the last actions before install starts, as part of the preparation phase (I think.)
This would present no opportunity for the user to override this.
internal/manifests/manifests.go
Outdated
if srcPath != destPath { | ||
m.log.Infof("Removing old manifest %s for cluster %s as the new file is at %s", srcPath, params.ClusterID.String(), destPath) | ||
err = m.deleteManifest(ctx, params.ClusterID, srcPath) | ||
if err != nil { | ||
return nil, err | ||
} | ||
if isCustomManifest != nil { |
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.
Should this be a check for nil or some value?
b6f96c3
to
ee64fc0
Compare
/retest |
@@ -1975,7 +1975,7 @@ var _ = Describe("cluster reconcile", func() { | |||
mockInstallerInternal.EXPECT().HostWithCollectedLogsExists(gomock.Any()).Return(false, nil) | |||
mockInstallerInternal.EXPECT().GetKnownHostApprovedCounts(gomock.Any()).Return(5, 5, nil).Times(2) | |||
mockManifestsApi.EXPECT().ListClusterManifestsInternal(gomock.Any(), gomock.Any()).Return(models.ListManifests{}, nil).Times(1) | |||
mockManifestsApi.EXPECT().CreateClusterManifestInternal(gomock.Any(), gomock.Any()).Return(nil, errors.Errorf("error")).Times(1) | |||
mockManifestsApi.EXPECT().CreateClusterManifestInternal(gomock.Any(), gomock.Any(), gomock.Any()).Return(nil, errors.Errorf("error")).Times(1) |
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.
true instead of gomock.Any() - for all three affected tests?
internal/manifests/manifests.go
Outdated
manifestMetadataPrefix := filepath.Join(clusterID, constants.ManifestMetadataFolder) | ||
isCustomManifest, err := m.objectHandler.DoesObjectExist(ctx, filepath.Join(manifestMetadataPrefix, folder, fileName, constants.ManifestSourceUserSupplied)) | ||
if err != nil { | ||
m.log.Warnf("Could not determine if manifest %s/%s is a %s manifest due to error %s, leaving this as nil", folder, fileName, constants.ManifestSourceUserSupplied, err.Error()) |
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.
Nobody will ever see this message... Why not propagate the error?
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.
As requested, I will propagate this error and make it visible by making it fatal.
This might lead to more actual failures when fetching manifests but will at least make those errors visible.
internal/manifests/manifests.go
Outdated
return isCustomManifest | ||
} | ||
|
||
func (m *Manifests) deleteMetadataForManifest(ctx context.Context, clusterID strfmt.UUID, path string) error { |
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.
func (m *Manifests) deleteMetadataForManifest(ctx context.Context, clusterID strfmt.UUID, path string) error { | |
func (m *Manifests) unmarkUserSuppliedManifest(ctx context.Context, clusterID strfmt.UUID, path string) error { |
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.
Because in the method name you call it "metadata", but in reality you're only dealing with "user supplied".
internal/manifests/manifests.go
Outdated
return nil | ||
} | ||
|
||
func (m *Manifests) createMetadataForManifest(ctx context.Context, clusterID strfmt.UUID, path string) error { |
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.
func (m *Manifests) createMetadataForManifest(ctx context.Context, clusterID strfmt.UUID, path string) error { | |
func (m *Manifests) markUserSuppliedManifest(ctx context.Context, clusterID strfmt.UUID, path string) error { |
internal/manifests/manifests.go
Outdated
manifestMetadataPrefix := filepath.Join(clusterID, constants.ManifestMetadataFolder) | ||
isCustomManifest, err := m.objectHandler.DoesObjectExist(ctx, filepath.Join(manifestMetadataPrefix, folder, fileName, constants.ManifestSourceUserSupplied)) |
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.
Use GetManifestMetadataObjectName()?
… endpoint. It has been reported that users have no way to determine whether or not a manifest is a custom manifest or one generated by the assisted-service. This PR introduces a change that uses the file system to store additional metadata about a manifest to indicate whether or not the manifest is a custom one. For example, if the original file is stored in ``` "e09df13f-6f31-42c2-8361-2b5605f80e77/manifests/openshift/99-openshift-machineconfig-master-kargs.yaml" ``` Then, if an only if the manifest is custom - a corresponding metadata file will be created in the following path. ``` "e09df13f-6f31-42c2-8361-2b5605f80e77/manifest-attributes/openshift/99-openshift-machineconfig-master-kargs.yaml/user-defined" ``` Any internally generated manifests are considered to be "non custom" and are created as such. All other manifests are considered to be custom and will follow the scheme above. When the user retrieves the manifest list, an additional parameter will be supplied for each manifest to indicate the custom/non custom status of the manifest.
@@ -1149,14 +1149,16 @@ func (r *ClusterDeploymentsReconciler) syncManifests(ctx context.Context, log lo | |||
|
|||
// create/update all manifests provided by configmap data | |||
for filename, manifest := range manifestsFromConfigMap { | |||
is_user_manifest := true |
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.
is_user_manifest := true | |
isUserManifest := true |
internal/manifests/manifests.go
Outdated
manifests = append(manifests, &models.Manifest{FileName: filepath.Join(parts[3:]...), Folder: parts[2]}) | ||
fileName := filepath.Join(parts[3:]...) | ||
folder := parts[2] | ||
err, is_user_manifest := m.isUserManifest(ctx, params.ClusterID, folder, fileName) |
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.
err, is_user_manifest := m.isUserManifest(ctx, params.ClusterID, folder, fileName) | |
err, isUserManifest := m.isUserManifest(ctx, params.ClusterID, folder, fileName) |
/lgtm |
[APPROVALNOTIFIER] This PR is APPROVED This pull-request has been approved by: avishayt, paul-maidment The full list of commands accepted by this bot can be found here. The pull request process is described here
Needs approval from an approver in each of these files:
Approvers can indicate their approval by writing |
@paul-maidment: all tests passed! Full PR test history. Your PR dashboard. Instructions for interacting with me using PR comments are available here. If you have questions or suggestions related to my behavior, please file an issue against the kubernetes/test-infra repository. I understand the commands that are listed here. |
… endpoint. (openshift#5278) It has been reported that users have no way to determine whether or not a manifest is a custom manifest or one generated by the assisted-service. This PR introduces a change that uses the file system to store additional metadata about a manifest to indicate whether or not the manifest is a custom one. For example, if the original file is stored in ``` "e09df13f-6f31-42c2-8361-2b5605f80e77/manifests/openshift/99-openshift-machineconfig-master-kargs.yaml" ``` Then, if an only if the manifest is custom - a corresponding metadata file will be created in the following path. ``` "e09df13f-6f31-42c2-8361-2b5605f80e77/manifest-attributes/openshift/99-openshift-machineconfig-master-kargs.yaml/user-defined" ``` Any internally generated manifests are considered to be "non custom" and are created as such. All other manifests are considered to be custom and will follow the scheme above. When the user retrieves the manifest list, an additional parameter will be supplied for each manifest to indicate the custom/non custom status of the manifest.
It has been reported that users have no way to determine whether or not a manifest is a custom manifest or one generated by the assisted-service. This PR introduces a change that uses the file system to store additional metadata about a manifest to indicate whether or not the manifest is a custom one.
For example, if the original file is stored in
Then, if an only if the manifest is custom - a corresponding metadata file will be created in the following path.
Any internally generated manifests are considered to be "non custom" and are created as such. All other manifests are considered to be custom and will follow the scheme above.
When the user retrieves the manifest list, an additional parameter will be supplied for each manifest to indicate the custom/non custom status of the manifest.
List all the issues related to this PR
What environments does this code impact?
How was this code tested?
Building a custom version of the service, creating a cluster and uploading manifests
Fetching the manifest list
Observing that behaviour is as expected.
Checklist
docs
, README, etc)Reviewers Checklist