vanagon 0.15.37 → 0.18.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (47) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +48 -23
  3. data/bin/build +4 -25
  4. data/bin/build_host_info +4 -17
  5. data/bin/build_requirements +4 -31
  6. data/bin/inspect +4 -21
  7. data/bin/render +4 -22
  8. data/bin/ship +4 -28
  9. data/bin/sign +4 -11
  10. data/bin/vanagon +7 -0
  11. data/extras/completions/vanagon.bash +38 -0
  12. data/extras/completions/vanagon.zsh +41 -0
  13. data/lib/vanagon.rb +1 -1
  14. data/lib/vanagon/cli.rb +102 -0
  15. data/lib/vanagon/cli/build.rb +83 -0
  16. data/lib/vanagon/cli/build_host_info.rb +57 -0
  17. data/lib/vanagon/cli/build_requirements.rb +68 -0
  18. data/lib/vanagon/cli/completion.rb +43 -0
  19. data/lib/vanagon/cli/inspect.rb +73 -0
  20. data/lib/vanagon/cli/list.rb +75 -0
  21. data/lib/vanagon/cli/render.rb +59 -0
  22. data/lib/vanagon/cli/ship.rb +52 -0
  23. data/lib/vanagon/cli/sign.rb +34 -0
  24. data/lib/vanagon/driver.rb +34 -28
  25. data/lib/vanagon/engine/always_be_scheduling.rb +271 -1
  26. data/lib/vanagon/engine/docker.rb +101 -14
  27. data/lib/vanagon/engine/pooler.rb +7 -3
  28. data/lib/vanagon/platform.rb +5 -3
  29. data/lib/vanagon/platform/deb.rb +3 -1
  30. data/lib/vanagon/platform/dsl.rb +11 -0
  31. data/lib/vanagon/platform/rpm.rb +1 -1
  32. data/lib/vanagon/platform/windows.rb +29 -2
  33. data/lib/vanagon/project.rb +23 -4
  34. data/lib/vanagon/project/dsl.rb +33 -0
  35. data/lib/vanagon/utilities.rb +30 -8
  36. data/resources/osx/postinstall.erb +1 -1
  37. data/resources/solaris/10/postinstall.erb +1 -1
  38. data/spec/lib/vanagon/cli_spec.rb +226 -0
  39. data/spec/lib/vanagon/driver_spec.rb +1 -1
  40. data/spec/lib/vanagon/engine/always_be_scheduling_spec.rb +113 -1
  41. data/spec/lib/vanagon/engine/docker_spec.rb +74 -16
  42. data/spec/lib/vanagon/engine/ec2_spec.rb +2 -0
  43. data/spec/lib/vanagon/engine/pooler_spec.rb +1 -1
  44. data/spec/spec_helper.rb +1 -0
  45. metadata +57 -30
  46. data/lib/vanagon/optparse.rb +0 -86
  47. data/spec/lib/vanagon/optparse_spec.rb +0 -64
@@ -0,0 +1,41 @@
1
+ _vanagon()
2
+ {
3
+ local line commands template_arg_commands projects
4
+
5
+ commands="build build_host_info build_requirements completion inspect list render sign ship help"
6
+ template_arg_commands=("build" "build_host_info" "build_requirements" "inspect" "render")
7
+ projects=($({ vanagon list -r | sed 1d; } 2>/dev/null))
8
+
9
+ # '%p:globbed-files:' sets completion to only offer files matching a
10
+ # described pattern.
11
+ zstyle ':completion:*' file-patterns '%p:globbed-files:'
12
+
13
+ # arguments function provides potential completions to zsh
14
+ # specs are of the form n:message:action
15
+ _arguments -C \
16
+ ": :(${commands})" \
17
+ "*::arg:->args"
18
+
19
+ # (Ie)prevents "invalid subscript"
20
+ if ((template_arg_commands[(Ie)$line[1]])); then
21
+ _vanagon_template_sub_projects
22
+ fi
23
+ if [[ $projects =~ (^| )$line[2]($| ) ]]; then
24
+ _vanagon_template_sub_platforms
25
+ fi
26
+ }
27
+
28
+ _vanagon_template_sub_projects()
29
+ {
30
+ # -W look in certain path but don't append path to tab compelte
31
+ # -g enables file matching pattern
32
+ # (:r) removes the file extension `.rb` from the completion
33
+ _arguments "1: :_files -W $(PWD)/configs/projects/ -g '*.rb(:r)'"
34
+ }
35
+
36
+ _vanagon_template_sub_platforms()
37
+ {
38
+ _arguments "*: :_files -W $(PWD)/configs/platforms/ -g '*.rb(:r)'"
39
+ }
40
+ # compdef registeres the completion function: compdef <function-name> <program>
41
+ compdef _vanagon vanagon
@@ -8,7 +8,7 @@ VANAGON_VERSION = Gem.loaded_specs["vanagon"].version.to_s
8
8
  $:.unshift(LIBDIR) unless
