Skip to content

Commit

Permalink
Building out full deploy
Browse files Browse the repository at this point in the history
  • Loading branch information
timothysmith0609 committed Feb 13, 2025
1 parent ba2b558 commit 673f608
Show file tree
Hide file tree
Showing 5 changed files with 196 additions and 86 deletions.
222 changes: 138 additions & 84 deletions lib/krane/cli/full_deploy_command.rb
Original file line number Diff line number Diff line change
@@ -1,88 +1,142 @@
# frozen_string_literal: true

class FullDeployCommand
DEFAULT_DEPLOY_TIMEOUT = "300s"
OPTIONS = {
# Command args
"command-timeout" => {
type: :string,
banner: "duration",
default: DEFAULT_DEPLOY_TIMEOUT,
desc: "Max duration to monitor workloads correctly deployed. " \
"The timeout is applied separately to the global and namespaced deploy steps",
},
"filenames" => {
type: :array,
banner: "config/deploy/production config/deploy/my-extra-resource.yml",
aliases: :f,
required: false,
default: [],
desc: "Directories and files that contains the configuration to apply",
},
"stdin" => {
type: :boolean,
default: false,
desc: "[DEPRECATED] Read resources from stdin",
},
"verbose-log-prefix" => {
type: :boolean,
desc: "Add [context][namespace] to the log prefix",
default: false,
},
require 'krane/cli/deploy_command'
require 'krane/cli/global_deploy_command'

# Global deploy args
"global-selector" => {
type: :string,
banner: "'label=value'",
required: true,
desc: "Select workloads owned by selector(s)",
},
"global-selector-as-filter" => {
type: :boolean,
desc: "Use --selector as a label filter to deploy only a subset " \
"of the provided resources",
default: false,
},
"global-prune" => {
type: :boolean,
desc: "Enable deletion of resources that match " \
"the provided selector and do not appear in the provided templates",
default: true,
},
"global-verify-result" => {
type: :boolean,
default: true,
desc: "Verify workloads correctly deployed",
},
module Krane
module CLI
class FullDeployCommand
DEFAULT_DEPLOY_TIMEOUT = "300s"
OPTIONS = {
# Command args
"filenames" => {
type: :array,
banner: "config/deploy/production config/deploy/my-extra-resource.yml",
aliases: :f,
required: false,
default: [],
desc: "Directories and files that contains the configuration to apply",
},
"stdin" => {
type: :boolean,
default: false,
desc: "[DEPRECATED] Read resources from stdin",
},
"verbose-log-prefix" => {
type: :boolean,
desc: "Add [context][namespace] to the log prefix",
default: false,
},

# Namespaced deploy args
"protected-namespaces" => {
type: :array,
banner: "namespace1 namespace2 namespaceN",
desc: "Enable deploys to a list of selected namespaces; set to an empty string " \
"to disable",
default: PROTECTED_NAMESPACES,
},
"prune" => {
type: :boolean,
desc: "Enable deletion of resources that do not appear in the template dir",
default: true,
},
"selector-as-filter" => {
type: :boolean,
desc: "Use --selector as a label filter to deploy only a subset " \
"of the provided resources",
default: false,
},
"selector" => {
type: :string,
banner: "'label=value'",
desc: "Select workloads by selector(s)",
},
"verify-result" => {
type: :boolean,
default: true,
desc: "Verify workloads correctly deployed",
},
}
end
# Global deploy args
"global-selector" => {
type: :string,
banner: "'label=value'",
required: true,
desc: "Select workloads owned by selector(s)",
},
"global-selector-as-filter" => {
type: :boolean,
desc: "Use --selector as a label filter to deploy only a subset " \
"of the provided resources",
default: false,
},
"global-prune" => {
type: :boolean,
desc: "Enable deletion of resources that match " \
"the provided selector and do not appear in the provided templates",
default: true,
},
"global-verify-result" => {
type: :boolean,
default: true,
desc: "Verify workloads correctly deployed",
},

# Namespaced deploy args
"protected-namespaces" => {
type: :array,
banner: "namespace1 namespace2 namespaceN",
desc: "Enable deploys to a list of selected namespaces; set to an empty string " \
"to disable",
default: DeployCommand::PROTECTED_NAMESPACES,
},
"prune" => {
type: :boolean,
desc: "Enable deletion of resources that do not appear in the template dir",
default: true,
},
"selector-as-filter" => {
type: :boolean,
desc: "Use --selector as a label filter to deploy only a subset " \
"of the provided resources",
default: false,
},
"selector" => {
type: :string,
banner: "'label=value'",
desc: "Select workloads by selector(s)",
},
"verify-result" => {
type: :boolean,
default: true,
desc: "Verify workloads correctly deployed",
},
}

def self.from_options(namespace, context, options)
require 'krane/global_deploy_task'
require 'krane/options_helper'
require 'krane/label_selector'
require 'krane/duration_parser'

logger = ::Krane::FormattedLogger.build(namespace, context, verbose_prefix: options['verbose-log-prefix'])

protected_namespaces = options['protected-namespaces']
if options['protected-namespaces'].size == 1 && %w('' "").include?(options['protected-namespaces'][0])
protected_namespaces = []
end

