aeolus-image 0.0.1 → 0.4.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (63) hide show
  1. data/COPYING +161 -0
  2. data/Rakefile +32 -19
  3. data/lib/aeolus_image.rb +35 -0
  4. data/lib/aeolus_image/active_resource_oauth_client.rb +62 -0
  5. data/lib/aeolus_image/import.rb +44 -0
  6. data/lib/aeolus_image/model/factory/base.rb +93 -0
  7. data/lib/aeolus_image/model/factory/build.rb +23 -0
  8. data/lib/aeolus_image/model/factory/builder.rb +46 -0
  9. data/lib/aeolus_image/model/factory/image.rb +23 -0
  10. data/lib/aeolus_image/model/factory/provider_image.rb +35 -0
  11. data/lib/aeolus_image/model/factory/target_image.rb +45 -0
  12. data/lib/aeolus_image/model/warehouse/icicle.rb +60 -0
  13. data/lib/aeolus_image/model/warehouse/image.rb +135 -0
  14. data/lib/aeolus_image/model/warehouse/image_build.rb +60 -0
  15. data/lib/aeolus_image/model/warehouse/provider_image.rb +36 -0
  16. data/lib/aeolus_image/model/warehouse/target_image.rb +53 -0
  17. data/lib/aeolus_image/model/warehouse/template.rb +35 -0
  18. data/lib/aeolus_image/model/warehouse/warehouse_client.rb +201 -0
  19. data/lib/aeolus_image/model/warehouse/warehouse_model.rb +236 -0
  20. data/spec/aeolus_image/model/factory/provider_image_spec.rb +12 -0
  21. data/spec/models/factory/base_spec.rb +94 -0
  22. data/spec/models/factory/builder_spec.rb +31 -0
  23. data/spec/models/factory/provider_image_spec.rb +21 -0
  24. data/spec/models/factory/target_image_spec.rb +21 -0
  25. data/spec/models/warehouse/image_build_spec.rb +189 -0
  26. data/spec/models/warehouse/image_spec.rb +241 -0
  27. data/spec/models/warehouse/provider_image_spec.rb +115 -0
  28. data/spec/models/warehouse/target_image_spec.rb +180 -0
  29. data/spec/models/warehouse/template_spec.rb +76 -0
  30. data/spec/models/warehouse/warehouse_client_spec.rb +445 -0
  31. data/spec/models/warehouse/warehouse_model_spec.rb +94 -0
  32. data/spec/spec_helper.rb +34 -47
  33. data/spec/vcr/cassettes/builder.yml +24 -0
  34. data/spec/vcr/cassettes/oauth.yml +80 -0
  35. data/spec/vcr/cassettes/oauth_fail_invalid.yml +30 -0
  36. data/spec/vcr/cassettes/oauth_fail_no.yml +22 -0
  37. data/spec/vcr/cassettes/oauth_success_valid.yml +30 -0
  38. data/spec/vcr_setup.rb +26 -0
  39. metadata +70 -46
  40. data/bin/aeolus-image +0 -6
  41. data/examples/aeolus-cli +0 -9
  42. data/examples/custom_repo.tdl +0 -18
  43. data/examples/image_description.xml +0 -3
  44. data/examples/tdl.rng +0 -207
  45. data/lib/base_command.rb +0 -134
  46. data/lib/build_command.rb +0 -68
  47. data/lib/config_parser.rb +0 -212
  48. data/lib/delete_command.rb +0 -9
  49. data/lib/import_command.rb +0 -44
  50. data/lib/list_command.rb +0 -141
  51. data/lib/push_command.rb +0 -72
  52. data/man/aeolus-image-build.1 +0 -36
  53. data/man/aeolus-image-import.1 +0 -57
  54. data/man/aeolus-image-list.1 +0 -80
  55. data/man/aeolus-image-push.1 +0 -40
  56. data/man/aeolus-image.1 +0 -16
  57. data/spec/base_command_spec.rb +0 -76
  58. data/spec/build_command_spec.rb +0 -63
  59. data/spec/config_parser_spec.rb +0 -82
  60. data/spec/import_command_spec.rb +0 -43
  61. data/spec/list_command_spec.rb +0 -21
  62. data/spec/push_command_spec.rb +0 -56
  63. data/spec/spec.opts +0 -3