9
9
  $:.include?(File.dirname(__FILE__)) || $:.include?(LIBDIR)
10
10
 
11
- require 'vanagon/optparse'
11
+ require 'vanagon/cli'
12
12
  require 'vanagon/driver'
13
13
 
14
14
  # The main entry point is {Vanagon::Driver}.
@@ -0,0 +1,102 @@
1
+ require 'docopt'
2
+ require 'json'
3
+
4
+ require 'vanagon/extensions/ostruct/json'
5
+ require 'vanagon/extensions/set/json'
6
+ require 'vanagon/extensions/hashable'
7
+
8
+ require 'vanagon/cli/build'
9
+ require 'vanagon/cli/build_host_info'
10
+ require 'vanagon/cli/build_requirements'
11
+ require 'vanagon/cli/completion'
12
+ require 'vanagon/cli/inspect'
13
+ require 'vanagon/cli/list'
14
+ require 'vanagon/cli/render'
15
+ require 'vanagon/cli/ship'
16
+ require 'vanagon/cli/sign'
17
+
18
+
19
+ class Vanagon
20
+ class InvalidArgument < StandardError
21
+ end
22
+
23
+ class CLI
24
+ DOCUMENTATION = <<~DOCOPT.freeze
25
+ Usage:
26
+ vanagon <command> [<args>]...
27
+
28
+ Commands are:
29
+ build build a package given a project and platform
30
+ build_host_info print information about build hosts
31
+ build_requirements print external packages required to build project
32
+ completion outputs path to tab completion script
33
+ inspect a build dry-run, printing lots of information about the build
34
+ list shows a list of available projects and platforms
35
+ render create local versions of packaging artifacts for project
36
+ sign sign a package
37
+ ship upload a package to a distribution server
38
+ help print this help
39
+ DOCOPT
40
+
41
+ def parse(argv) # rubocop:disable Metrics/AbcSize
42
+ parsed_options = parse_options(argv)
43
+ sub_command = parsed_options['<command>']
44
+ sub_argv = parsed_options['<args>']
45
+
46
+ case sub_command
47
+ when 'build'
48
+ @sub_parser = Vanagon::CLI::Build.new
49
+ when 'build_host_info'
50
+ @sub_parser = Vanagon::CLI::BuildHostInfo.new
51
+ when 'build_requirements'
52
+ @sub_parser = Vanagon::CLI::BuildRequirements.new
53
+ when 'completion'
54
+ @sub_parser = Vanagon::CLI::Completion.new
55
+ when 'inspect'
56
+ @sub_parser = Vanagon::CLI::Inspect.new
57
+ when 'render'
58
+ @sub_parser = Vanagon::CLI::Render.new
59
+ when 'list'
60
+ @sub_parser = Vanagon::CLI::List.new
61
+ when 'sign'
62
+ @sub_parser = Vanagon::CLI::Sign.new
63
+ when 'ship'
64
+ @sub_parser = Vanagon::CLI::Ship.new
65
+ when 'help'
66
+ puts DOCUMENTATION
67
+ exit 0
68
+ else
69
+ warn "vanagon: Error: unknown command: \"#{sub_command}\"\n\n#{DOCUMENTATION}"
70
+ exit 1
71
+ end
72
+
73
+ raw_options = @sub_parser.parse(sub_argv)
74
+ options = @sub_parser.options_translate(raw_options)
75
+ @sub_parser.options_validate(options)
76
+ return options
77
+ end
78
+
79
+ def run(options)
80
+ @sub_parser.run(options)
81
+ end
82
+
83
+ # Do validation of options
84
+ def options_validate(options)
85
+ options
86
+ end
87
+
88
+ # Provide a translation from parsed docopt options to older optparse options
89
+ def options_translate(docopt_options)
90
+ docopt_options
91
+ end
92
+
93
+ private
94
+
95
+ def parse_options(argv)
96
+ Docopt.docopt(DOCUMENTATION, { argv: argv, options_first: true })
97
+ rescue Docopt::Exit => e
98
+ puts e.message
99
+ exit 1
100
+ end
101
+ end
102
+ end
@@ -0,0 +1,83 @@
1
+ require 'docopt'
2
+
3
+ class Vanagon
4
+ class CLI
5
+ class Build < Vanagon::CLI
6
+ DOCUMENTATION = <<~DOCOPT.freeze
7
+ Usage:
8
+ build [options] <project-name> <platforms> [<targets>]
9
+
10
+ Options:
11
+ -h, --help Display help
12
+ -c, --configdir DIRECTORY Configuration directory [default: #{Dir.pwd}/configs]
13
+ -e, --engine ENGINE Custom engine to use [default: always_be_scheduling]
14
+ -o, --only-build COMPONENT,COMPONENT,...
15
+ Only build listed COMPONENTs
16
+ -p, --preserve [RULE] Rule for VM preservation: never, on-failure, always
17
+ [Default: always]
18
+ -r, --remote-workdir DIRECTORY Working directory on the remote host
19
+ -s, --skipcheck Skip the "check" stage when building components
20
+ -w, --workdir DIRECTORY Working directory on the local host
21
+ -v, --verbose Only here for backwards compatibility. Does nothing.
22
+
23
+ Engines:
24
+ always_be_scheduling: default engine using Puppet's ABS infrastructure
25
+ docker: a docker container on the local host
26
+ ec2: an Amazon EC2 instance
27
+ hardware: a dedicated hardware device
28
+ local: the local machine, cannot be used with a target
29
+ pooler: [deprecated] Puppet's vmpooler
30
+ DOCOPT
31
+
32
+ def parse(argv)
33
+ Docopt.docopt(DOCUMENTATION, { argv: argv })
34
+ rescue Docopt::Exit => e
35
+ puts e.message
36
+ exit 1
37
+ end
38
+
39
+ def run(options) # rubocop:disable Metrics/AbcSize
40
+ project = options[:project_name]
41
+ platform_list = options[:platforms].split(',')
42
+ target_list = []
43
+ unless options[:targets].nil? || options[:targets].empty?
44
+ target_list = options[:targets].split(',')
45
+ end
46
+
47
+ platform_list.zip(target_list).each do |pair|
48
+ platform, target = pair
49
+ artifact = Vanagon::Driver.new(platform, project, options.merge({ :target => target }))
50
+ artifact.run
51
+ end
52
+ end
53
+
54
+ def options_translate(docopt_options)
55
+ translations = {
56
+ '--verbose' => :verbose,
57
+ '--workdir' => :workdir,
58
+ '--remote-workdir' => :"remote-workdir",
59
+ '--configdir' => :configdir,
60
+ '--engine' => :engine,
61
+ '--skipcheck' => :skipcheck,
62
+ '--preserve' => :preserve,
63
+ '--only-build' => :only_build,
64
+ '<project-name>' => :project_name,
65
+ '<platforms>' => :platforms,
66
+ '<targets>' => :targets
67
+ }
68
+ return docopt_options.map { |k, v| [translations[k], v] }.to_h
69
+ end
70
+
71
+ def options_validate(options)
72
+ # Handle --preserve option checking
73
+ valid_preserves = %w[always never on-failure]
74
+ unless valid_preserves.include? options[:preserve]
75
+ raise InvalidArgument, "--preserve option can only be one of: " +
76
+ valid_preserves.join(', ')
77
+ end
78
+ options[:preserve] = options[:preserve].to_sym
79
+ return options
80
+ end
81
+ end
82
+ end
83
+ end
@@ -0,0 +1,57 @@
1
+ require 'docopt'
2
+
3
+ class Vanagon
4
+ class CLI
5
+ class BuildHostInfo < Vanagon::CLI
6
+ DOCUMENTATION = <<~DOCOPT.freeze
7
+ Usage:
8
+ build_host_info [options] <project-name> <platforms>
9
+
10
+ Options:
11
+ -h, --help Display help
12
+ -c, --configdir DIRECTORY Configuration directory [default: #{Dir.pwd}/configs]
13
+ -e, --engine ENGINE Custom engine to use [default: always_be_scheduling]
14
+ -w, --workdir DIRECTORY Working directory on the local host
15
+ -v, --verbose Only here for backwards compatibility. Does nothing.
16
+
17
+ Engines:
18
+ always_be_scheduling: default engine using Puppet's ABS infrastructure
19
+ docker: a docker container on the local host
20
+ ec2: an Amazon EC2 instance
21
+ hardware: a dedicated hardware device
22
+ local: the local machine, cannot be used with a target
23
+ pooler: [deprecated] Puppet's vmpooler
24
+ DOCOPT
25
+
26
+ def parse(argv)
27
+ Docopt.docopt(DOCUMENTATION, { argv: argv })
28
+ rescue Docopt::Exit => e
29
+ puts e.message
30
+ exit 1
31
+ end
32
+
33
+ def run(options)
34
+ platforms = options[:platforms].split(',')
35
+ project = options[:project_name]
36
+
37
+ platforms.each do |platform|
38
+ driver = Vanagon::Driver.new(platform, project, options)
39
+ $stdout.puts JSON.generate(driver.build_host_info)
40
+ end
41
+ end
42
+
43
+ def options_translate(docopt_options)
44
+ translations = {
45
+ '--verbose' => :verbose,
46
+ '--workdir' => :workdir,
47
+ '--configdir' => :configdir,
48
+ '--engine' => :engine,
49
+ '<project-name>' => :project_name,
50
+ '<platforms>' => :platforms,
51
+ '<targets>' => :targets
52
+ }
53
+ return docopt_options.map { |k, v| [translations[k], v] }.to_h
54
+ end
55
+ end
56
+ end
57
+ end
@@ -0,0 +1,68 @@
1
+ require 'docopt'
2
+ require 'json'
3
+
4
+ class Vanagon
5
+ class CLI
6
+ class BuildRequirements < Vanagon::CLI
7
+ DOCUMENTATION = <<~DOCOPT.freeze
8
+ Usage:
9
+ build_requirements [options] <project-name> <platform>
10
+
11
+ Options:
12
+ -h, --help Display help
13
+ -c, --configdir DIRECTORY Configuration directory [default: #{Dir.pwd}/configs]
14
+ -e, --engine ENGINE Custom engine to use [default: always_be_scheduling]
15
+ -w, --workdir DIRECTORY Working directory on the local host
16
+ -v, --verbose Only here for backwards compatibility. Does nothing.
17
+
18
+ Engines:
19
+ always_be_scheduling: default engine using Puppet's ABS infrastructure
20
+ docker: a docker container on the local host
21
+ ec2: an Amazon EC2 instance
22
+ hardware: a dedicated hardware device
23
+ local: the local machine, cannot be used with a target
24
+ pooler: [deprecated] Puppet's vmpooler
25
+ DOCOPT
26
+
27
+ def parse(argv)
28
+ Docopt.docopt(DOCUMENTATION, { argv: argv })
29
+ rescue Docopt::Exit => e
30
+ puts e.message
31
+ exit 1
32
+ end
33
+
34
+ def run(options) # rubocop:disable Metrics/AbcSize
35
+ platform = options[:platform]
36
+ project = options[:project_name]
37
+ driver = Vanagon::Driver.new(platform, project)
38
+
39
+ components = driver.project.components
40
+ component_names = components.map(&:name)
41
+ build_requirements = []
42
+ components.each do |component|
43
+ build_requirements << component.build_requires.reject do |requirement|
44
+ # only include external requirements: i.e. those that do not match
45
+ # other components in the project
46
+ component_names.include?(requirement)
47
+ end
48
+ end
49
+
50
+ $stdout.puts
51
+ $stdout.puts "**** External packages required to build #{project} on #{platform}: ***"
52
+ $stdout.puts JSON.pretty_generate(build_requirements.flatten.uniq.sort)
53
+ end
54
+
55
+ def options_translate(docopt_options)
56
+ translations = {
57
+ '--verbose' => :verbose,
58
+ '--workdir' => :workdir,
59
+ '--configdir' => :configdir,
60
+ '--engine' => :engine,
61
+ '<project-name>' => :project_name,
62
+ '<platform>' => :platform,
63
+ }
64
+ return docopt_options.map { |k, v| [translations[k], v] }.to_h
65
+ end
66
+ end
67
+ end
68
+ end
@@ -0,0 +1,43 @@
1
+ require 'docopt'
2
+
3
+ class Vanagon
4
+ class CLI
5
+ class Completion < Vanagon::CLI
6
+ DOCUMENTATION = <<~DOCOPT.freeze
7
+ Usage:
8
+ completion [options]
9
+
10
+ Options:
11
+ -h, --help Display help
12
+ -s, --shell SHELL Specify shell for completion script [default: bash]
13
+ DOCOPT
14
+
15
+ def parse(argv)
16
+ Docopt.docopt(DOCUMENTATION, { argv: argv })
17
+ rescue Docopt::Exit => e
18
+ puts e.message
19
+ exit 1
20
+ end
21
+
22
+ def run(options)
23
+ shell = options[:shell].downcase.strip
24
+ completion_file = File.expand_path(File.join('..', '..', '..', '..', 'extras', 'completions', "vanagon.#{shell}"), __FILE__)
25
+
26
+ if File.exist?(completion_file)
27
+ puts completion_file
28
+ exit 0
29
+ else
30
+ puts "Could not find completion file for '#{shell}': No such file #{completion_file}"
31
+ exit 1
32
+ end
33
+ end
34
+
35
+ def options_translate(docopt_options)
36
+ translations = {
37
+ '--shell' => :shell,
38
+ }
39
+ return docopt_options.map { |k, v| [translations[k], v] }.to_h
40
+ end
41
+ end
42
+ end
43
+ end
@@ -0,0 +1,73 @@
1
+ require 'docopt'
2
+ require 'json'
3
+
4
+ class Vanagon
5
+ class CLI
6
+ class Inspect < Vanagon::CLI
7
+ DOCUMENTATION = <<~DOCOPT.freeze
8
+ Usage:
9
+ inspect [options] <project-name> <platforms>
10
+
11
+ Options:
12
+ -h, --help Display help
13
+ -c, --configdir DIRECTORY Configuration directory [default: #{Dir.pwd}/configs]
14
+ -e, --engine ENGINE Custom engine to use [default: always_be_scheduling]
15
+
16
+ -p, --preserve [RULE] Rule for VM preservation: never, on-failure, always
17
+ [Default: on-failure]
18
+ -w, --workdir DIRECTORY Working directory on the local host
19
+ -v, --verbose Only here for backwards compatibility. Does nothing.
20
+
21
+ Engines:
22
+ always_be_scheduling: default engine using Puppet's ABS infrastructure
23
+ docker: a docker container on the local host
24
+ ec2: an Amazon EC2 instance
25
+ hardware: a dedicated hardware device
26
+ local: the local machine, cannot be used with a target
27
+ pooler: [deprecated] Puppet's vmpooler
28
+ DOCOPT
29
+
30
+ def parse(argv)
31
+ Docopt.docopt(DOCUMENTATION, { argv: argv })
32
+ rescue Docopt::Exit => e
33
+ puts e.message
34
+ exit 1
35
+ end
36
+
37
+ def run(options)
38
+ platforms = options[:platforms].split(',')
39
+ project = options[:project_name]
40
+
41
+ platforms.each do |platform|
42
+ driver = Vanagon::Driver.new(platform, project, options)
43
+ components = driver.project.components.map(&:to_hash)
44
+ $stdout.puts JSON.pretty_generate(components)
45
+ end
46
+ end
47
+
48
+ def options_translate(docopt_options)
49
+ translations = {
50
+ '--verbose' => :verbose,
51
+ '--workdir' => :workdir,
52
+ '--configdir' => :configdir,
53
+ '--engine' => :engine,
54
+ '--preserve' => :preserve,
55
+ '<project-name>' => :project_name,
56
+ '<platforms>' => :platforms
57
+ }
58
+ return docopt_options.map { |k, v| [translations[k], v] }.to_h
59
+ end
60
+
61
+ def options_validate(options)
62
+ # Handle --preserve option checking
63
+ valid_preserves = %w[always never on-failure]
64
+ unless valid_preserves.include? options[:preserve]
65
+ raise InvalidArgument, "--preserve option can only be one of: " +
66
+ valid_preserves.join(', ')
67
+ end
68
+ options[:preserve] = options[:preserve].to_sym
69
+ return options
70
+ end
71
+ end
72
+ end
73
+ end