aeolus-image 0.0.1
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.
- data/Rakefile +62 -0
- data/bin/aeolus-image +6 -0
- data/examples/aeolus-cli +9 -0
- data/examples/custom_repo.tdl +18 -0
- data/examples/image_description.xml +3 -0
- data/examples/tdl.rng +207 -0
- data/lib/base_command.rb +134 -0
- data/lib/build_command.rb +68 -0
- data/lib/config_parser.rb +212 -0
- data/lib/delete_command.rb +9 -0
- data/lib/import_command.rb +44 -0
- data/lib/list_command.rb +141 -0
- data/lib/push_command.rb +72 -0
- data/man/aeolus-image-build.1 +36 -0
- data/man/aeolus-image-import.1 +57 -0
- data/man/aeolus-image-list.1 +80 -0
- data/man/aeolus-image-push.1 +40 -0
- data/man/aeolus-image.1 +16 -0
- data/spec/base_command_spec.rb +76 -0
- data/spec/build_command_spec.rb +63 -0
- data/spec/config_parser_spec.rb +82 -0
- data/spec/fixtures/invalid_template.tdl +18 -0
- data/spec/fixtures/valid_template.tdl +18 -0
- data/spec/import_command_spec.rb +43 -0
- data/spec/list_command_spec.rb +21 -0
- data/spec/push_command_spec.rb +56 -0
- data/spec/spec.opts +3 -0
- data/spec/spec_helper.rb +52 -0
- metadata +155 -0
data/Rakefile
ADDED
@@ -0,0 +1,62 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'rake'
|
3
|
+
require 'rake/clean'
|
4
|
+
require 'rake/gempackagetask'
|
5
|
+
require 'rake/rdoctask'
|
6
|
+
require 'rake/testtask'
|
7
|
+
require 'spec/rake/spectask'
|
8
|
+
require 'rake/rpmtask'
|
9
|
+
|
10
|
+
RPMBUILD_DIR = "#{File.expand_path('~')}/rpmbuild"
|
11
|
+
RPM_SPEC = "rubygem-aeolus-image.spec"
|
12
|
+
|
13
|
+
spec = Gem::Specification.new do |s|
|
14
|
+
s.name = 'aeolus-image'
|
15
|
+
s.version = '0.0.1'
|
16
|
+
s.has_rdoc = true
|
17
|
+
s.summary= 'cli for aeolus cloud suite'
|
18
|
+
s.description = 'Commandline interface for working with the aeolus cloud management suite'
|
19
|
+
s.author = 'Jason Guiditta, Martyn Taylor'
|
20
|
+
s.email = 'jguiditt@redhat.com, mtaylor@redhat.com'
|
21
|
+
s.license = 'GPL-2'
|
22
|
+
s.homepage = 'http://aeolusproject.org'
|
23
|
+
s.executables << 'aeolus-image'
|
24
|
+
s.files = %w(Rakefile) + Dir.glob("{bin,lib,spec,examples,man}/**/*")
|
25
|
+
s.require_path = "lib"
|
26
|
+
s.bindir = "bin"
|
27
|
+
s.add_dependency('nokogiri', '>=0.4.0')
|
28
|
+
s.add_dependency('rest-client')
|
29
|
+
s.add_dependency('imagefactory-console', '>=0.4.0')
|
30
|
+
|
31
|
+
s.add_development_dependency('rspec', '~>1.3.0')
|
32
|
+
end
|
33
|
+
|
34
|
+
Rake::GemPackageTask.new(spec) do |p|
|
35
|
+
p.gem_spec = spec
|
36
|
+
p.need_tar = true
|
37
|
+
p.need_zip = true
|
38
|
+
end
|
39
|
+
|
40
|
+
Rake::RDocTask.new do |rdoc|
|
41
|
+
files =['README', 'LICENSE', 'lib/**/*.rb']
|
42
|
+
rdoc.rdoc_files.add(files)
|
43
|
+
rdoc.main = "README" # page to start on
|
44
|
+
rdoc.title = "aeolus-image Docs"
|
45
|
+
rdoc.rdoc_dir = 'doc/rdoc' # rdoc output folder
|
46
|
+
rdoc.options << '--line-numbers'
|
47
|
+
end
|
48
|
+
|
49
|
+
Rake::TestTask.new do |t|
|
50
|
+
t.test_files = FileList['test/**/*.rb']
|
51
|
+
end
|
52
|
+
|
53
|
+
Spec::Rake::SpecTask.new do |t|
|
54
|
+
t.spec_files = FileList['spec/**/*.rb']
|
55
|
+
t.libs << Dir["lib"]
|
56
|
+
end
|
57
|
+
|
58
|
+
Rake::RpmTask.new(RPM_SPEC) do |rpm|
|
59
|
+
rpm.need_tar = true
|
60
|
+
rpm.package_files.include("lib/*")
|
61
|
+
rpm.topdir = "#{RPMBUILD_DIR}"
|
62
|
+
end
|
data/bin/aeolus-image
ADDED
data/examples/aeolus-cli
ADDED
@@ -0,0 +1,18 @@
|
|
1
|
+
<template>
|
2
|
+
<name>tmpl1</name>
|
3
|
+
<description>foo</description>
|
4
|
+
<os>
|
5
|
+
<name>Fedora</name>
|
6
|
+
<arch>x86_64</arch>
|
7
|
+
<version>14</version>
|
8
|
+
<install type="url">
|
9
|
+
<url>http://download.fedoraproject.org/pub/fedora/linux/releases/14/Fedora/x86_64/os/</url>
|
10
|
+
</install>
|
11
|
+
</os>
|
12
|
+
<repositories>
|
13
|
+
<repository name="custom">
|
14
|
+
<url>http://repos.fedorapeople.org/repos/aeolus/demo/webapp/</url>
|
15
|
+
<signed>false</signed>
|
16
|
+
</repository>
|
17
|
+
</repositories>
|
18
|
+
</template>
|
data/examples/tdl.rng
ADDED
@@ -0,0 +1,207 @@
|
|
1
|
+
<?xml version="1.0"?>
|
2
|
+
<!-- This Schema is lifted from the OZ project: http://www.aeolusproject.org/oz.html any changes to this schema should be done in the upstream project, then added here-->
|
3
|
+
<!-- A Relax NG schema for the TDL (template description language) format -->
|
4
|
+
<grammar xmlns="http://relaxng.org/ns/structure/1.0" datatypeLibrary="http://www.w3.org/2001/XMLSchema-datatypes">
|
5
|
+
<start>
|
6
|
+
<ref name='template'/>
|
7
|
+
</start>
|
8
|
+
|
9
|
+
<define name='template'>
|
10
|
+
<element name='template'>
|
11
|
+
<interleave>
|
12
|
+
<element name='name'>
|
13
|
+
<text/>
|
14
|
+
</element>
|
15
|
+
<element name='os'>
|
16
|
+
<interleave>
|
17
|
+
<element name='name'>
|
18
|
+
<text/>
|
19
|
+
</element>
|
20
|
+
<element name='version'>
|
21
|
+
<text/>
|
22
|
+
</element>
|
23
|
+
<element name='arch'>
|
24
|
+
<choice>
|
25
|
+
<value>i386</value>
|
26
|
+
<value>x86_64</value>
|
27
|
+
</choice>
|
28
|
+
</element>
|
29
|
+
<element name='install'>
|
30
|
+
<choice>
|
31
|
+
<ref name='url'/>
|
32
|
+
<ref name='iso'/>
|
33
|
+
</choice>
|
34
|
+
</element>
|
35
|
+
<optional>
|
36
|
+
<element name='rootpw'>
|
37
|
+
<text/>
|
38
|
+
</element>
|
39
|
+
</optional>
|
40
|
+
<optional>
|
41
|
+
<element name='key'>
|
42
|
+
<text/>
|
43
|
+
</element>
|
44
|
+
</optional>
|
45
|
+
</interleave>
|
46
|
+
</element>
|
47
|
+
<optional>
|
48
|
+
<element name='description'>
|
49
|
+
<text/>
|
50
|
+
</element>
|
51
|
+
</optional>
|
52
|
+
<optional>
|
53
|
+
<element name='packages'>
|
54
|
+
<zeroOrMore>
|
55
|
+
<element name='package'>
|
56
|
+
<attribute name='name'>
|
57
|
+
<text/>
|
58
|
+
</attribute>
|
59
|
+
<interleave>
|
60
|
+
<optional>
|
61
|
+
<element name='repository'>
|
62
|
+
<text/>
|
63
|
+
</element>
|
64
|
+
</optional>
|
65
|
+
<optional>
|
66
|
+
<element name='file'>
|
67
|
+
<text/>
|
68
|
+
</element>
|
69
|
+
</optional>
|
70
|
+
<optional>
|
71
|
+
<element name='arguments'>
|
72
|
+
<text/>
|
73
|
+
</element>
|
74
|
+
</optional>
|
75
|
+
</interleave>
|
76
|
+
</element>
|
77
|
+
</zeroOrMore>
|
78
|
+
</element>
|
79
|
+
</optional>
|
80
|
+
<optional>
|
81
|
+
<element name='files'>
|
82
|
+
<zeroOrMore>
|
83
|
+
<element name='file'>
|
84
|
+
<attribute name='name'>
|
85
|
+
<text/>
|
86
|
+
</attribute>
|
87
|
+
<choice>
|
88
|
+
<ref name='rawtype'/>
|
89
|
+
<ref name='base64type'/>
|
90
|
+
</choice>
|
91
|
+
</element>
|
92
|
+
</zeroOrMore>
|
93
|
+
</element>
|
94
|
+
</optional>
|
95
|
+
<optional>
|
96
|
+
<element name='commands'>
|
97
|
+
<zeroOrMore>
|
98
|
+
<element name='command'>
|
99
|
+
<attribute name='name'>
|
100
|
+
<text/>
|
101
|
+
</attribute>
|
102
|
+
<choice>
|
103
|
+
<ref name='rawtype'/>
|
104
|
+
<ref name='base64type'/>
|
105
|
+
</choice>
|
106
|
+
</element>
|
107
|
+
</zeroOrMore>
|
108
|
+
</element>
|
109
|
+
</optional>
|
110
|
+
<optional>
|
111
|
+
<element name='repositories'>
|
112
|
+
<zeroOrMore>
|
113
|
+
<element name='repository'>
|
114
|
+
<attribute name='name'>
|
115
|
+
<text/>
|
116
|
+
</attribute>
|
117
|
+
<interleave>
|
118
|
+
<element name='url'>
|
119
|
+
<text/>
|
120
|
+
</element>
|
121
|
+
<optional>
|
122
|
+
<element name='signed'>
|
123
|
+
<ref name='bool'/>
|
124
|
+
</element>
|
125
|
+
</optional>
|
126
|
+
</interleave>
|
127
|
+
</element>
|
128
|
+
</zeroOrMore>
|
129
|
+
</element>
|
130
|
+
</optional>
|
131
|
+
</interleave>
|
132
|
+
</element>
|
133
|
+
</define>
|
134
|
+
|
135
|
+
<define name='url'>
|
136
|
+
<attribute name='type'>
|
137
|
+
<value>url</value>
|
138
|
+
</attribute>
|
139
|
+
<element name='url'>
|
140
|
+
<text/>
|
141
|
+
</element>
|
142
|
+
</define>
|
143
|
+
|
144
|
+
<define name='iso'>
|
145
|
+
<attribute name='type'>
|
146
|
+
<value>iso</value>
|
147
|
+
</attribute>
|
148
|
+
<interleave>
|
149
|
+
<element name='iso'>
|
150
|
+
<text/>
|
151
|
+
</element>
|
152
|
+
<optional>
|
153
|
+
<choice>
|
154
|
+
<element name='md5sum'>
|
155
|
+
<text/>
|
156
|
+
</element>
|
157
|
+
<element name='sha1sum'>
|
158
|
+
<text/>
|
159
|
+
</element>
|
160
|
+
<element name='sha256sum'>
|
161
|
+
<text/>
|
162
|
+
</element>
|
163
|
+
</choice>
|
164
|
+
</optional>
|
165
|
+
</interleave>
|
166
|
+
</define>
|
167
|
+
|
168
|
+
<define name='bool'>
|
169
|
+
<choice>
|
170
|
+
<data type="string">
|
171
|
+
<param name="pattern">[Tt][Rr][Uu][Ee]</param>
|
172
|
+
</data>
|
173
|
+
<data type="string">
|
174
|
+
<param name="pattern">[Ff][Aa][Ll][Ss][Ee]</param>
|
175
|
+
</data>
|
176
|
+
<data type="string">
|
177
|
+
<param name="pattern">[Yy][Ee][Ss]</param>
|
178
|
+
</data>
|
179
|
+
<data type="string">
|
180
|
+
<param name="pattern">[Nn][Oo]</param>
|
181
|
+
</data>
|
182
|
+
</choice>
|
183
|
+
</define>
|
184
|
+
|
185
|
+
<define name='rawtype'>
|
186
|
+
<optional>
|
187
|
+
<attribute name='type'>
|
188
|
+
<value>raw</value>
|
189
|
+
</attribute>
|
190
|
+
</optional>
|
191
|
+
<text/>
|
192
|
+
</define>
|
193
|
+
|
194
|
+
<define name='base64'>
|
195
|
+
<data type="string">
|
196
|
+
<param name="pattern">[a-zA-Z0-9+/]+={0,2}</param>
|
197
|
+
</data>
|
198
|
+
</define>
|
199
|
+
|
200
|
+
<define name='base64type'>
|
201
|
+
<attribute name='type'>
|
202
|
+
<value>base64</value>
|
203
|
+
</attribute>
|
204
|
+
<ref name='base64'/>
|
205
|
+
</define>
|
206
|
+
|
207
|
+
</grammar>
|
data/lib/base_command.rb
ADDED
@@ -0,0 +1,134 @@
|
|
1
|
+
require 'yaml'
|
2
|
+
require 'rest_client'
|
3
|
+
require 'nokogiri'
|
4
|
+
|
5
|
+
module Aeolus
|
6
|
+
module Image
|
7
|
+
#This will house some methods that multiple Command classes need to use.
|
8
|
+
class BaseCommand
|
9
|
+
attr_accessor :options
|
10
|
+
|
11
|
+
def initialize(opts={}, logger=nil)
|
12
|
+
logger(logger)
|
13
|
+
@options = opts
|
14
|
+
@config_location = "~/.aeolus-cli"
|
15
|
+
@config = load_config
|
16
|
+
end
|
17
|
+
|
18
|
+
protected
|
19
|
+
def not_implemented
|
20
|
+
"This option or combination is not yet implemented"
|
21
|
+
end
|
22
|
+
|
23
|
+
def logger(logger=nil)
|
24
|
+
@logger ||= logger
|
25
|
+
unless @logger
|
26
|
+
@logger = Logger.new(STDOUT)
|
27
|
+
@logger.level = Logger::INFO
|
28
|
+
@logger.datetime_format = "%Y-%m-%d %H:%M:%S"
|
29
|
+
end
|
30
|
+
return @logger
|
31
|
+
end
|
32
|
+
|
33
|
+
def iwhd
|
34
|
+
create_resource(:iwhd)
|
35
|
+
end
|
36
|
+
|
37
|
+
def conductor
|
38
|
+
create_resource(:conductor)
|
39
|
+
end
|
40
|
+
|
41
|
+
def read_file(path)
|
42
|
+
begin
|
43
|
+
full_path = File.expand_path(path)
|
44
|
+
if is_file?(path)
|
45
|
+
File.read(full_path)
|
46
|
+
else
|
47
|
+
return nil
|
48
|
+
end
|
49
|
+
rescue
|
50
|
+
nil
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
# TODO: Consider ripping all this file-related stuff into a module or
|
55
|
+
# class for better encapsulation and testability
|
56
|
+
def is_file?(path)
|
57
|
+
full_path = File.expand_path(path)
|
58
|
+
if File.exist?(full_path) && !File.directory?(full_path)
|
59
|
+
return true
|
60
|
+
end
|
61
|
+
false
|
62
|
+
end
|
63
|
+
|
64
|
+
def quit(code)
|
65
|
+
exit(code)
|
66
|
+
end
|
67
|
+
|
68
|
+
def validate_xml_document(schema_path, xml_string)
|
69
|
+
schema = Nokogiri::XML::RelaxNG(File.read(schema_path))
|
70
|
+
doc = Nokogiri::XML xml_string
|
71
|
+
schema.validate(doc)
|
72
|
+
end
|
73
|
+
|
74
|
+
private
|
75
|
+
def load_config
|
76
|
+
begin
|
77
|
+
file_str = read_file(@config_location)
|
78
|
+
if is_file?(@config_location) && !file_str.include?(":url")
|
79
|
+
lines = File.readlines(File.expand_path(@config_location)).map do |line|
|
80
|
+
"#" + line
|
81
|
+
end
|
82
|
+
File.open(File.expand_path(@config_location), 'w') do |file|
|
83
|
+
file.puts lines
|
84
|
+
end
|
85
|
+
write_file
|
86
|
+
end
|
87
|
+
write_file unless is_file?(@config_location)
|
88
|
+
YAML::load(File.open(File.expand_path(@config_location)))
|
89
|
+
rescue Errno::ENOENT
|
90
|
+
#TODO: Create a custom exception to wrap CLI Exceptions
|
91
|
+
raise "Unable to locate or write configuration file: \"" + @config_location + "\""
|
92
|
+
end
|
93
|
+
end
|
94
|
+
|
95
|
+
def write_file
|
96
|
+
example = File.read(File.expand_path(File.dirname(__FILE__) + "/../examples/aeolus-cli"))
|
97
|
+
File.open(File.expand_path(@config_location), 'a+') do |f|
|
98
|
+
f.write(example)
|
99
|
+
end
|
100
|
+
end
|
101
|
+
|
102
|
+
def create_resource(resource_name)
|
103
|
+
# Check to see if config has a resource with this name
|
104
|
+
if !@config.has_key?(resource_name)
|
105
|
+
raise "Unable to determine resource: " + resource_name.to_s + " from configuration file. Please check: " + @config_location
|
106
|
+
return
|
107
|
+
end
|
108
|
+
|
109
|
+
#Use command line arguments for username/password
|
110
|
+
if @options.has_key?(:username)
|
111
|
+
if @options.has_key?(:password)
|
112
|
+
RestClient::Resource.new(@config[resource_name][:url], :user => @options[:username], :password => @options[:password])
|
113
|
+
else
|
114
|
+
#TODO: Create a custom exception to wrap CLI Exceptions
|
115
|
+
raise "Password not found for user: " + @options[:username]
|
116
|
+
end
|
117
|
+
|
118
|
+
#Use config for username/password
|
119
|
+
elsif @config[resource_name].has_key?(:username)
|
120
|
+
if @config[resource_name].has_key?(:password)
|
121
|
+
RestClient::Resource.new(@config[resource_name][:url], :user => @config[resource_name][:username], :password => @config[resource_name][:password])
|
122
|
+
else
|
123
|
+
#TODO: Create a custom exception to wrap CLI Exceptions
|
124
|
+
raise "Password not found for user: " + @config[resource_name][:username]
|
125
|
+
end
|
126
|
+
|
127
|
+
# Do not use authentication
|
128
|
+
else
|
129
|
+
RestClient::Resource.new(@config[resource_name][:url])
|
130
|
+
end
|
131
|
+
end
|
132
|
+
end
|
133
|
+
end
|
134
|
+
end
|