Conversation
|
|
||
| [NOTE] | ||
| ==== | ||
| The uninstall command deletes the namespace the demo was installed in. Therefore it is not possible to uninstall demos in the `default` namespace. |
There was a problem hiding this comment.
I feel like this should be opt-in behaviour. Or rather, if we created the namespace, it gets deleted.
There could be existing namespaces that shouldn't be deleted.
There was a problem hiding this comment.
One such example is if we have the monitoring stack installed, and want to add and remove demos.
There was a problem hiding this comment.
According to #187 (comment) "Update after a discussion on 2025-11-26:" it was decided the first version provides no option to be less destructive. Not sure which meeting that was or if it makes sense to change the requirements now.
There was a problem hiding this comment.
There were also problems with deleting everything without deleting the namespace, see stackabletech/hdfs-operator#761 (comment). So maybe for the first version / MVP it is fine for now like this? But feel free to disagree
There was a problem hiding this comment.
I left an idea below in how we could do it: #429 (comment)
But of course, if this implements what we agreed on, that's fine.
It does feel a little dangerous though.
There was a problem hiding this comment.
Yes, I agree it feels dangerous, tried to avoid it at first but ran into the problems above, which unfortunately won't be solved by your idea I think. The manifests we would delete with that approach were also deleted with the help of the labels, so would be the same situation, unless I misunderstood something 😞
Another thing might be adding a confirmation dialogue like the one I added to the installation for the namespace. That it asks if the user really wants to uninstall since that would delete the namespace, and cancel the deletion otherwise.
|
|
||
| [NOTE] | ||
| ==== | ||
| The uninstall command deletes the namespace the stack was installed in. Therefore it is not possible to uninstall stacks in the `default` namespace. |
There was a problem hiding this comment.
Same as my comment about demos.
NickLarsenNZ
left a comment
There was a problem hiding this comment.
Left a couple of comments about namespace deletion.
| // Delete demo namespace | ||
| client | ||
| .delete_object( | ||
| &uninstall_parameters.demo_namespace, | ||
| &ApiResource::from_gvk(&GroupVersionKind { | ||
| group: "".to_owned(), | ||
| version: "v1".to_owned(), | ||
| kind: "Namespace".to_owned(), | ||
| }), | ||
| None, | ||
| ) | ||
| .await | ||
| .context(DeleteObjectSnafu)?; |
There was a problem hiding this comment.
Here's where I think we should have a check to see if the namespace was "owned" by the demo (via labels/annotations).
There was a problem hiding this comment.
One thing we could consider is reading in the demo, get the GVKs and Helm charts, and uninstall in reverse order before uninstalling the namespace (if it was created by the demo).
Same would apply for stacks.
That could be a follow-up PR, but I think at least we should be careful with namespace deletion.
| // Delete stack namespace | ||
| client | ||
| .delete_object( | ||
| &uninstall_parameters.stack_namespace, | ||
| &ApiResource::from_gvk(&GroupVersionKind { | ||
| group: "".to_owned(), | ||
| version: "v1".to_owned(), | ||
| kind: "Namespace".to_owned(), | ||
| }), | ||
| None, | ||
| ) | ||
| .await | ||
| .context(DeleteObjectSnafu)?; |
Techassi
left a comment
There was a problem hiding this comment.
Left a few comments and questions.
| transfer_client: &xfer::Client, | ||
| stack: StackSpec, | ||
| ) -> Result<(), Error> { | ||
| // Uninstall Helm Charts |
There was a problem hiding this comment.
note: I think this comments seems misplaced and needs to move a few lines lower.
| // Delete demo namespace | ||
| client | ||
| .delete_object( | ||
| &uninstall_parameters.demo_namespace, | ||
| &ApiResource::from_gvk(&GroupVersionKind { | ||
| group: "".to_owned(), | ||
| version: "v1".to_owned(), | ||
| kind: "Namespace".to_owned(), | ||
| }), | ||
| None, | ||
| ) | ||
| .await | ||
| .context(DeleteObjectSnafu)?; |
There was a problem hiding this comment.
note: I think we should abstract that away in an associated function called delete_namespace similar to what we have to create a namespace. See:
stackable-cockpit/rust/stackable-cockpit/src/utils/k8s/client.rs
Lines 443 to 460 in 32cf847
| "stackable.tech/demo", | ||
| &uninstall_parameters.demo_name, |
There was a problem hiding this comment.
question: Do we want to use a validated Label instead of a free-form string here?
| #[cfg_attr(feature = "openapi", derive(ToSchema))] | ||
| pub struct StackSpec { | ||
| /// A short description of the demo | ||
| /// A short description of the stack |
| parameters.insert("STACK".to_owned(), stack_name.into()); | ||
| if let Some(demo_name) = demo_name { | ||
| parameters.insert("DEMO".to_owned(), demo_name.into()); | ||
| } |
There was a problem hiding this comment.
question: Just that we are on the same track: These are now added earlier and are part of the passed parameters, right?
question: Out of curiosity, what was the reason you did that? I assume the demo and stack name are needed earlier in the call chain now?
| if let Some(objectlist) = objects { | ||
| for object in objectlist { | ||
| if let Some(value) = object.labels().get(label_key) { | ||
| if value.eq(label_value) { | ||
| self.delete_object( | ||
| &object.metadata.name.unwrap(), | ||
| &api_resource, | ||
| object.metadata.namespace.as_deref(), | ||
| ) | ||
| .await?; | ||
| } | ||
| } | ||
| } | ||
| } | ||
| } |
There was a problem hiding this comment.
note: I think we should try reducing the amount of right-shift here. We might be able to use something like:
let Some(object_list) = objects else {
continue;
}| while let Ok(delete_status) = delete_request { | ||
| match delete_status { | ||
| // Left side of Either, when deletion is in progress | ||
| either::Either::Left(_) => { | ||
| Span::current() | ||
| .pb_set_message(&format!("Deleting {} {}", api_resource.kind, object_name)); | ||
| // Short sleep to reduce number of requests | ||
| sleep(time::Duration::from_millis(600)).await; | ||
| // Resend request to get deletion status | ||
| delete_request = object_api | ||
| .delete(object_name, &DeleteParams::foreground()) | ||
| .await; | ||
| } | ||
| // Right side of Either, when deletion is done | ||
| either::Either::Right(_) => { | ||
| return Ok(()); | ||
| } | ||
| } | ||
| } |
There was a problem hiding this comment.
note: We might want to use kube's is_deleted for this instead: https://docs.rs/kube/latest/kube/runtime/wait/conditions/fn.is_deleted.html
| let demo_namespace = tracing_indicatif::suspend_tracing_indicatif( | ||
| || -> Result<String, CmdError> { | ||
| if args.namespaces.namespace == DEFAULT_NAMESPACE { | ||
| if Confirm::new() | ||
| .with_prompt( | ||
| format!( | ||
| "Demos installed in the '{DEFAULT_NAMESPACE}' namespace cannot be uninstalled with stackablectl. Install the demo in the '{demo_namespace}' namespace instead?", | ||
| demo_namespace = args.demo_name.clone()) | ||
| ) | ||
| .default(true) | ||
| .interact() | ||
| .context(ConfirmDialogSnafu)? { | ||
| // User selected to install in suggested namespace | ||
| Ok(args.demo_name.clone()) | ||
| } else { | ||
| // User selected to install in default namespace | ||
| Ok(args.namespaces.namespace.clone()) | ||
| } | ||
| } else { | ||
| Ok(args.namespaces.namespace.clone()) | ||
| } | ||
| }, | ||
| )?; |
There was a problem hiding this comment.
note: Well that's a mouthful to read. Can we somehow make this easier to grasp?
| if Confirm::new() | ||
| .with_prompt( | ||
| format!( | ||
| "Demos installed in the '{DEFAULT_NAMESPACE}' namespace cannot be uninstalled with stackablectl. Install the demo in the '{demo_namespace}' namespace instead?", |
There was a problem hiding this comment.
note: Use the debug impl for String instead, which already includes quotes:
| "Demos installed in the '{DEFAULT_NAMESPACE}' namespace cannot be uninstalled with stackablectl. Install the demo in the '{demo_namespace}' namespace instead?", | |
| "Demos installed in the {DEFAULT_NAMESPACE:?} namespace cannot be uninstalled with stackablectl. Install the demo in the {demo_namespace:?} namespace instead?", |
| .context(BuildListSnafu)?; | ||
|
|
||
| // Get the stack spec based on the name defined in the demo spec | ||
| let stack = stack_list.get(&demo.stack).context(NoSuchStackSnafu { |
There was a problem hiding this comment.
note: already extracting the stack here (and then having to clone it via to_owned below) is a completely different approach compared to installing a demo. Why don't we use the same approach here as well?
Description
Part of #187
This PR adds the
uninstallsubcommands todemoandstackcommands. It implements the MVP features mentioned here #187 (comment)The flag of skipping operators and CRD deletion was optional and I wasn't sure about the naming or if needs to be one command or two. Can also be just removed, added it because it was not much additional work.
Tested with all current demos/stacks. Some demos have edge cases in the deletion, will document that in the parent issue.
This PR also contains thestripped out into #432DEMO/STACKparameter addition for stackabletech/demos#374 (comment)Definition of Done Checklist
Author
Reviewer
Acceptance