class Kitchen::Driver::Pulumi
Driver
class implementing the CLI equivalency between Kitchen
and Pulumi
@author Jacob Learned
Public Instance Methods
Get the value of the config file to use, if set on instance or provided as param, optionally as a command line flag `–config-file`
@param conf_file [String] path to a stack config file to use for configuration @param flag [Boolean] specify true to prepend '–config-file ' to the config file @return [String] the path to the config file or its corresponding CLI flag
# File lib/kitchen/driver/pulumi.rb, line 221 def config_file(conf_file = '', flag: false) file = conf_file.empty? ? config_config_file : conf_file return '' if File.directory?(file) || file.empty? return "--config-file #{file}" if flag file end
Configures a stack in the current directory unless another is provided
@param stack_confs [::Hash] hash specifying the stack config for the instance @param stack [String] name of the stack to configure @param conf_file [String] path to a stack config file to use for configuration @param dir [String] path to the directory to run Pulumi
commands in @param is_secret [Boolean] specify true to set the given stack config as secrets @return [void]
# File lib/kitchen/driver/pulumi.rb, line 185 def configure(stack_confs, stack, conf_file, dir = '', is_secret: false) secret = is_secret ? '--secret' : '' config_flag = config_file(conf_file, flag: true) base_cmd = "config set #{secret} -s #{stack} #{dir} #{config_flag}" stack_confs.each do |namespace, stack_settings| stack_settings.each do |key, val| ::Kitchen::Pulumi::ShellOut.run( cmd: "#{base_cmd} #{namespace}:#{key} \"#{val}\"", logger: logger, ) end end end
Initializes a stack via `pulumi stack init` & run a preview of changes
@param _state [::Hash] the current kitchen state @return [void]
# File lib/kitchen/driver/pulumi.rb, line 55 def create(_state) dir = "-C #{config_directory}" login initialize_stack(stack, dir) ::Kitchen::Pulumi.with_temp_conf(config_file) do |temp_conf_file| refresh_config(stack, temp_conf_file, dir) if config_refresh_config configure(config_config, stack, temp_conf_file, dir) configure(config_secrets, stack, temp_conf_file, dir, is_secret: true) preview_stack(stack, temp_conf_file, dir) end end
Destroys a stack via `pulumi destroy`
@param _state [::Hash] the current kitchen state @return [void]
# File lib/kitchen/driver/pulumi.rb, line 103 def destroy(_state) dir = "-C #{config_directory}" cmds = [ "destroy -y -r --show-config -s #{stack} #{dir}", "stack rm #{preserve_config} -y -s #{stack} #{dir}", ] login ::Kitchen::Pulumi::ShellOut.run(cmd: cmds, logger: logger) rescue ::Kitchen::Pulumi::Error => e if e.message.match?(/no stack named '#{stack}' found/) || ( e.message.match?(/failed to load checkpoint/) && config_backend == 'local' ) puts "Stack '#{stack}' does not exist, continuing..." end end
Evolves a stack via successive calls to `pulumi config set` and `pulumi up` according to the `stack_evolution` instance attribute, if set. This permits testing stack config changes over time.
@param (see refresh_config
) @param config_only [Boolean] specify true to prevent running `pulumi up` @return [void]
# File lib/kitchen/driver/pulumi.rb, line 263 def evolve_stack(stack, conf_file, dir = '', config_only: false) config_stack_evolution.each do |evolution| new_conf_file = config_file(evolution.fetch(:config_file, '')) new_stack_confs = evolution.fetch(:config, {}) new_stack_secrets = evolution.fetch(:secrets, {}) rewrite_config_file(new_conf_file, conf_file) configure(new_stack_confs, stack, conf_file, dir) configure(new_stack_secrets, stack, conf_file, dir, is_secret: true) update_stack(stack, conf_file, dir) unless config_only end end
Initializes a stack in the current directory unless another is provided
@param stack [String] name of the stack to initialize @param dir [String] path to the directory to run Pulumi
commands in
# File lib/kitchen/driver/pulumi.rb, line 168 def initialize_stack(stack, dir = '') ::Kitchen::Pulumi::ShellOut.run( cmd: "stack init #{stack} #{dir} #{secrets_provider(flag: true)}", logger: logger, ) rescue ::Kitchen::Pulumi::Error => e puts 'Continuing...' if e.message.match?(/stack '#{stack}' already exists/) end
Logs in to the Pulumi
backend set for the instance via `pulumi login`
@return [void]
# File lib/kitchen/driver/pulumi.rb, line 156 def login backend = config_backend == 'local' ? '--local' : config_backend ::Kitchen::Pulumi::ShellOut.run( cmd: "login #{backend}", logger: logger, ) end
Returns `–preserve-config` if the `preserve_config` instance attribute is set
@return [String] either `''` or `–preserve-config`
# File lib/kitchen/driver/pulumi.rb, line 124 def preserve_config return '' unless config_preserve_config '--preserve-config' end
Preview effects of `pulumi up`
@param stack [String] name of the stack being refreshed @param conf_file [String] path to a stack config file to use for configuration @param dir [String] path to the directory to run Pulumi
commands in @return [void]
# File lib/kitchen/driver/pulumi.rb, line 248 def preview_stack(stack, conf_file, dir = '') base_cmd = "preview -r --show-config -s #{stack} #{dir}" ::Kitchen::Pulumi::ShellOut.run( cmd: "#{base_cmd} #{config_file(conf_file, flag: true)}", logger: logger, ) end
Refreshes a stack's config on the specified config file
@param stack [String] name of the stack being refreshed @param conf_file [String] path to a stack config file to use for configuration @param dir [String] path to the directory to run Pulumi
commands in @return [void]
# File lib/kitchen/driver/pulumi.rb, line 206 def refresh_config(stack, conf_file, dir = '') ::Kitchen::Pulumi::ShellOut.run( cmd: "config refresh -s #{stack} #{dir} #{config_file(conf_file, flag: true)}", logger: logger, ) rescue ::Kitchen::Pulumi::Error => e puts 'Continuing...' if e.message.match?(/no previous deployment/) end
Rewrites a temporary config file by merging the contents of the new config file into the old config file. This is used during stack evolution to ensure that stack config changes for each evolution step are implemented correctly if the user has provided a new config file to use for a step.
@param new_conf_file [String] the path to the new config file to use @param old_conf_file [String] the path to the config file to overwrite @return [void]
# File lib/kitchen/driver/pulumi.rb, line 285 def rewrite_config_file(new_conf_file, old_conf_file) return if new_conf_file.empty? old_conf = YAML.load_file(old_conf_file) new_conf_file = File.join(config_directory, new_conf_file) return unless File.exist?(new_conf_file) new_conf = old_conf.deep_merge(YAML.load_file(new_conf_file)) File.write(old_conf_file, new_conf.to_yaml) end
Returns the name of the secrets provider, if set, optionally as a Pulumi
CLI flag
@param flag [Boolean] specify true to prepend `–secrets-provider=“ to the name @return [String] value to use for the secrets provider
# File lib/kitchen/driver/pulumi.rb, line 145 def secrets_provider(flag: false) return '' if config_secrets_provider.empty? return "--secrets-provider=\"#{config_secrets_provider}\"" if flag config_secrets_provider end
Returns the name of the current stack to use. If the `test_stack_name` driver attribute is set, then it uses that one, otherwise it will be `<suite name>-<platform name>`
@return [String] either the empty string or '–preserve-config'
# File lib/kitchen/driver/pulumi.rb, line 135 def stack return config_test_stack_name unless config_test_stack_name.empty? "#{instance.suite.name}-#{instance.platform.name}" end
Retrieves the fully resolved stack inputs based on the current configuration of the stack via `pulumi config`
@param block [Block] block to run with stack inputs yielded to it
for block {|stack_inputs| … } @yield [stack_inputs] yields a hash of stack inputs
@raise [Kitchen::ActionFailed] if an error occurs retrieving stack inputs @return [self]
# File lib/kitchen/driver/pulumi.rb, line 306 def stack_inputs(&block) update({}, config_only: true) do |temp_conf_file| ::Kitchen::Pulumi::Command::Input.run( directory: config_directory, stack: stack, conf_file: config_file(temp_conf_file, flag: true), logger: logger, &block ) end self rescue ::Kitchen::Pulumi::Error => e raise ::Kitchen::ActionFailed, e.message end
Retrieves stack outputs via `pulumi stack output`
@param block [Block] block to run with stack outputs yielded to it
for block {|stack_outputs| … } @yield [stack_outputs] yields a hash of stack outputs
@raise [Kitchen::ActionFailed] if an error occurs retrieving stack outputs @return [self]
# File lib/kitchen/driver/pulumi.rb, line 331 def stack_outputs(&block) ::Kitchen::Pulumi::Command::Output.run( directory: config_directory, stack: stack, logger: logger, &block ) self rescue ::Kitchen::Pulumi::Error => e raise ::Kitchen::ActionFailed, e.message end
Sets stack config values via `pulumi config` and updates the stack via `pulumi up`
@param _state [::Hash] the current kitchen state @param config_only [Boolean] specify true to update the stack config without
applying changes to the stack via `pulumi up`. This is used primarily for setting the correct stack inputs by successively applying `pulumi config` in the order of precedence for specifying stack config values in the config file or kitchen.yml file.
for block {|temp_conf_file| …} @yield [temp_conf_file] provides the path to the temporary config file used
@return [void]
# File lib/kitchen/driver/pulumi.rb, line 81 def update(_state, config_only: false) dir = "-C #{config_directory}" ::Kitchen::Pulumi.with_temp_conf(config_file) do |temp_conf_file| login refresh_config(stack, temp_conf_file, dir) if config_refresh_config configure(config_config, stack, temp_conf_file, dir) configure(config_secrets, stack, temp_conf_file, dir, is_secret: true) update_stack(stack, temp_conf_file, dir) unless config_only unless config_stack_evolution.empty? evolve_stack(stack, temp_conf_file, dir, config_only: config_only) end yield temp_conf_file if block_given? end end
Updates a stack via `pulumi up` according to instance attributes
@param (see refresh_config
) @return [void]
# File lib/kitchen/driver/pulumi.rb, line 234 def update_stack(stack, conf_file, dir = '') base_cmd = "up -y -r --show-config -s #{stack} #{dir}" ::Kitchen::Pulumi::ShellOut.run( cmd: "#{base_cmd} #{config_file(conf_file, flag: true)}", logger: logger, ) end
Private Instance Methods
@return [Logger] the common logger @api private
# File lib/kitchen/driver/pulumi.rb, line 348 def logger Kitchen.logger end