lib/command/setup_app.rb in cpl-1.4.0 vs lib/command/setup_app.rb in cpl-2.2.0

- old
+ new

@@ -3,44 +3,111 @@ module Command class SetupApp < Base NAME = "setup-app" OPTIONS = [ app_option(required: true), - skip_secret_access_binding_option + skip_secret_access_binding_option, + skip_secrets_setup_option, + skip_post_creation_hook_option ].freeze DESCRIPTION = "Creates an app and all its workloads" LONG_DESCRIPTION = <<~DESC - Creates an app and all its workloads - Specify the templates for the app and workloads through `setup_app_templates` in the `.controlplane/controlplane.yml` file - - This should only be used for temporary apps like review apps, never for persistent apps like production (to update workloads for those, use 'cpl apply-template' instead) - - Automatically binds the app to the secrets policy, as long as both the identity and the policy exist - - Use `--skip-secret-access-binding` to prevent the automatic bind + - This should only be used for temporary apps like review apps, never for persistent apps like production or staging (to update workloads for those, use 'cpl apply-template' instead) + - Configures app to have org-level secrets with default name "{APP_PREFIX}-secrets" + using org-level policy with default name "{APP_PREFIX}-secrets-policy" (names can be customized, see docs) + - Creates identity for secrets if it does not exist + - Use `--skip-secrets-setup` to prevent the automatic setup of secrets, + or set it through `skip_secrets_setup` in the `.controlplane/controlplane.yml` file + - Runs a post-creation hook after the app is created if `hooks.post_creation` is specified in the `.controlplane/controlplane.yml` file + - If the hook exits with a non-zero code, the command will stop executing and also exit with a non-zero code + - Use `--skip-post-creation-hook` to skip the hook if specified in `controlplane.yml` DESC + VALIDATIONS = %w[config templates].freeze - def call # rubocop:disable Metrics/MethodLength + def call # rubocop:disable Metrics/CyclomaticComplexity, Metrics/MethodLength templates = config[:setup_app_templates] app = cp.fetch_gvc if app raise "App '#{config.app}' already exists. If you want to update this app, " \ "either run 'cpl delete -a #{config.app}' and then re-run this command, " \ "or run 'cpl apply-template #{templates.join(' ')} -a #{config.app}'." end - Cpl::Cli.start(["apply-template", *templates, "-a", config.app]) + skip_secrets_setup = config.options[:skip_secret_access_binding] || + config.options[:skip_secrets_setup] || config.current[:skip_secrets_setup] - return if config.options[:skip_secret_access_binding] + create_secret_and_policy_if_not_exist unless skip_secrets_setup + args = [] + args.push("--add-app-identity") unless skip_secrets_setup + Cpl::Cli.start(["apply-template", *templates, "-a", config.app, *args]) + + bind_identity_to_policy unless skip_secrets_setup + run_post_creation_hook unless config.options[:skip_post_creation_hook] + end + + private + + def create_secret_and_policy_if_not_exist + create_secret_if_not_exists + create_policy_if_not_exists + progress.puts + end - if cp.fetch_identity(app_identity).nil? || cp.fetch_policy(app_secrets_policy).nil? - raise "Can't bind identity to policy: identity '#{app_identity}' or " \ - "policy '#{app_secrets_policy}' doesn't exist. " \ - "Please create them or use `--skip-secret-access-binding` to ignore this message." + def create_secret_if_not_exists + if cp.fetch_secret(config.secrets) + progress.puts("Secret '#{config.secrets}' already exists. Skipping creation...") + else + step("Creating secret '#{config.secrets}'") do + cp.apply_hash(build_secret_hash) + end end + end - step("Binding identity to policy") do - cp.bind_identity_to_policy(app_identity_link, app_secrets_policy) + def create_policy_if_not_exists + if cp.fetch_policy(config.secrets_policy) + progress.puts("Policy '#{config.secrets_policy}' already exists. Skipping creation...") + else + step("Creating policy '#{config.secrets_policy}'") do + cp.apply_hash(build_policy_hash) + end end + end + + def build_secret_hash + { + "kind" => "secret", + "name" => config.secrets, + "type" => "dictionary", + "data" => {} + } + end + + def build_policy_hash + { + "kind" => "policy", + "name" => config.secrets_policy, + "targetKind" => "secret", + "targetLinks" => ["//secret/#{config.secrets}"] + } + end + + def bind_identity_to_policy + progress.puts + + step("Binding identity '#{config.identity}' to policy '#{config.secrets_policy}'") do + cp.bind_identity_to_policy(config.identity_link, config.secrets_policy) + end + end + + def run_post_creation_hook + post_creation_hook = config.current.dig(:hooks, :post_creation) + return unless post_creation_hook + + run_command_in_latest_image(post_creation_hook, title: "post-creation hook") end end end