@@ -1,212 +0,0 @@
1
- require 'optparse'
2
- require 'logger'
3
- require 'base_command'
4
- require 'list_command'
5
- require 'build_command'
6
- require 'push_command'
7
- require 'import_command'
8
- require 'delete_command'
9
-
10
- module Aeolus
11
- module Image
12
- class ConfigParser
13
- COMMANDS = %w(list build push import delete)
14
- attr_accessor :options, :command, :args
15
-
16
- def initialize(argv)
17
- @args = argv
18
- # Default options
19
- @options = {}
20
- parse
21
- end
22
-
23
- def process
24
- # Check for command, then call appropriate Optionparser and initiate
25
- # call to that class.
26
- @command = @args.shift
27
- # Eventually get the config file from user dir if it exists.
28
- # File.expand_path("~")
29
- if COMMANDS.include?(@command)
30
- self.send(@command.to_sym)
31
- else
32
- @args << "-h"
33
- puts "Valid command required: \n\n"
34
- parse
35
- end
36
- end
37
-
38
- private
39
- def parse
40
- @optparse ||= OptionParser.new do|opts|
41
- opts.banner = "Usage: aeolus-image [#{COMMANDS.join('|')}] [general options] [command options]"
42
-
43
- opts.separator ""
44
- opts.separator "General options:"
45
- opts.on('-u', '--user USERNAME', 'Conductor username') do |user|
46
- @options[:user] = user
47
- end
48
- opts.on('-w', '--password PASSWORD', 'Conductor password') do |pw|
49
- @options[:password] = pw
50
- end
51
- opts.on('-d', '--id ID', 'id for a given object') do |id|
52
- @options[:id] = id
53
- end
54
- opts.on('-r', '--description NAME', 'description (e.g. "<image><name>MyImage</name></image>" or "/home/user/myImage.xml")') do |description|
55
- @options[:description] = description
56
- end
57
- opts.on('-r', '--provider NAME1,NAME2', Array,'name of specific provider (ie ec2-us-east1)') do |name|
58
- @options[:provider] = name
59
- end
60
- opts.on('-I', '--image ID', 'ID of the base image, can be used in build and push commands, see examples') do |id|
61
- @options[:image] = id
62
- end
63
- opts.on('-T', '--target TARGET1,TARGET2', Array, 'provider type (ec2, rackspace, rhevm, etc)') do |name|
64
- @options[:target] = name
65
- end
66
- opts.on('-d', '--daemon', 'run as a background process') do
67
- @options[:subcommand] = :images
68
- end
69
- opts.on( '-h', '--help', 'Get usage information for this tool') do
70
- puts opts
71
- exit(0)
72
- end
73
-
74
- opts.separator ""
75
- opts.separator "List options:"
76
- opts.on('-i', '--images', 'Retrieve a list of images') do
77
- @options[:subcommand] = :images
78
- end
79
- opts.on('-b', '--builds ID', 'Retrieve the builds of an image') do |id|
80
- @options[:subcommand] = :builds
81
- @options[:id] = id
82
- end
83
- opts.on('-t', '--targetimages ID', 'Retrieve the target images from a build') do |id|
84
- @options[:subcommand] = :targetimages
85
- @options[:id] = id
86
- end
87
- opts.on('-P', '--providerimages ID', 'Retrieve the provider images from a target image') do |id|
88
- @options[:subcommand] = :targetimages
89
- @options[:id] = id
90
- end
91
- opts.on('-g', '--targets', 'Retrieve the values available for the --target parameter') do
92
- @options[:subcommand] = :targets
93
- end
94
- opts.on('-p', '--providers', 'Retrieve the values available for the --provider parameter') do
95
- @options[:subcommand] = :providers
96
- end
97
- opts.on('-a', '--accounts', 'Retrieve the values available for the --account parameter') do
98
- @options[:subcommand] = :accounts
99
- end
100
-
101
- opts.separator ""
102
- opts.separator "Build options:"
103
- opts.on('-e', '--template FILE', 'path to file that contains template xml') do |file|
104
- @options[:template] = file
105
- end
106
-
107
- opts.separator ""
108
- opts.separator "Push options:"
109
- opts.on('-B', '--build ID', 'push all target images for a build, to same providers as previously') do |id|
110
- @options[:build] = id
111
- end
112
- opts.on('-A', '--account NAME', 'name of specific provider account to use for push') do |name|
113
- @options[:account] = name
114
- end
115
-
116
- opts.separator ""
117
- opts.separator "Delete options:"
118
- opts.on('-m', '--targetimage ID', 'delete target image and its provider images') do |id|
119
- @options[:targetimage] = id
120
- end
121
- opts.on('-D', '--providerimage ID', 'delete provider image') do |id|
122
- @options[:providerimage] = id
123
- end
124
-
125
- opts.separator ""
126
- opts.separator "List Examples:"
127
- opts.separator "aeolus-image list --images # list available images"
128
- opts.separator "aeolus-image list --builds $image_id # list the builds of an image"
129
- opts.separator "aeolus-image list --targetimages $build_id # list the target images from a build"
130
- opts.separator "aeolus-image list --targets # list the values available for the --target parameter"
131
- opts.separator "aeolus-image list --providers # list the values available for the --provider parameter"
132
- opts.separator "aeolus-image list --accounts # list the values available for the --account parameter"
133
-
134
- opts.separator ""
135
- opts.separator "Build examples:"
136
- opts.separator "aeolus-image build --target ec2 --template my.tmpl # build a new image for ec2 from the template"
137
- opts.separator "aeolus-image build --image $image_id # (NOT IMPLEMENTED) rebuild the image template and targets from latest build"
138
- opts.separator %q{aeolus-image build --target ec2,rackspace \ # rebuild the image with a new template and set of targets
139
- --image $image_i \
140
- --template my.tmpl}
141
-
142
- opts.separator ""
143
- opts.separator "Push examples:"
144
- opts.separator "aeolus-image push --provider ec2-us-east-1 --id $image_id # initial push of an image build via image id to the specified provider"
145
- opts.separator "aeolus-image push --build $build_id # push an image build via build id to the specified provider"
146
- opts.separator "aeolus-image push --account $provider_account --build $build_id # (NOT IMPLEMENTED) ditto, using a specific provider account"
147
- opts.separator "aeolus-image push --image $image_id # (NOT IMPLEMENTED) push all the target images for the latest build"
148
-
149
- opts.separator ""
150
- opts.separator "Import examples:"
151
- opts.separator "aeolus-image import --provider ec2-us-east-1 --target ec2 --id $ami_id # import an AMI from the specified provider"
152
- opts.separator "aeolus-image import --provider ec2-us-east-1 --target ec2 --id $ami_id --description '<image><name>My Image</name></image>' # import an AMI from the specified provider"
153
- opts.separator "aeolus-image import --provider ec2-us-east-1 --target ec2 --id $ami_id --description <path_to_xml_file> # import an AMI from the specified provider"
154
-
155
- opts.separator ""
156
- opts.separator "Delete examples: (DELETE CURRENTLY NOT IMPLEMENTED) "
157
- opts.separator "aeolus-image delete --build $build_id # deletes a build, updating latest/parent references as appropriate"
158
- opts.separator "aeolus-image delete --targetimage $target_image # deletes a target image and its provider images"
159
- opts.separator "aeolus-image delete --providerimage $provider_image # deletes a provider image"
160
- end
161
-
162
- begin
163
- @optparse.parse!(@args)
164
- rescue OptionParser::InvalidOption
165
- puts "Warning: Invalid option"
166
- exit(1)
167
- rescue OptionParser::MissingArgument => e
168
- puts "Warning, #{e.message}"
169
- exit(1)
170
- end
171
- end
172
-
173
- # TODO: Remove all this boilerplate and replace with some metaprogramming,
174
- # perhaps method_missing
175
- def list
176
- # TODO: Instantiate and call object matching command type, for example:
177
- # l = ListCommand.new(@options)
178
- # Each Command will call it's own internal method depending on the contents of the hash.
179
- # For the list example above, that object would call a method 'images' based on the item
180
- # @options[:subcommand] being :images, so internally that class may do something like:
181
- # self.send(@options[:subcommand])
182
- if @options[:subcommand].nil?
183
- # TODO: Pull out Print Usage into seporate method, and print
184
- puts "Could not find subcommand for list, run `./aeolus-image --help` for usage instructions"
185
- exit(1)
186
- else
187
- list_command = ListCommand.new(@options)
188
- list_command.send(@options[:subcommand])
189
- end
190
- end
191
-
192
- def build
193
- b = BuildCommand.new(@options)
194
- b.run
195
- end
196
-
197
- def push
198
- b = PushCommand.new(@options)
199
- b.run
200
- end
201
-
202
- def import
203
- import_command = ImportCommand.new(@options)
204
- import_command.import_image
205
- end
206
-
207
- def delete
208
- "Not implemented"
209
- end
210
- end
211
- end
212
- end
@@ -1,9 +0,0 @@
1
- module Aeolus
2
- module Image
3
- class DeleteCommand < BaseCommand
4
- def initialize(opts={}, logger=nil)
5
- super(opts, logger)
6
- end
7
- end
8
- end
9
- end
@@ -1,44 +0,0 @@
1
- module Aeolus
2
- module Image
3
- class ImportCommand < BaseCommand
4
- def initialize(opts={}, logger=nil)
5
- super(opts, logger)
6
- default = {
7
- :image => '',
8
- :build => '',
9
- :id => '',
10
- :description => '<image><name>' + @options[:id] + '</name></image>',
11
- :target => '',
12
- :provider => ''
13
- }
14
- @options = default.merge(@options)
15
- @console = ImageFactoryConsole.new()
16
- @console.start
17
- end
18
-
19
- def import_image
20
- description = read_file(@options[:description])
21
- if !description.nil?
22
- @options[:description] = description
23
- end
24
- # TODO: Validate Description XML
25
-
26
- #This is a temporary hack in case the agent doesn't show up on bus
27
- #immediately
28
- sleep(5)
29
- import_map = @console.import_image(@options[:image], @options[:build], @options[:id], @options[:description], @options[:target].first, @options[:provider].first)
30
- puts ""
31
- puts "Target Image: " + import_map['target_image']
32
- puts "Image: " + import_map['image']
33
- puts "Build: " + import_map['build']
34
- puts "Provider Image: " + import_map['provider_image']
35
- quit(0)
36
- end
37
-
38
- def quit(code)
39
- @console.shutdown
40
- super
41
- end
42
- end
43
- end
44
- end
@@ -1,141 +0,0 @@
1
- module Aeolus
2
- module Image
3
- class ListCommand < BaseCommand
4
- def initialize(opts={}, logger=nil)
5
- super(opts, logger)
6
- end
7
-
8
- def images
9
- images = [["IMAGE ID", "LASTEST PUSHED BUILD", "NAME", "TARGET", "OS", "OS VERSION", "ARCH", "DESCRIPTION"]]
10
- doc = Nokogiri::XML iwhd['/target_images'].get
11
- # Check for any invalid data in iwhd
12
- invalid_images = []
13
- doc.xpath("/objects/object/key").each do |targetimage|
14
- begin
15
- build = iwhd["/target_images/" + targetimage.text + "/build"].get
16
- image = iwhd["/builds/" + build + "/image"].get
17
-
18
- if template_info = get_template_info(image, targetimage.text)
19
- images << [image] + [lastest_pushed(image)] + template_info
20
- else
21
- images << [image] + [lastest_pushed(image)] +[get_image_name(image), iwhd["/target_images/" + targetimage + "/target"].get, "", "", "", ""]
22
- end
23
- rescue
24
- invalid_images << targetimage.text
25
- end
26
- end
27
- format_print(images)
28
-
29
- unless invalid_images.empty?
30
- puts "\nN.B. following images were not listed, aeolus-image encountered some invalid data in iwhd:"
31
- puts invalid_images.join "\n"
32
- end
33
- quit(0)
34
- end
35
-
36
- def builds
37
- doc = Nokogiri::XML iwhd['/builds'].get
38
- doc.xpath("/objects/object/key").each do |build|
39
- if iwhd['/builds/' + build.text + "/image"].get == @options[:id]
40
- puts build.text
41
- end
42
- end
43
- quit(0)
44
- end
45
-
46
- def targetimages
47
- doc = Nokogiri::XML iwhd['/target_images'].get
48
- doc.xpath("/objects/object/key").each do |target_image|
49
- begin
50
- if iwhd['/target_images/' + target_image.text + "/build"].get == @options[:id]
51
- puts target_image.text
52
- end
53
- rescue RestClient::ResourceNotFound
54
- end
55
- end
56
- quit(0)
57
- end
58
-
59
- def targets
60
- targets = [["NAME", "TARGET CODE"]]
61
- targets << ["Mock", "mock"]
62
- targets << ["Amazon EC2", "ec2"]
63
- targets << ["RHEV-M", "rhevm"]
64
- targets << ["VMware vSphere", "vsphere"]
65
- targets << ["Condor Cloud", "condor_cloud"]
66
- format_print(targets)
67
- quit(0)
68
- end
69
-
70
- def providers
71
- print_values = [["NAME", "TYPE", "URL"]]
72
-
73
- doc = Nokogiri::XML conductor['/providers'].get
74
- doc.xpath("/providers/provider").each do |provider|
75
- print_values << [provider.xpath("name").text, provider.xpath("provider_type").text, provider.xpath("url").text]
76
- end
77
-
78
- format_print(print_values)
79
- quit(0)
80
- end
81
-
82
- def accounts
83
- print_values = [["NAME", "PROVIDER", "PROVIDER TYPE"]]
84
- doc = Nokogiri::XML conductor['/provider_accounts/'].get
85
- doc.xpath("/provider_accounts/provider_account").each do |account|
86
- print_values << [account.xpath("name").text, account.xpath("provider").text, account.xpath("provider_type").text]
87
- end
88
-
89
- format_print(print_values)
90
- quit(0)
91
- end
92
-
93
- private
94
- # Takes a 2D array of strings and neatly prints them to STDOUT
95
- def format_print(print_values)
96
- widths = Array.new(print_values[0].size, 0)
97
- print_values.each do |print_value|
98
- widths = widths.zip(print_value).map! {|width, value| value.length > width ? value.length : width }
99
- end
100
-
101
- print_values.each do |print_value|
102
- widths.zip(print_value) do |width, value|
103
- printf("%-#{width + 5}s", value)
104
- end
105
- puts ""
106
- end
107
- end
108
-
109
- def get_template_info(image, targetimage)
110
- begin
111
- template = Nokogiri::XML iwhd["/templates/" + iwhd["/target_images/" + targetimage + "/template"].get].get
112
- [template.xpath("/template/name").text,
113
- iwhd["/target_images/" + targetimage + "/target"].get,
114
- template.xpath("/template/os/name").text,
115
- template.xpath("/template/os/version").text,
116
- template.xpath("/template/os/arch").text,
117
- template.xpath("/template/description").text]
118
- rescue
119
- end
120
- end
121
-
122
- def get_image_name(image)
123
- begin
124
- template_xml = Nokogiri::XML iwhd["images/" + image].get
125
- template_xml.xpath("/image/name").text
126
- rescue
127
- ""
128
- end
129
- end
130
-
131
- def lastest_pushed(image)
132
- begin
133
- build = iwhd["/images/" + image + "/latest_build"].get
134
- build.nil? ? "" : build
135
- rescue
136
- ""
137
- end
138
- end
139
- end
140
- end
141
- end
@@ -1,72 +0,0 @@
1
- require 'rest_client'
2
-
3
- module Aeolus
4
- module Image
5
- class PushCommand < BaseCommand
6
- attr_accessor :console
7
- def initialize(opts={}, logger=nil)
8
- super(opts, logger)
9
- default = {
10
- :provider => [],
11
- :id => '',
12
- :build => ''
13
- }
14
- @options = default.merge(@options)
15
- @console = ImageFactoryConsole.new()
16
- @console.start
17
- end
18
- def run
19
- begin
20
- if combo_implemented?
21
- if !@options[:id].empty? && pushed?(@options[:id])
22
- puts "ERROR: This image has already been pushed, to push to another provider please push via build-id rather than image-id"
23
- puts "e.g. aeolus-image push --provider <provider> --build <build-id>"
24
- quit(1)
25
- end
26
-
27
- sleep(5)
28
- @console.push(@options[:provider], get_creds, @options[:id], @options[:build]).each do |adaptor|
29
- puts ""
30
- puts "Provider Image: #{adaptor.image_id}"
31
- puts "Image: #{adaptor.image}"
32
- puts "Build: #{adaptor.build}"
33
- puts "Status: #{adaptor.status}"
34
- puts "Percent Complete: #{adaptor.percent_complete}"
35
- end
36
- quit(0)
37
- end
38
- rescue
39
- puts "An Error occured whilst trying to push this build, please check aeolus-image --help for details on how to use this command"
40
- quit(1)
41
- end
42
- end
43
-
44
- def get_creds
45
- conductor['provider_accounts'].get
46
- end
47
-
48
- def combo_implemented?
49
- if @options[:provider].empty? || (@options[:build].empty? && @options[:id].empty?)
50
- puts "This combination of parameters is not currently supported"
51
- quit(1)
52
- end
53
- true
54
- end
55
-
56
- private
57
- def quit(code)
58
- @console.shutdown
59
- exit(code)
60
- end
61
-
62
- def pushed?(image)
63
- begin
64
- uuid = Regexp.new('[\w]{8}[-][\w]{4}[-][\w]{4}[-][\w]{4}[-][\w]{12}')
65
- uuid.match(iwhd["/images/" + image + "/latest_unpushed"].get).nil? ? true : false
66
- rescue
67
- true
68
- end
69
- end
70
- end
71
- end
72
- end