Skip to content
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

Fix issue where delete command fails to delete apps with volumesets #123

Merged
merged 3 commits into from
Jan 4, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ _Please add entries here for your pull requests that are not yet released._

- Fixed issue where `info` command does not respect `CPLN_ORG` env var. [PR 88](https://github.com/shakacode/heroku-to-control-plane/pull/88) by [Rafael Gomes](https://github.com/rafaelgomesxyz).
- Fixed issues with running `cpl --version` and `cpl --help` where no configuration file exists. [PR 100](https://github.com/shakacode/heroku-to-control-plane/pull/100) by [Mostafa Ahangarha](https://github.com/ahangarha).
- Fixed issue where `delete` command fails to delete apps with volumesets. [PR 123](https://github.com/shakacode/heroku-to-control-plane/pull/123) by [Rafael Gomes](https://github.com/rafaelgomesxyz).

### Added

Expand Down
2 changes: 1 addition & 1 deletion docs/commands.md
Original file line number Diff line number Diff line change
Expand Up @@ -100,7 +100,7 @@ cpl copy-image-from-upstream -a $APP_NAME --upstream-token $UPSTREAM_TOKEN --ima

### `delete`

- Deletes the whole app (GVC with all workloads and all images)
- Deletes the whole app (GVC with all workloads, all volumesets and all images)
- Will ask for explicit user confirmation

```sh
Expand Down
51 changes: 40 additions & 11 deletions lib/command/delete.rb
Original file line number Diff line number Diff line change
Expand Up @@ -7,21 +7,45 @@ class Delete < Base
app_option(required: true),
skip_confirm_option
].freeze
DESCRIPTION = "Deletes the whole app (GVC with all workloads and all images)"
DESCRIPTION = "Deletes the whole app (GVC with all workloads, all volumesets and all images)"
LONG_DESCRIPTION = <<~DESC
- Deletes the whole app (GVC with all workloads and all images)
- Deletes the whole app (GVC with all workloads, all volumesets and all images)
- Will ask for explicit user confirmation
DESC

def call
return progress.puts("App '#{config.app}' does not exist.") if cp.fetch_gvc.nil?

check_volumesets
check_images
return unless confirm_delete

delete_volumesets
delete_gvc
delete_images
end

private

def check_volumesets
@volumesets = cp.fetch_volumesets["items"]
return progress.puts("No volumesets to delete.") unless @volumesets.any?

message = "The following volumesets will be deleted along with the app:"
volumesets_list = @volumesets.map { |volumeset| "- #{volumeset['name']}" }.join("\n")
progress.puts("#{Shell.color(message, :red)}\n#{volumesets_list}\n\n")
end

def check_images
@images = cp.query_images["items"]
.select { |image| image["name"].start_with?("#{config.app}:") }
return progress.puts("No images to delete.") unless @images.any?

message = "The following images will be deleted along with the app:"
images_list = @images.map { |image| "- #{image['name']}" }.join("\n")
progress.puts("#{Shell.color(message, :red)}\n#{images_list}\n\n")
end

def confirm_delete
return true if config.options[:yes]

Expand All @@ -33,22 +57,27 @@ def confirm_delete
end

def delete_gvc
return progress.puts("App '#{config.app}' does not exist.") if cp.fetch_gvc.nil?

step("Deleting app '#{config.app}'") do
cp.gvc_delete
end
end

def delete_images
images = cp.query_images["items"]
.filter_map { |item| item["name"] if item["name"].start_with?("#{config.app}:") }
def delete_volumesets
@volumesets.each do |volumeset|
step("Deleting volumeset '#{volumeset['name']}'") do
# If the volumeset is attached to a workload, we need to delete the workload first
workload = volumeset.dig("status", "usedByWorkload")&.split("/")&.last
cp.delete_workload(workload) if workload

return progress.puts("No images to delete.") unless images.any?
cp.delete_volumeset(volumeset["name"])
end
end
end

images.each do |image|
step("Deleting image '#{image}'") do
cp.image_delete(image)
def delete_images
@images.each do |image|
step("Deleting image '#{image['name']}'") do
cp.image_delete(image["name"])
end
end
end
Expand Down
10 changes: 10 additions & 0 deletions lib/core/controlplane.rb
Original file line number Diff line number Diff line change
Expand Up @@ -235,6 +235,16 @@ def workload_exec(workload, location:, container: nil, command: nil)
perform!(cmd)
end

# volumeset

def fetch_volumesets(a_gvc = gvc)
api.list_volumesets(org: org, gvc: a_gvc)
end

def delete_volumeset(volumeset, a_gvc = gvc)
api.delete_volumeset(org: org, gvc: a_gvc, volumeset: volumeset)
end

# domain

def find_domain_route(data)
Expand Down
10 changes: 9 additions & 1 deletion lib/core/controlplane_api.rb
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# frozen_string_literal: true

class ControlplaneApi
class ControlplaneApi # rubocop:disable Metrics/ClassLength
def gvc_list(org:)
api_json("/org/#{org}/gvc", method: :get)
end
Expand Down Expand Up @@ -86,6 +86,14 @@ def delete_workload(org:, gvc:, workload:)
api_json("/org/#{org}/gvc/#{gvc}/workload/#{workload}", method: :delete)
end

def list_volumesets(org:, gvc:)
api_json("/org/#{org}/gvc/#{gvc}/volumeset", method: :get)
end

def delete_volumeset(org:, gvc:, volumeset:)
api_json("/org/#{org}/gvc/#{gvc}/volumeset/#{volumeset}", method: :delete)
end

def list_domains(org:)
api_json("/org/#{org}/domain", method: :get)
end
Expand Down