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
Bug 1759051: Ensure that pre-labelled nodes are not re-labelled #3326
Conversation
Hi @parthdhanjal. Thanks for your PR. I'm waiting for a openshift member to verify that this patch is reasonable to test. If it is, they should reply with Once the patch is verified, the new status will be reflected by the I understand the commands that are listed here. 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. |
history.push( | ||
`/k8s/ns/${ocsProps.namespace}/clusterserviceversions/${ | ||
ocsProps.clusterServiceVersion.metadata.name | ||
}/${referenceForModel(OCSServiceModel)}/${ocsObj.metadata.name}`, |
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 resourcePathFromModel
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.
@bipuladh We need ocs.openshift.io~v1~StorageCluster
here, hence referenceForModel
is being used. Output of resourcePathFromModel
is /k8s/all-namespaces/ocs.openshift.io~v1~StorageCluster
which is not needed here
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.
resourcePathFromModel would replace the whole of the line and you can specify the namespace as per your need as well as the appName.
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.
@bipuladh resourcePathFromModel would not give us the the same path. I do feel like maybe the path used here might actually be a bug. The path to k8s resources should be standardized, and this appears at first glance to be different from the usual format.
return k8sPatch(NodeModel, node, patch); | ||
} | ||
}); | ||
promises.push(selectedNodes); |
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.
You are creating an array containing an array of promises. ([][])
I would do something in the lines of:
const promise = k8sPatch(NodeMode,node,patch);
promises.push(promise);
history.push( | ||
`/k8s/ns/${ocsProps.namespace}/clusterserviceversions/${ | ||
ocsProps.clusterServiceVersion.metadata.name | ||
}/${referenceForModel(OCSServiceModel)}/${ocsObj.metadata.name}`, | ||
); |
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 it would be easier for you to use resourcePathFromModel
.
if (promises) { | ||
Promise.all(promises) | ||
.then(() => { | ||
k8sCreate(OCSServiceModel, ocsObj) | ||
.then(() => { | ||
history.push( | ||
`/k8s/ns/${ocsProps.namespace}/clusterserviceversions/${ | ||
ocsProps.clusterServiceVersion.metadata.name | ||
}/${referenceForModel(OCSServiceModel)}/${ocsObj.metadata.name}`, | ||
); | ||
}) | ||
.catch((err) => { | ||
setProgress(false); | ||
setError(err.message); | ||
}); | ||
}) | ||
.catch((err) => { | ||
setProgress(false); | ||
setError(err.message); | ||
}); | ||
} else { | ||
k8sCreate(OCSServiceModel, ocsObj) | ||
.then(() => { | ||
history.push( | ||
`/k8s/ns/${ocsProps.namespace}/clusterserviceversions/${ | ||
ocsProps.clusterServiceVersion.metadata.name | ||
}/${referenceForModel(OCSServiceModel)}/${ocsObj.metadata.name}`, | ||
); | ||
}) | ||
.catch((err) => { | ||
setProgress(false); | ||
setError(err.message); | ||
}); | ||
} |
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.
no need for if else
. Use finally
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.
No need to use finally
here either. Promise.all() will resolve if passed an empty array. You can remove all of the conditional logic around this, and it should work fine.
promises.push(selectedNodes); | ||
return promises; |
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.
You are creating an array of array.
value: '', | ||
}, | ||
]; | ||
return k8sPatch(NodeModel, node, patch); |
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.
return k8sPatch(NodeModel, node, patch); | |
const promise = k8sPatch(NodeModel, node, patch); | |
promises.push(promise); |
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.
Creating a "const" array then pushing to it is a bit counterintuitive since constants should be immutable. I don't know why js allows this, but I think it's better practice to use a 'pure' approach like a reducer here:
const makeLabelNodesRequest = (selectedNodes: NodeKind[]): Promise<NodeKind>[] =>
_.reduce(selectedNodes, (accumulator, node) => {
// patch could actually be defined as a constant at the top level scope since it is static.
const patch = [
{
op: 'add',
path: '/metadata/labels/cluster.ocs.openshift.io~1openshift-storage',
value: '',
},
];
return isLabelPresent(node) ? accumulator : [
...accumulator,
k8sPatch(NodeModel, node, patch)
];
}, []);
@parthdhanjal: This pull request references Bugzilla bug 1759051, which is valid. The bug has been updated to refer to the pull request using the external bug tracker. 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. |
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 @bipuladh pointed out, I think there is some flawed logic in makeLabelNodesRequest
. You are returning a 2D array (which I don't think is the intention). See my comments on how this function could be improved. There are also a few "not new" things in node-list.tsx
that I think should probably be addressed in a follow on at some point. I'll leave a separate comment for that.
value: '', | ||
}, | ||
]; | ||
return k8sPatch(NodeModel, node, patch); |
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.
Creating a "const" array then pushing to it is a bit counterintuitive since constants should be immutable. I don't know why js allows this, but I think it's better practice to use a 'pure' approach like a reducer here:
const makeLabelNodesRequest = (selectedNodes: NodeKind[]): Promise<NodeKind>[] =>
_.reduce(selectedNodes, (accumulator, node) => {
// patch could actually be defined as a constant at the top level scope since it is static.
const patch = [
{
op: 'add',
path: '/metadata/labels/cluster.ocs.openshift.io~1openshift-storage',
value: '',
},
];
return isLabelPresent(node) ? accumulator : [
...accumulator,
k8sPatch(NodeModel, node, patch)
];
}, []);
if (promises) { | ||
Promise.all(promises) | ||
.then(() => { | ||
k8sCreate(OCSServiceModel, ocsObj) | ||
.then(() => { | ||
history.push( | ||
`/k8s/ns/${ocsProps.namespace}/clusterserviceversions/${ | ||
ocsProps.clusterServiceVersion.metadata.name | ||
}/${referenceForModel(OCSServiceModel)}/${ocsObj.metadata.name}`, | ||
); | ||
}) | ||
.catch((err) => { | ||
setProgress(false); | ||
setError(err.message); | ||
}); | ||
}) | ||
.catch((err) => { | ||
setProgress(false); | ||
setError(err.message); | ||
}); | ||
} else { | ||
k8sCreate(OCSServiceModel, ocsObj) | ||
.then(() => { | ||
history.push( | ||
`/k8s/ns/${ocsProps.namespace}/clusterserviceversions/${ | ||
ocsProps.clusterServiceVersion.metadata.name | ||
}/${referenceForModel(OCSServiceModel)}/${ocsObj.metadata.name}`, | ||
); | ||
}) | ||
.catch((err) => { | ||
setProgress(false); | ||
setError(err.message); | ||
}); | ||
} |
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.
No need to use finally
here either. Promise.all() will resolve if passed an empty array. You can remove all of the conditional logic around this, and it should work fine.
"Not new" issues that should probably be addressed at some point in a follow on. node-list.tsx [line 313-315] unnecessary spread operator: const promises = [];
promises.push(...makeLabelNodesRequest(selectedData)); Should just be: const promises = makeLabelNodesRequest(selectedData); node-list.tsx [line 319-320] Mutating deep object properties: Instead of creating a static export const getOCSRequestData = (storageClassName: string): K8sResourceKind => ({
apiVersion: 'ocs.openshift.io/v1',
kind: 'StorageCluster',
metadata: {
name: 'ocs-storagecluster',
namespace: 'openshift-storage',
},
spec: {
managedNodes: false,
storageDeviceSets: [
{
name: 'ocs-deviceset',
count: 3,
resources: {},
placement: {},
portable: true,
dataPVCTemplate: {
spec: {
storageClassName,
accessModes: ['ReadWriteOnce'],
volumeMode: 'Block',
resources: {
requests: {
storage: '1Ti',
},
},
},
},
},
],
},
}); Tainting logic that is commented out should not be in master |
@TheRealJon |
}, | ||
]; | ||
return k8sPatch(NodeModel, node, patch); | ||
const promises = []; |
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.
@parthdhanjal makeLabelNodesRequest definition should be like this -
const makeLabelNodesRequest = (selectedNodes: NodeKind[]): Promise<NodeKind>[] => {
return selectedNodes.map((node: NodeKind) => {
const nodeLabel = isLabelPresent(node, ocsLabel);
if (!nodeLabel) {
const patch = [
{
op: 'add',
path: '/metadata/labels/cluster.ocs.openshift.io~1openshift-storage',
value: '',
},
];
return k8sPatch(NodeModel, node, patch);
}
});
};
No need to create a promise array here and pass the ocs label explicitly so that isLabelPresent
function should be generic.
setError(err.message); | ||
}); | ||
|
||
if (promises) { |
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.
Promise.all(promises)
.then(() => {
return k8sCreate(OCSServiceModel, ocsObj);
})
.then(() => {
history.push(
`/k8s/ns/${ocsProps.namespace}/clusterserviceversions/${
ocsProps.clusterServiceVersion.metadata.name
}/${referenceForModel(OCSServiceModel)}/${ocsObj.metadata.name}`,
);
})
.catch((err) => {
setProgress(false);
setError(err.message);
});
No need of if else and no need to write separate catch for both scenarios. It can be done in one like I have mentioned above.
@@ -18,6 +18,9 @@ export const getNodeRoles = (node: NodeKind): string[] => { | |||
); | |||
}; | |||
|
|||
export const isLabelPresent = (node: NodeKind) => |
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.
export const isLabelPresent = (node: NodeKind, label: string) : boolean =>
_.has(node, ['metadata', 'labels', label]);
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 would also argue that this function probably belongs in frontend/packages/console-shared/src/selectors/common.ts
. Labels are common to all k8s resources, so this could be reused elsewhere. Also, I think 'hasLabel' is probably a more concise and accurate name.
export const hasLabel = <A extends K8sResourceKind = K8sResourceKind>(value: A, label: string) : boolean =>
_.has(value, ['metadata', 'labels', label]);
/ok-to-test |
@parthdhanjal Frontend tests are failing. Can you please check? |
frontend/packages/ceph-storage-plugin/src/components/ocs-install/node-list.tsx
Outdated
Show resolved
Hide resolved
frontend/packages/ceph-storage-plugin/src/components/ocs-install/node-list.tsx
Outdated
Show resolved
Hide resolved
@gnehapk I have to disagree with this. If you need to change part of the object when you use it, then by definition it is not constant. The number of fields being updated doesn't matter. The important thing is that we are generating a dynamic object in a reusable way. The best way to do that is with a function. |
/test images |
Fixes: https://bugzilla.redhat.com/show_bug.cgi?id=1759051 Signed-off-by: parthdhanjal <dparth@redhat.com>
/test e2e-gcp-console |
/retest |
/test e2e-gcp-console |
const patch = [ | ||
{ | ||
op: 'add', | ||
path: '/metadata/labels/cluster.ocs.openshift.io~1openshift-storage', |
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.
Out of curiousity, where does '/metadata/labels/cluster.ocs.openshift.io~1openshift-storage'
come from? the ~1openshift-storage
seems a little strange to me.
/lgtm I believe @TheRealJon is going to create a few follow-up chores in Jira to address some of the items he mentioned above. |
[APPROVALNOTIFIER] This PR is APPROVED This pull-request has been approved by: benjaminapetersen, cloudbehl, gnehapk, parthdhanjal, TheRealJon 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 |
/retest |
/retest Please review the full test history for this PR and help us cut down flakes. |
11 similar comments
/retest Please review the full test history for this PR and help us cut down flakes. |
/retest Please review the full test history for this PR and help us cut down flakes. |
/retest Please review the full test history for this PR and help us cut down flakes. |
/retest Please review the full test history for this PR and help us cut down flakes. |
/retest Please review the full test history for this PR and help us cut down flakes. |
/retest Please review the full test history for this PR and help us cut down flakes. |
/retest Please review the full test history for this PR and help us cut down flakes. |
/retest Please review the full test history for this PR and help us cut down flakes. |
/retest Please review the full test history for this PR and help us cut down flakes. |
/retest Please review the full test history for this PR and help us cut down flakes. |
/retest Please review the full test history for this PR and help us cut down flakes. |
@parthdhanjal: All pull requests linked via external trackers have merged. Bugzilla bug 1759051 has been moved to the MODIFIED state. 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. |
@spadgett: new pull request created: #3591 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. |
Fixes: https://bugzilla.redhat.com/show_bug.cgi?id=1759051
Signed-off-by: parthdhanjal dparth@redhat.com