global_selector = ::Krane::LabelSelector.parse(options["global-selector"])
global_selector_as_filter = options['selector-as-filter']
if global_selector_as_filter && !global_selector
raise(Thor::RequiredArgumentMissingError, '--selector must be set when --selector-as-filter is set')
end

selector = ::Krane::LabelSelector.parse(options[:selector]) if options[:selector]
selector_as_filter = options['selector-as-filter']
if selector_as_filter && !selector
raise(Thor::RequiredArgumentMissingError, '--selector must be set when --selector-as-filter is set')
end

filenames = options[:filenames].dup
filenames << "-" if options[:stdin]
if filenames.empty?
raise(Thor::RequiredArgumentMissingError, '--filenames must be set and not empty')
end

::Krane::OptionsHelper.with_processed_template_paths(filenames) do |paths|
full_deploy = ::Krane::FullDeployTask.new(
namespace: namespace,
context: context,
filenames: paths,
logger: logger,
selector: selector,
selector_as_filter: selector_as_filter,
protected_namespaces: protected_namespaces,
global_timeout: ::Krane::DurationParser.new(options["global-timeout"]).parse!.to_i,
global_selector: global_selector,
global_selector_as_filter: global_selector_as_filter,
)

full_deploy.run!(
global_prune: options['global-prune'],
global_verify_result: options['global-verify-result'],
verify_result: options['verify-result'],
prune: options('prune'),
)
end
end
end
end
end
1 change: 1 addition & 0 deletions lib/krane/cli/krane.rb
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
require 'krane'
require 'krane/cli/deploy_command'
require 'krane/cli/global_deploy_command'
require 'krane/cli/full_deploy_command'
require 'krane/cli/render_command'
require 'krane/cli/restart_command'
require 'krane/cli/run_command'
Expand Down
55 changes: 55 additions & 0 deletions lib/krane/full_deploy_task.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
# frozen_string_literal: true

module Krane
class FullDeployTask
extend Krane::StatsD::MeasureMethods
include TemplateReporting
delegate :context, :logger, :global_kinds, :kubeclient_builder, to: :@task_config
attr_reader :task_config

# Initializes the deploy task
#
# @param namespace [String] Kubernetes namespace (*required*)
# @param context [String] Kubernetes context (*required*)
# @param global_timeout [Integer] Timeout in seconds
# @param global_selector [Hash] Global selector(s) parsed by Krane::LabelSelector (*required*)
# @param global_selector_as_filter [Boolean] Allow selecting a subset of Kubernetes resource during global deploy
# @param selector [Hash] Selector(s) parsed by Krane::LabelSelector (*required*)
# @param selector_as_filter [Boolean] Allow selecting a subset of Kubernetes resource templates to deploy
# @param filenames [Array<String>] An array of filenames and/or directories containing templates (*required*)
# @param protected_namespaces [Array<String>] Array of protected Kubernetes namespaces (defaults
def initialize(namespace:, context:, global_timeout: nil, global_selector: nil, global_selector_as_filter: false, selector: nil,
selector_as_filter: false, filenames: [], logger: nil, protected_namespaces: nil, kubeconfig: nil)
@logger = logger || Krane::FormattedLogger.build(namespace, context)
@template_sets = TemplateSets.from_dirs_and_files(paths: filenames, logger: @logger, render_erb: false)
@task_config = TaskConfig.new(context, namespace, logger, kubeconfig)
@global_timeout = global_timeout
@global_selector = global_selector
@global_selector_as_filter = global_selector_as_filter
@selector = selector
@selector_as_filter = selector_as_filter
@protected_namespaces = protected_namespaces
end

# Runs the task, returning a boolean representing success or failure
#
# @return [Boolean]
def run(**args)
run!(**args)
true
rescue FatalDeploymentError
false
end

# Runs the task, raising exceptions in case of issues
#
# @param verify_result [Boolean] Wait for completion and verify success
# @param prune [Boolean] Enable deletion of resources that do not appear in the template dir
#
# @return [nil]
def run!(global_verify_result: true, global_prune: true, verify_result: true, prune: true)
start = Time.now.utc
logger.reset
end
end
end
2 changes: 1 addition & 1 deletion lib/krane/render_task.rb
Original file line number Diff line number Diff line change
Expand Up @@ -93,7 +93,7 @@ def validate_configuration(template_sets)
end

if !@current_sha.nil? && @current_sha.empty?
errors << "current-sha is optional but can not be blank"
errors << "`current-sha is optional but can not be blank"
end
errors += template_sets.validate

Expand Down
2 changes: 1 addition & 1 deletion lib/krane/template_sets.rb
Original file line number Diff line number Diff line change
Expand Up @@ -96,7 +96,7 @@ def templates(filename:, raw:)
private_constant :TemplateSet

class << self
def from_dirs_and_files(paths:, logger:, render_erb: true)
def from_dirs_and_files(paths:, logger:, render_erb: true, partition: false)
resource_templates = {}
dir_paths, file_paths = paths.partition { |path| File.directory?(path) }

Expand Down

0 comments on commit 673f608

Please sign in to comment.