imagemaster3000 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
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