imagemaster3000 0.1.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 (60) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +12 -0
  3. data/.rspec +2 -0
  4. data/.rubocop.yml +38 -0
  5. data/.travis.yml +22 -0
  6. data/CODE_OF_CONDUCT.md +74 -0
  7. data/Gemfile +4 -0
  8. data/LICENSE.txt +13 -0
  9. data/README.md +60 -0
  10. data/Rakefile +17 -0
  11. data/bin/imagemaster3000 +4 -0
  12. data/config/definitions/centos-7.json +29 -0
  13. data/config/definitions/debian-8.json +33 -0
  14. data/config/definitions/files/.gitkeep +0 -0
  15. data/config/definitions/files/centos-cloud.cfg +95 -0
  16. data/config/definitions/files/debian-cloud.cfg +101 -0
  17. data/config/definitions/files/serial-getty@ttyS0.service +35 -0
  18. data/config/definitions/files/ttyS0.conf +22 -0
  19. data/config/definitions/files/ubuntu-cloud.cfg +111 -0
  20. data/config/definitions/ubuntu-14.04.json +30 -0
  21. data/config/definitions/ubuntu-16.04.json +30 -0
  22. data/config/imagemaster3000.yml +15 -0
  23. data/imagemaster3000.gemspec +42 -0
  24. data/lib/imagemaster3000/actions/copy.rb +45 -0
  25. data/lib/imagemaster3000/actions/remove.rb +24 -0
  26. data/lib/imagemaster3000/actions.rb +6 -0
  27. data/lib/imagemaster3000/cli.rb +115 -0
  28. data/lib/imagemaster3000/definitions/parser.rb +45 -0
  29. data/lib/imagemaster3000/definitions/schemas/imagemaster3000-definition-schema.json +238 -0
  30. data/lib/imagemaster3000/definitions.rb +5 -0
  31. data/lib/imagemaster3000/entities/downloadable.rb +47 -0
  32. data/lib/imagemaster3000/entities/image.rb +92 -0
  33. data/lib/imagemaster3000/entities.rb +6 -0
  34. data/lib/imagemaster3000/errors/action_error.rb +5 -0
  35. data/lib/imagemaster3000/errors/argument_error.rb +5 -0
  36. data/lib/imagemaster3000/errors/command_execution_error.rb +5 -0
  37. data/lib/imagemaster3000/errors/download_error.rb +5 -0
  38. data/lib/imagemaster3000/errors/parsing_error.rb +5 -0
  39. data/lib/imagemaster3000/errors/standard_error.rb +5 -0
  40. data/lib/imagemaster3000/errors/verification_error.rb +5 -0
  41. data/lib/imagemaster3000/errors.rb +11 -0
  42. data/lib/imagemaster3000/image_list/generator.rb +25 -0
  43. data/lib/imagemaster3000/image_list/signer.rb +18 -0
  44. data/lib/imagemaster3000/image_list/templates/image_list.erb +41 -0
  45. data/lib/imagemaster3000/image_list.rb +6 -0
  46. data/lib/imagemaster3000/main_process.rb +22 -0
  47. data/lib/imagemaster3000/settings.rb +19 -0
  48. data/lib/imagemaster3000/utils/command_executioner.rb +22 -0
  49. data/lib/imagemaster3000/utils/crypto.rb +28 -0
  50. data/lib/imagemaster3000/utils/tmp.rb +24 -0
  51. data/lib/imagemaster3000/utils.rb +7 -0
  52. data/lib/imagemaster3000/verification/hash.rb +45 -0
  53. data/lib/imagemaster3000/verification/signatures/clearsign.rb +16 -0
  54. data/lib/imagemaster3000/verification/signatures/detached.rb +18 -0
  55. data/lib/imagemaster3000/verification/signatures.rb +8 -0
  56. data/lib/imagemaster3000/verification/verifiable.rb +10 -0
  57. data/lib/imagemaster3000/verification.rb +7 -0
  58. data/lib/imagemaster3000/version.rb +3 -0
  59. data/lib/imagemaster3000.rb +18 -0
  60. metadata +347 -0
