diff --git a/lib/hako/application.rb b/lib/hako/application.rb index 5ac1d65..3fde33e 100644 --- a/lib/hako/application.rb +++ b/lib/hako/application.rb @@ -15,7 +15,7 @@ class Application # @return [Hash] attr_reader :id, :root_path, :definition - def initialize(definition_path, expand_variables: true, ask_keys: false) + def initialize(definition_path, expand_variables: true, ask_keys: false, ext_vars: {}) path = Pathname.new(definition_path) @id = path.basename.sub_ext('').to_s @root_path = path.parent @@ -24,7 +24,7 @@ def initialize(definition_path, expand_variables: true, ask_keys: false) when '.yml', '.yaml' YamlLoader.new.load(path) when '.jsonnet', '.json' - JsonnetLoader.new(self, expand_variables: expand_variables, ask_keys: ask_keys).load(path) + JsonnetLoader.new(self, expand_variables: expand_variables, ask_keys: ask_keys, ext_vars: ext_vars).load(path) else raise Error.new("Unknown extension: #{path}") end diff --git a/lib/hako/cli.rb b/lib/hako/cli.rb index 3e7faba..14108a8 100644 --- a/lib/hako/cli.rb +++ b/lib/hako/cli.rb @@ -73,6 +73,7 @@ def run(argv) else {} end + options.merge!(ext_vars: @ext_vars) Commander.new(Application.new(@definition_path, options)).deploy(force: @force, tag: @tag, dry_run: @dry_run, timeout: @timeout) end @@ -83,6 +84,7 @@ def parse!(argv) @dry_run = false @verbose = false @timeout = DEFAULT_TIMEOUT + @ext_vars = {} parser.parse!(argv) @definition_path = argv.first @@ -101,6 +103,10 @@ def parser opts.on('-n', '--dry-run', 'Enable dry-run mode') { @dry_run = true } opts.on('-v', '--verbose', 'Enable verbose logging') { @verbose = true } opts.on('--timeout=TIMEOUT_SEC', "Timeout deployment after TIMEOUT_SEC seconds (default: #{DEFAULT_TIMEOUT})") { |v| @timeout = v.to_i } + opts.on('--ext-var=KEY=VAL', 'Specify external variable for Jsonnet') do |arg| + k, v = arg.split('=', 2) + @ext_vars[k] = v + end end end end @@ -121,12 +127,14 @@ def run(argv) else {} end + options.merge!(ext_vars: @ext_vars) Commander.new(Application.new(@definition_path, options)).rollback(dry_run: @dry_run) end def parse!(argv) @dry_run = false @verbose = false + @ext_vars = {} parser.parse!(argv) @definition_path = argv.first @@ -142,6 +150,10 @@ def parser opts.version = VERSION opts.on('-n', '--dry-run', 'Enable dry-run mode') { @dry_run = true } opts.on('-v', '--verbose', 'Enable verbose logging') { @verbose = true } + opts.on('--ext-var=KEY=VAL', 'Specify external variable for Jsonnet') do |arg| + k, v = arg.split('=', 2) + @ext_vars[k] = v + end end end end @@ -162,6 +174,7 @@ def run(argv) else {} end + options.merge!(ext_vars: @ext_vars) Commander.new(Application.new(@definition_path, options)).oneshot(@argv, tag: @tag, containers: @containers, env: @env, dry_run: @dry_run, no_wait: @no_wait) end @@ -171,6 +184,7 @@ def parse!(argv) @env = {} @verbose = false @no_wait = false + @ext_vars = {} parser.parse!(argv) @definition_path = argv.shift @argv = argv @@ -194,6 +208,10 @@ def parser k, v = arg.split('=', 2) @env[k] = v end + opts.on('--ext-var=KEY=VAL', 'Specify external variable for Jsonnet') do |arg| + k, v = arg.split('=', 2) + @ext_vars[k] = v + end end end end @@ -202,12 +220,13 @@ class ShowDefinition def run(argv) parse!(argv) require 'hako/application' - app = Application.new(@path, expand_variables: @expand_variables) + app = Application.new(@path, expand_variables: @expand_variables, ext_vars: @ext_vars) puts JSON.pretty_generate(app.definition) end def parse!(argv) @expand_variables = false + @ext_vars = {} parser.parse!(argv) @path = argv.first if @path.nil? @@ -221,6 +240,10 @@ def parser opts.banner = 'hako show-definition FILE' opts.version = VERSION opts.on('--expand', 'Expand variables (Jsonnet only)') { @expand_variables = true } + opts.on('--ext-var=KEY=VAL', 'Specify external variable for Jsonnet') do |arg| + k, v = arg.split('=', 2) + @ext_vars[k] = v + end end end end @@ -230,10 +253,11 @@ def run(argv) parse!(argv) require 'hako/application' require 'hako/commander' - Commander.new(Application.new(@definition_path, expand_variables: false)).status + Commander.new(Application.new(@definition_path, expand_variables: false, ext_vars: @ext_vars)).status end def parse!(argv) + @ext_vars = {} parser.parse!(argv) @definition_path = argv.first @@ -247,6 +271,10 @@ def parser @parser ||= OptionParser.new do |opts| opts.banner = 'hako status FILE' opts.version = VERSION + opts.on('--ext-var=KEY=VAL', 'Specify external variable for Jsonnet') do |arg| + k, v = arg.split('=', 2) + @ext_vars[k] = v + end end end end @@ -257,11 +285,12 @@ def run(argv) require 'hako/application' require 'hako/commander' - Commander.new(Application.new(@definition_path, expand_variables: false)).remove(dry_run: @dry_run) + Commander.new(Application.new(@definition_path, expand_variables: false, ext_vars: @ext_vars)).remove(dry_run: @dry_run) end def parse!(argv) @dry_run = false + @ext_vars = {} parser.parse!(argv) @definition_path = argv.first @@ -276,6 +305,10 @@ def parser opts.banner = 'hako remove FILE' opts.version = VERSION opts.on('-n', '--dry-run', 'Enable dry-run mode') { @dry_run = true } + opts.on('--ext-var=KEY=VAL', 'Specify external variable for Jsonnet') do |arg| + k, v = arg.split('=', 2) + @ext_vars[k] = v + end end end end @@ -286,11 +319,12 @@ def run(argv) require 'hako/application' require 'hako/commander' - Commander.new(Application.new(@definition_path, expand_variables: false)).stop(dry_run: @dry_run) + Commander.new(Application.new(@definition_path, expand_variables: false, ext_vars: @ext_vars)).stop(dry_run: @dry_run) end def parse!(argv) @dry_run = false + @ext_vars = {} parser.parse!(argv) @definition_path = argv.first @@ -305,6 +339,10 @@ def parser opts.banner = 'hako stop FILE' opts.version = VERSION opts.on('-n', '--dry-run', 'Enable dry-run mode') { @dry_run = true } + opts.on('--ext-var=KEY=VAL', 'Specify external variable for Jsonnet') do |arg| + k, v = arg.split('=', 2) + @ext_vars[k] = v + end end end end diff --git a/lib/hako/jsonnet_loader.rb b/lib/hako/jsonnet_loader.rb index 5400b4d..3cbeddc 100644 --- a/lib/hako/jsonnet_loader.rb +++ b/lib/hako/jsonnet_loader.rb @@ -12,11 +12,12 @@ class JsonnetLoader # @param [Application] application # @param [Boolean] expand_variables # @param [Boolean] ask_keys - def initialize(application, expand_variables:, ask_keys:) + def initialize(application, expand_variables:, ask_keys:, ext_vars:) @vm = Jsonnet::VM.new @root_path = application.root_path define_provider_functions(expand_variables, ask_keys) @vm.ext_var('appId', application.id) + ext_vars.each { |k, v| @vm.ext_var(k.to_s, v) } end # @param [Pathname] path diff --git a/spec/fixtures/jsonnet/default_with_ext_var.jsonnet b/spec/fixtures/jsonnet/default_with_ext_var.jsonnet new file mode 100644 index 0000000..53c7c62 --- /dev/null +++ b/spec/fixtures/jsonnet/default_with_ext_var.jsonnet @@ -0,0 +1,11 @@ +{ + app: { + image: std.extVar('app_image'), + }, + sidecars: { + front: { + type: 'nginx', + image_tag: std.extVar('front_image'), + }, + }, +} diff --git a/spec/hako/definition_loader_spec.rb b/spec/hako/definition_loader_spec.rb index 46abda5..d926ece 100644 --- a/spec/hako/definition_loader_spec.rb +++ b/spec/hako/definition_loader_spec.rb @@ -63,5 +63,37 @@ end end end + + context 'with ext_vars' do + let(:fixture_name) { 'default_with_ext_var.jsonnet' } + let(:app) { Hako::Application.new(fixture_root.join('jsonnet', fixture_name), ext_vars: ext_vars) } + + context 'specify ext_vars' do + let(:ext_vars) do + { + app_image: 'app-image', + front_image: 'front-image', + } + end + + it 'loads all containers' do + containers = definition_loader.load + expect(containers.keys).to match_array(%w[app front]) + expect(containers.values).to all(be_a(Hako::Container)) + expect(containers['app'].image_tag).to eq('app-image:latest') + expect(containers['app'].links).to eq([]) + expect(containers['front'].image_tag).to eq('front-image') + expect(containers['front'].links).to eq([]) + end + end + + context 'not specify ext_vars' do + let(:ext_vars) { {} } + + it 'error occur' do + expect { definition_loader.load }.to raise_error(Jsonnet::EvaluationError) + end + end + end end end