@@ -0,0 +1,35 @@
1
+ # This file is part of systemd.
2
+ #
3
+ # systemd is free software; you can redistribute it and/or modify it
4
+ # under the terms of the GNU Lesser General Public License as published by
5
+ # the Free Software Foundation; either version 2.1 of the License, or
6
+ # (at your option) any later version.
7
+
8
+ [Unit]
9
+ Description=Serial Getty on %I
10
+ Documentation=man:agetty(8) man:systemd-getty-generator(8)
11
+ Documentation=http://0pointer.de/blog/projects/serial-console.html
12
+ BindsTo=dev-%i.device
13
+ After=dev-%i.device systemd-user-sessions.service plymouth-quit-wait.service
14
+ After=rc-local.service
15
+
16
+ # If additional gettys are spawned during boot then we should make
17
+ # sure that this is synchronized before getty.target, even though
18
+ # getty.target didn't actually pull it in.
19
+ Before=getty.target
20
+ IgnoreOnIsolate=yes
21
+
22
+ [Service]
23
+ ExecStart=-/sbin/agetty --autologin root --keep-baud 115200,38400,9600 %I $TERM
24
+ Type=idle
25
+ Restart=always
26
+ UtmpIdentifier=%I
27
+ TTYPath=/dev/%I
28
+ TTYReset=yes
29
+ TTYVHangup=yes
30
+ KillMode=process
31
+ IgnoreSIGPIPE=no
32
+ SendSIGHUP=yes
33
+
34
+ [Install]
35
+ WantedBy=getty.target
@@ -0,0 +1,22 @@
1
+ # ttyS0 - getty
2
+ #
3
+ # This service maintains a getty on ttyS0 from the point the system is
4
+ # started until it is shut down again.
5
+
6
+ start on stopped rc RUNLEVEL=[2345] and (
7
+ not-container or
8
+ container CONTAINER=lxc or
9
+ container CONTAINER=lxc-libvirt)
10
+
11
+ stop on runlevel [!2345]
12
+
13
+ pre-start script
14
+ # getty will not be started if the serial console is not present
15
+ stty -F /dev/ttyS0 -a 2> /dev/null > /dev/null || { stop ; exit 0; }
16
+ end script
17
+
18
+ respawn
19
+ script
20
+ exec /sbin/getty --autologin root -L ttyS0 115200 vt102
21
+ end script
22
+ # CLOUD_IMG: This file was created/modified by the Cloud Image build process
@@ -0,0 +1,111 @@
1
+ # If this is set, 'root' will not be able to ssh in and they
2
+ # will get a message to login instead as the above $user (ubuntu)
3
+ disable_root: False
4
+ user: root
5
+ ssh_pwauth: False
6
+ ssh_deletekeys: True
7
+ ssh_genkeytypes: ['rsa', 'dsa']
8
+ ssh_svcname: sshd
9
+
10
+ # This will cause the set+update hostname module to not operate (if true)
11
+ preserve_hostname: false
12
+ cc_ready_cmd: ['/bin/true']
13
+ mount_default_fields: [~, ~, 'auto', 'defaults,nofail', '0', '2']
14
+ syslog_fix_perms: ~
15
+ manage_etc_hosts: True
16
+
17
+ # Update and upgrade system on first boot
18
+ apt_preserve_sources_list: True
19
+ package_update: True
20
+ package_upgrade: True
21
+ package_reboot_if_required: True
22
+
23
+ # work only with OpenNebula, use network based datasource,
24
+ # so that we can successfully resolve IPv4 based hostname
25
+ disable_ec2_metadata: True
26
+ datasource_list: ['OpenNebula']
27
+ datasource:
28
+ OpenNebula:
29
+ dsmode: net
30
+
31
+ # The modules that run in the 'init' stage
32
+ cloud_init_modules:
33
+ - migrator
34
+ - seed_random
35
+ - bootcmd
36
+ - write-files
37
+ - growpart
38
+ - resizefs
39
+ - set_hostname
40
+ - update_hostname
41
+ - update_etc_hosts
42
+ - ca-certs
43
+ - rsyslog
44
+ - users-groups
45
+ - ssh
46
+
47
+ # The modules that run in the 'config' stage
48
+ cloud_config_modules:
49
+ # Emit the cloud config ready event
50
+ # this can be used by upstart jobs for 'start on cloud-config'.
51
+ - emit_upstart
52
+ - disk_setup
53
+ - mounts
54
+ - ssh-import-id
55
+ - locale
56
+ - set-passwords
57
+ - grub-dpkg
58
+ - apt-pipelining
59
+ - apt-configure
60
+ - package-update-upgrade-install
61
+ - landscape
62
+ - timezone
63
+ - puppet
64
+ - chef
65
+ - salt-minion
66
+ - mcollective
67
+ - disable-ec2-metadata
68
+ - runcmd
69
+ - byobu
70
+
71
+ # The modules that run in the 'final' stage
72
+ cloud_final_modules:
73
+ - rightscale_userdata
74
+ - scripts-per-once
75
+ - scripts-per-boot
76
+ - scripts-per-instance
77
+ - scripts-user
78
+ - ssh-authkey-fingerprints
79
+ - keys-to-console
80
+ - phone-home
81
+ - final-message
82
+ - power-state-change
83
+
84
+ # System and/or distro specific settings
85
+ # (not accessible to handlers/transforms)
86
+ system_info:
87
+ # This will affect which distro class gets used
88
+ distro: ubuntu
89
+ # Other config here will be given to the distro class and/or path classes
90
+ paths:
91
+ cloud_dir: /var/lib/cloud/
92
+ templates_dir: /etc/cloud/templates/
93
+ upstart_dir: /etc/init/
94
+ package_mirrors:
95
+ - arches: [i386, amd64]
96
+ failsafe:
97
+ primary: http://archive.ubuntu.com/ubuntu
98
+ security: http://security.ubuntu.com/ubuntu
99
+ search:
100
+ primary:
101
+ - http://%(ec2_region)s.ec2.archive.ubuntu.com/ubuntu/
102
+ - http://%(availability_zone)s.clouds.archive.ubuntu.com/ubuntu/
103
+ - http://%(region)s.clouds.archive.ubuntu.com/ubuntu/
104
+ security: []
105
+ - arches: [armhf, armel, default]
106
+ failsafe:
107
+ primary: http://ports.ubuntu.com/ubuntu-ports
108
+ security: http://ports.ubuntu.com/ubuntu-ports
109
+ ssh_svcname: ssh
110
+
111
+ # vim:syntax=yaml
@@ -0,0 +1,30 @@
1
+ {
2
+ "name":"METACLOUD-Ubuntu-14.04-x86_64@metacloud-dukan",
3
+ "url":"https://cloud-images.ubuntu.com/trusty/current/trusty-server-cloudimg-amd64-disk1.img",
4
+ "verification":{
5
+ "signature":{
6
+ "detached":{
7
+ "signature":"https://cloud-images.ubuntu.com/trusty/current/SHA256SUMS.gpg",
8
+ "data":"https://cloud-images.ubuntu.com/trusty/current/SHA256SUMS"
9
+ }
10
+ },
11
+ "hash":{
12
+ "function":"SHA256"
13
+ }
14
+ },
15
+ "distribution":"Ubuntu",
16
+ "version":"14.04",
17
+ "actions":{
18
+ "copy":[
19
+ {
20
+ "source":"ubuntu-cloud.cfg",
21
+ "target":"/etc/cloud/",
22
+ "name":"cloud.cfg"
23
+ },
24
+ {
25
+ "source":"ttyS0.conf",
26
+ "target":"/etc/init/"
27
+ }
28
+ ]
29
+ }
30
+ }
@@ -0,0 +1,30 @@
1
+ {
2
+ "name":"METACLOUD-Ubuntu-16.04-x86_64@metacloud-dukan",
3
+ "url":"https://cloud-images.ubuntu.com/xenial/current/xenial-server-cloudimg-amd64-disk1.img",
4
+ "verification":{
5
+ "signature":{
6
+ "detached":{
7
+ "signature":"https://cloud-images.ubuntu.com/xenial/current/SHA256SUMS.gpg",
8
+ "data":"https://cloud-images.ubuntu.com/xenial/current/SHA256SUMS"
9
+ }
10
+ },
11
+ "hash":{
12
+ "function":"SHA256"
13
+ }
14
+ },
15
+ "distribution":"Ubuntu",
16
+ "version":"16.04",
17
+ "actions":{
18
+ "copy":[
19
+ {
20
+ "source":"ubuntu-cloud.cfg",
21
+ "target":"/etc/cloud/",
22
+ "name":"cloud.cfg"
23
+ },
24
+ {
25
+ "source":"serial-getty@ttyS0.service",
26
+ "target":"/etc/systemd/system/getty.target.wants/"
27
+ }
28
+ ]
29
+ }
30
+ }
@@ -0,0 +1,15 @@
1
+ imagemaster3000:
2
+ definitions-dir: # If set, definitions in this direcotry are used to download and modify images
3
+ image-dir: /var/spool/imagemaster3000/images/ # Directory where to temporarily store images
4
+ image-list: /var/spool/imagemaster3000/image-list/imagemaster3000.list # Name and path of generated image list
5
+ endpoint: http://localhost/ # Endpoint where image list will be available
6
+ certificate: /etc/grid-security/cert.pem # Certificate to sign image list with
7
+ key: /etc/grid-security/key.pem # Key to sign image list with
8
+ group: imagemaster3000 # Group, images will be uploaded to
9
+ binaries:
10
+ virt-copy-in: /usr/bin/virt-copy-in # Path to binary needed for 'copy' action
11
+ guestfish: /usr/bin/guestfish # Path to binary needed for 'remove' action
12
+ logging:
13
+ level: ERROR # Logging level
14
+ file: /var/log/imagemaster3000/imagemaster3000.log # File to write log to. To turn off file logging leave this field empty.
15
+ debug: false # Debug mode
@@ -0,0 +1,42 @@
1
+ # coding: utf-8
2
+
3
+ lib = File.expand_path('../lib', __FILE__)
4
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
5
+ require 'imagemaster3000/version'
6
+
7
+ Gem::Specification.new do |spec|
8
+ spec.name = 'imagemaster3000'
9
+ spec.version = Imagemaster3000::VERSION
10
+ spec.authors = ['Michal Kimle']
11
+ spec.email = ['kimle.michal@gmail.com']
12
+
13
+ spec.summary = 'Downloading and slight modification of cloud images'
14
+ spec.description = 'Downloading and slight modification of cloud images'
15
+ spec.homepage = 'https://github.com/Misenko/imagemaster3000'
16
+ spec.license = 'Apache License, Version 2.0'
17
+
18
+ spec.files = `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
19
+ spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
20
+ spec.require_paths = ['lib']
21
+
22
+ spec.add_development_dependency 'bundler', '~> 1.15'
23
+ spec.add_development_dependency 'rake', '~> 12.0'
24
+ spec.add_development_dependency 'rspec', '~> 3.5'
25
+ spec.add_development_dependency 'rubocop', '~> 0.48'
26
+ spec.add_development_dependency 'rubocop-rspec', '~> 1.15'
27
+ spec.add_development_dependency 'simplecov', '~> 0.12'
28
+ spec.add_development_dependency 'pry', '~> 0.10'
29
+ spec.add_development_dependency 'vcr', '~> 3.0'
30
+ spec.add_development_dependency 'webmock', '~> 3.0'
31
+
32
+ spec.add_runtime_dependency 'thor', '~> 0.19'
33
+ spec.add_runtime_dependency 'yell', '~> 2.0'
34
+ spec.add_runtime_dependency 'settingslogic', '~> 2.0'
35
+ spec.add_runtime_dependency 'activesupport', '>= 4.0', '< 6.0'
36
+ spec.add_runtime_dependency 'tilt', '~> 2.0'
37
+ spec.add_runtime_dependency 'gpgme', '~> 2.0'
38
+ spec.add_runtime_dependency 'mixlib-shellout', '~> 2.2'
39
+ spec.add_runtime_dependency 'json-schema', '~> 2.8'
40
+
41
+ spec.required_ruby_version = '>= 2.2.0'
42
+ end
@@ -0,0 +1,45 @@
1
+ module Imagemaster3000
2
+ module Actions
3
+ class Copy
4
+ attr_accessor :filename, :source, :target, :name
5
+
6
+ def initialize(source: nil, target: nil, name: nil)
7
+ raise Imagemaster3000::Errors::ArgumentError, 'neither source nor target can be nil' if source.empty? || target.empty?
8
+
9
+ @filename = source
10
+ @source = File.join(Imagemaster3000::Settings[:'definitions-dir'], 'files', source)
11
+ @target = target
12
+ @name = name
13
+ logger.debug "Created action #{inspect}"
14
+ end
15
+
16
+ def run(image_file)
17
+ logger.debug "Running 'copy' action with source #{source.inspect} and target #{target.inspect} on file #{image_file.inspect}"
18
+ copy image_file
19
+ rename image_file if name
20
+ rescue Imagemaster3000::Errors::CommandExecutionError => ex
21
+ raise Imagemaster3000::Errors::ActionError, ex
22
+ end
23
+
24
+ private
25
+
26
+ def copy(image_file)
27
+ Imagemaster3000::Utils::CommandExecutioner.execute Imagemaster3000::Settings[:'binaries-virt-copy-in'],
28
+ '-a',
29
+ image_file,
30
+ source,
31
+ target
32
+ end
33
+
34
+ def rename(image_file)
35
+ Imagemaster3000::Utils::CommandExecutioner.execute Imagemaster3000::Settings[:'binaries-guestfish'],
36
+ '-a',
37
+ image_file,
38
+ '-i',
39
+ 'mv',
40
+ File.join(target, filename),
41
+ File.join(target, name)
42
+ end
43
+ end
44
+ end
45
+ end
@@ -0,0 +1,24 @@
1
+ module Imagemaster3000
2
+ module Actions
3
+ class Remove
4
+ attr_accessor :file
5
+
6
+ def initialize(file)
7
+ @file = file
8
+ logger.debug "Created action #{inspect}"
9
+ end
10
+
11
+ def run(image_file)
12
+ logger.debug "Running 'remove' action with argument #{file.inspect} on file #{image_file.inspect}"
13
+ Imagemaster3000::Utils::CommandExecutioner.execute Imagemaster3000::Settings[:'binaries-guestfish'],
14
+ '-a',
15
+ image_file,
16
+ '-i',
17
+ 'rm',
18
+ file
19
+ rescue Imagemaster3000::Errors::CommandExecutionError => ex
20
+ raise Imagemaster3000::Errors::ActionError, ex
21
+ end
22
+ end
23
+ end
24
+ end
@@ -0,0 +1,6 @@
1
+ module Imagemaster3000
2
+ module Actions
3
+ autoload :Copy, 'imagemaster3000/actions/copy'
4
+ autoload :Remove, 'imagemaster3000/actions/remove'
5
+ end
6
+ end
@@ -0,0 +1,115 @@
1
+ require 'thor'
2
+ require 'yell'
3
+
4
+ module Imagemaster3000
5
+ class CLI < Thor
6
+ class_option :'logging-level',
7
+ required: true,
8
+ default: Imagemaster3000::Settings['logging']['level'],
9
+ type: :string,
10
+ enum: Yell::Severities
11
+ class_option :'logging-file',
12
+ default: Imagemaster3000::Settings['logging']['file'],
13
+ type: :string,
14
+ desc: 'File to write logs to'
15
+ class_option :debug,
16
+ default: Imagemaster3000::Settings['debug'],
17
+ type: :boolean,
18
+ desc: 'Runs in debug mode'
19
+
20
+ method_option :'definitions-dir',
21
+ default: Imagemaster3000::Settings['definitions-dir'],
22
+ type: :string,
23
+ desc: 'If set, definitions in this direcotry are used to download and modify images'
24
+ method_option :'image-dir',
25
+ default: Imagemaster3000::Settings['image-dir'],
26
+ type: :string,
27
+ required: true,
28
+ desc: 'Directory where to temporarily store images'
29
+ method_option :group,
30
+ required: true,
31
+ default: Imagemaster3000::Settings['group'],
32
+ type: :string,
33
+ desc: 'Group, images will be uploaded to'
34
+ method_option :'image-list',
35
+ required: true,
36
+ default: Imagemaster3000::Settings['image-list'],
37
+ type: :string,
38
+ desc: 'Name and path of generated image list'
39
+ method_option :endpoint,
40
+ required: true,
41
+ default: Imagemaster3000::Settings['endpoint'],
42
+ type: :string,
43
+ desc: 'Endpoint where image list will be available'
44
+ method_option :certificate,
45
+ required: true,
46
+ default: Imagemaster3000::Settings['certificate'],
47
+ type: :string,
48
+ desc: 'Certificate to sign image list with'
49
+ method_option :key,
50
+ required: true,
51
+ default: Imagemaster3000::Settings['key'],
52
+ type: :string,
53
+ desc: 'Key to sign image list with'
54
+ method_option :'binaries-virt-copy-in',
55
+ required: true,
56
+ default: Imagemaster3000::Settings['binaries']['virt-copy-in'],
57
+ type: :string,
58
+ desc: 'Path to binary needed for \'copy\' action'
59
+ method_option :'binaries-guestfish',
60
+ required: true,
61
+ default: Imagemaster3000::Settings['binaries']['guestfish'],
62
+ type: :string,
63
+ desc: 'Path to binary needed for \'remove\' action'
64
+
65
+ desc 'start', 'Downloads images and generates image list'
66
+ def start
67
+ initialize_configuration options
68
+ initialize_logger
69
+ logger.debug "Imagemaster3000 'start' called with parameters: #{Imagemaster3000::Settings.to_hash.inspect}"
70
+
71
+ Imagemaster3000::MainProcess.new.run
72
+ end
73
+
74
+ desc 'version', 'Prints imagemaster3000 version'
75
+ def version
76
+ $stdout.puts Imagemaster3000::VERSION
77
+ end
78
+
79
+ default_task :start
80
+
81
+ private
82
+
83
+ def initialize_configuration(options)
84
+ Imagemaster3000::Settings.clear
85
+ Imagemaster3000::Settings.merge! options.to_hash
86
+
87
+ gem_dir = File.realdirpath(File.join(File.dirname(__FILE__), '..', '..'))
88
+ Imagemaster3000::Settings[:'definitions-dir'] = File.join(gem_dir, 'config', 'definitions') \
89
+ unless Imagemaster3000::Settings[:'definitions-dir']
90
+ end
91
+
92
+ def initialize_logger
93
+ Imagemaster3000::Settings[:'logging-level'] = 'DEBUG' if Imagemaster3000::Settings[:debug]
94
+
95
+ logging_file = Imagemaster3000::Settings[:'logging-file']
96
+ logging_level = Imagemaster3000::Settings[:'logging-level']
97
+
98
+ Yell.new :stdout, name: Object, level: logging_level.downcase, format: Yell::DefaultFormat
99
+ Object.send :include, Yell::Loggable
100
+
101
+ setup_file_logger(logging_file) if logging_file
102
+
103
+ logger.debug 'Running in debug mode...'
104
+ end
105
+
106
+ def setup_file_logger(logging_file)
107
+ unless (File.exist?(logging_file) && File.writable?(logging_file)) || File.writable?(File.dirname(logging_file))
108
+ logger.error "File #{logging_file} isn't writable"
109
+ return
110
+ end
111
+
112
+ logger.adapter :file, logging_file
113
+ end
114
+ end
115
+ end