ssc 0.1 → 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
data/Gemfile ADDED
@@ -0,0 +1,14 @@
1
+ source "http://rubygems.org"
2
+
3
+ gem "studio_api", ">= 3.1.2"
4
+ gem "thor", ">=0.14.6"
5
+
6
+ # Add dependencies to develop your gem here.
7
+ # Include everything needed to run rake, tests, features, etc.
8
+ group :development do
9
+ gem "shoulda", ">= 0"
10
+ gem "mocha", ">= 0"
11
+ gem "bundler", "~> 1.0.0"
12
+ gem "jeweler", "~> 1.6.0"
13
+ gem "rcov", ">= 0"
14
+ end
data/Gemfile.lock ADDED
@@ -0,0 +1,39 @@
1
+ GEM
2
+ remote: http://rubygems.org/
3
+ specs:
4
+ activemodel (3.0.0)
5
+ activesupport (= 3.0.0)
6
+ builder (~> 2.1.2)
7
+ i18n (~> 0.4.1)
8
+ activeresource (3.0.0)
9
+ activemodel (= 3.0.0)
10
+ activesupport (= 3.0.0)
11
+ activesupport (3.0.0)
12
+ builder (2.1.2)
13
+ git (1.2.5)
14
+ i18n (0.4.1)
15
+ jeweler (1.6.0)
16
+ bundler (~> 1.0.0)
17
+ git (>= 1.2.5)
18
+ rake
19
+ mocha (0.9.12)
20
+ rake (0.8.7)
21
+ rcov (0.9.9)
22
+ shoulda (2.11.3)
23
+ studio_api (3.1.2)
24
+ activeresource (>= 2.3.8)
25
+ xml-simple (>= 1.0.0)
26
+ thor (0.14.6)
27
+ xml-simple (1.1.0)
28
+
29
+ PLATFORMS
30
+ ruby
31
+
32
+ DEPENDENCIES
33
+ bundler (~> 1.0.0)
34
+ jeweler (~> 1.6.0)
35
+ mocha
36
+ rcov
37
+ shoulda
38
+ studio_api (>= 3.1.2)
39
+ thor (>= 0.14.6)
data/README.rdoc ADDED
@@ -0,0 +1,22 @@
1
+ = ssc
2
+
3
+ This is the new version of the the Suse Studio command line client. Built as a part of GSOC 2011.
4
+
5
+ == Installing ssc
6
+
7
+ === Straight from the code
8
+ * Checkout the code
9
+ * In the checked out directory do `rake install`
10
+
11
+ === Ocassionally released packaged gems
12
+ * Download
13
+
14
+ == Contributing to ssc
15
+
16
+ * Check out the latest master to make sure the feature hasn't been implemented or the bug hasn't been fixed yet
17
+ * Check out the issue tracker to make sure someone already hasn't requested it and/or contributed it
18
+ * Fork the project
19
+ * Start a feature/bugfix branch
20
+ * Commit and push until you are happy with your contribution
21
+ * Make sure to add tests for it. This is important so I don't break it in a future version unintentionally.
22
+ * Please try not to mess with the Rakefile, version, or history. If you want to have your own version, or is otherwise necessary, that is fine, but please isolate to its own commit so I can cherry-pick around it.
data/Rakefile ADDED
@@ -0,0 +1,53 @@
1
+ # encoding: utf-8
2
+
3
+ require 'rubygems'
4
+ require 'bundler'
5
+ begin
6
+ Bundler.setup(:default, :development)
7
+ rescue Bundler::BundlerError => e
8
+ $stderr.puts e.message
9
+ $stderr.puts "Run `bundle install` to install missing gems"
10
+ exit e.status_code
11
+ end
12
+ require 'rake'
13
+
14
+ require 'jeweler'
15
+ Jeweler::Tasks.new do |gem|
16
+ # gem is a Gem::Specification... see http://docs.rubygems.org/read/chapter/20 for more options
17
+ gem.name = "ssc"
18
+ gem.homepage = "http://github.com/rjsvaljean/ssc"
19
+ gem.license = "MIT"
20
+ gem.summary = %Q{Command-line client for Suse Studio}
21
+ gem.description = %Q{Command-line client for Suse Studio}
22
+ gem.email = "rjsvaljean@gmail.com"
23
+ gem.authors = ["Ratan Sebastian"]
24
+ # dependencies defined in Gemfile
25
+ end
26
+ Jeweler::RubygemsDotOrgTasks.new
27
+
28
+ require 'rake/testtask'
29
+ Rake::TestTask.new(:test) do |test|
30
+ test.libs << 'lib' << 'test'
31
+ test.pattern = 'test/**/test_*.rb'
32
+ test.verbose = true
33
+ end
34
+
35
+ require 'rcov/rcovtask'
36
+ Rcov::RcovTask.new do |test|
37
+ test.libs << 'test'
38
+ test.pattern = 'test/**/test_*.rb'
39
+ test.verbose = true
40
+ test.rcov_opts << '--exclude "gems/*"'
41
+ end
42
+
43
+ task :default => :test
44
+
45
+ require 'rake/rdoctask'
46
+ Rake::RDocTask.new do |rdoc|
47
+ version = File.exist?('VERSION') ? File.read('VERSION') : ""
48
+
49
+ rdoc.rdoc_dir = 'rdoc'
50
+ rdoc.title = "ssc #{version}"
51
+ rdoc.rdoc_files.include('README*')
52
+ rdoc.rdoc_files.include('lib/**/*.rb')
53
+ end
data/VERSION ADDED
@@ -0,0 +1 @@
1
+ 0.2.0
data/bin/ssc CHANGED
@@ -1,233 +1,6 @@
1
- #!/usr/bin/ruby
1
+ #!/usr/bin/env ruby
2
2
 
3
- require 'rubygems'
4
- require 'net/http'
5
- require 'net/netrc'
6
- require 'xml/smart'
7
- require 'cgi'
8
- require 'fileutils'
9
- require 'optparse'
3
+ $LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
10
4
 
11
- $LOAD_PATH << "#{File.dirname(__FILE__)}/../lib"
12
- require 'appliancehandler.rb'
13
- require 'buildhandler.rb'
14
- require 'checkouthandler.rb'
15
-
16
-
17
- $server_name="susestudio.com"
18
- $api_prefix="api/v1/user"
19
- $username=""
20
- $password=""
21
- force = false
22
- follow = false
23
- images = false
24
- version="0.1"
25
-
26
- def get_appliance_from_args_or_config args
27
- if args
28
- appliance = args[1]
29
- end
30
- unless appliance
31
- if File.exists?(".ssc/appliance.config")
32
- appliance_config = XML::Smart.open(".ssc/appliance.config")
33
- appliance = appliance_config.find("/checkout/appliance_id").first.to_s if appliance_config.find("/checkout/appliance_id").length > 0
34
- end
35
- end
36
- if appliance.nil? || appliance.empty?
37
- STDERR.puts "You need to specify an appliance."
38
- exit 1
39
- end
40
- appliance
41
- end
42
-
43
- def base_url
44
- "http://#{$server_name}/#{$api_prefix}"
45
- end
46
-
47
- opt = OptionParser.new
48
- opt.separator("Options")
49
- opt.on( "-s", "--server", "=HOST",
50
- "The Studio hostname" ) do |v|
51
- $server_name = v
52
- end
53
- opt.on( "-u", "--username", "=USER_NAME", "User name") do |v|
54
- $username = v
55
- end
56
- opt.on( "-p", "--password", "=PASSWORD", "Password") do |v|
57
- $password = v
58
- end
59
- opt.on( "-h", "--help", "Print this message" ) do
60
- puts opt
61
- exit
62
- end
63
- opt.on( "-v", "--version", "Print the version") do |v|
64
- puts "ssc #{version} - A command line interface to SUSE Studio"
65
- exit 0
66
- end
67
-
68
- # Try to get credentials from .netrc
69
- rc = Net::Netrc.locate($server_name)
70
- if $username.empty? and $password.empty? and rc
71
- $username = rc.login
72
- $password = rc.password
73
- end
74
-
75
-
76
- if ARGV.include?("ba") || ARGV.include?("buildappliance")
77
- opt.banner = "Usage: ssc [options] buildappliance APPLIANCE [command-options]"
78
- opt.separator("Trigger a build of an appliance.")
79
- opt.separator("\n")
80
- opt.separator("Command options:")
81
- opt.on( "-f", "--force","Force building the appliance even if it overwrites a build") do |v|
82
- force = v
83
- end
84
- elsif ARGV.include?("la") || ARGV.include?("listappliances")
85
- opt.banner = "Usage: ssc [options] listappliances"
86
- opt.separator("Show a list of your appliances.")
87
- elsif ARGV.include?("ca") || ARGV.include?("cloneappliance")
88
- opt.banner = "Usage: ssc [options] cloneappliance APPLIANCE"
89
- opt.separator("Create a new appliance by cloning a template.")
90
- elsif ARGV.include?("da") || ARGV.include?("deleteappliance")
91
- opt.banner = "Usage: ssc [options] deleteappliance APPLIANCE"
92
- opt.separator("Delete an appliance.")
93
- elsif ARGV.include?("lt") || ARGV.include?("listtemplates")
94
- opt.banner = "Usage: ssc [options] listtemplates"
95
- opt.separator("Get a list of available templates.")
96
- elsif ARGV.include?("lrb") || ARGV.include?("listrunningbuilds")
97
- opt.banner = "Usage: ssc [options] listrunningbuilds APPLIANCE"
98
- opt.separator("List all running builds of an appliance.")
99
- elsif ARGV.include?("srb") || ARGV.include?("showrunningbuild")
100
- opt.banner = "Usage: ssc [options] showrunningbuild ID"
101
- opt.separator("Show the status of a running build.")
102
- opt.on( "-f", "--follow","Follow the progress of the build") do |f|
103
- follow = f
104
- end
105
- elsif ARGV.include?("lb") || ARGV.include?("listbuilds")
106
- opt.banner = "Usage: ssc [options] listbuilds APPLIANCE"
107
- opt.separator("List builds of an appliance.")
108
- elsif ARGV.include?("sb") || ARGV.include?("showbuild")
109
- opt.banner = "Usage: ssc [options] showbuild ID"
110
- opt.separator("Show information on a build.")
111
- elsif ARGV.include?("cb") || ARGV.include?("cancelbuild")
112
- opt.banner = "Usage: ssc [options] cancelbuild ID"
113
- opt.separator("Cancel a running build.")
114
- elsif ARGV.include?("db") || ARGV.include?("deletebuild")
115
- opt.banner = "Usage: ssc [options] deletebuild ID"
116
- opt.separator("Delete a finished build.")
117
- elsif ARGV.include?("co") || ARGV.include?("checkout")
118
- opt.banner = "Usage: ssc [options] checkout APPLIANCE"
119
- opt.separator("Checkout an appliance.")
120
- opt.on( "-i", "--download-images","Download images of the appliance") do |i|
121
- images = i
122
- end
123
- elsif ARGV.include?("st") || ARGV.include?("status")
124
- opt.banner = "Usage: ssc [options] status"
125
- opt.separator("Show the status of the checkout.")
126
- elsif ARGV.include?("ci") || ARGV.include?("commit")
127
- opt.banner = "Usage: ssc [options] commit"
128
- opt.separator("Commit changes to the appliance.")
129
- elsif ARGV.include?("add")
130
- opt.banner = "Usage: ssc [options] add FILE"
131
- opt.separator("Add a file to the checkout.")
132
- elsif ARGV.include?("rm") || ARGV.include?("remove")
133
- opt.banner = "Usage: ssc [options] remove FILE"
134
- opt.separator("Remove a file from the checkout.")
135
- else
136
- opt.banner = "Usage: ssc [options] COMMAND [command-options]"
137
- opt.separator("SUSE Studio command line client.")
138
- opt.separator("Type 'ssc COMMAND --help' for help on a specific command.")
139
-
140
- opt.separator("\n")
141
- opt.separator("Commands:")
142
- opt.separator(" Managing your appliances:")
143
- opt.separator(" listappliances,la\t\t Get a list of your appliances")
144
- opt.separator(" cloneappliance,ca\t\t Create a new appliance by cloning a template")
145
- opt.separator(" deleteappliance,da\t Delete an appliance")
146
- opt.separator(" listtemplates,lt\t\t Get a list of available templates")
147
- opt.separator("\n")
148
- opt.separator(" Managing builds:")
149
- opt.separator(" buildappliance,ba\t\t Trigger a build of an appliance")
150
- opt.separator(" listrunningbuilds,lrb\t List all running builds of an appliance")
151
- opt.separator(" showrunningbuild,srb\t Show the status of a running build")
152
- opt.separator(" listbuilds,lb\t\t List builds of an appliance")
153
- opt.separator(" showbuild,sb\t\t Show information on a build")
154
- opt.separator(" cancelbuild,cb\t\t Cancel a running build")
155
- opt.separator(" deletebuild,db\t\t Delete a finished build")
156
- opt.separator("\n")
157
- opt.separator(" Managing checkouts:")
158
- opt.separator(" checkout,co\t\t Checkout an appliance")
159
- opt.separator(" status,st\t\t\t Show the status of the checkout")
160
- opt.separator(" commit,ci\t\t\t Commit changes to the appliance")
161
- opt.separator(" add\t\t\t Add a file to the checkout")
162
- opt.separator(" rm\t\t\t Remove a file from the checkout")
163
- opt.separator("\n")
164
- end
165
-
166
- begin
167
- opt.parse!( ARGV )
168
- rescue OptionParser::InvalidOption
169
- STDERR.puts $!
170
- STDERR.puts opt
171
- exit 1
172
- end
173
-
174
- if ARGV.size == 0
175
- STDERR.puts opt
176
- exit 1
177
- end
178
-
179
- cmd = ARGV[0]
180
-
181
- if cmd == "listappliances" or cmd =="la"
182
- ApplianceHandler.list_appliances
183
-
184
- elsif cmd == "cloneappliance" or cmd =="ca"
185
- ApplianceHandler.clone_appliance ARGV
186
-
187
- elsif cmd == "deleteappliance" or cmd == "da"
188
- ApplianceHandler.delete_appliance ARGV
189
-
190
- elsif cmd == "listtemplates" or cmd =="lt"
191
- ApplianceHandler.template_sets
192
-
193
- elsif cmd == "buildappliance" or cmd =="ba"
194
- BuildHandler.build_appliance ARGV, force
195
-
196
- elsif cmd == "listrunningbuilds" or cmd =="lrb"
197
- BuildHandler.list_running_builds ARGV
198
-
199
- elsif cmd == "showrunningbuild" or cmd =="srb"
200
- BuildHandler.show_running_build ARGV, follow
201
-
202
- elsif cmd == "listbuilds" or cmd =="lb"
203
- BuildHandler.list_builds ARGV
204
-
205
- elsif cmd == "showbuild" or cmd =="sb"
206
- BuildHandler.show_build ARGV
207
-
208
- elsif cmd == "cancelbuild" or cmd =="cb"
209
- BuildHandler.cancel_build ARGV
210
-
211
- elsif cmd == "deletebuild" or cmd =="db"
212
- BuildHandler.delete_build ARGV
213
-
214
- elsif cmd == "checkout" or cmd =="co"
215
- CheckoutHandler.checkout ARGV, images
216
-
217
- elsif cmd == "status" or cmd =="st"
218
- CheckoutHandler.status
219
-
220
- elsif cmd == "commit" or cmd =="ci"
221
- CheckoutHandler.commit
222
-
223
- elsif cmd == "add"
224
- CheckoutHandler.add ARGV
225
-
226
- elsif cmd == "remove" or cmd == "rm"
227
- CheckoutHandler.remove ARGV
228
-
229
- else
230
- STDERR.puts "Unknown command: #{cmd}\n"
231
- STDERR.puts opt
232
- exit 1
233
- end
5
+ require 'ssc'
6
+ SSC::Base.start
@@ -0,0 +1,194 @@
1
+ module SSC
2
+ module DirectoryManager
3
+
4
+ def self.included(base)
5
+ base.extend ClassMethods
6
+ base.send :include, InstanceMethods
7
+ end
8
+
9
+ module ClassMethods
10
+ def create_appliance_directory(appliance_dir, username, password, appliance_id)
11
+ FileUtils.mkdir_p(appliance_dir)
12
+ FileUtils.mkdir_p(File.join(appliance_dir, 'files'))
13
+ FileUtils.touch(File.join(appliance_dir, 'repositories'))
14
+ FileUtils.touch(File.join(appliance_dir, 'software'))
15
+ FileUtils.touch(File.join(appliance_dir, 'files/.file_list'))
16
+ File.open(File.join(appliance_dir, '.sscrc'), 'w') do |file|
17
+ file.write("username: #{username}\n"+
18
+ "password: #{password}\n"+
19
+ "appliance_id: #{appliance_id}")
20
+ end
21
+ File.join(Dir.pwd, appliance_dir)
22
+ end
23
+
24
+ def manage(local_source)
25
+ self.class.class_variable_set('@@appliance_directory', Dir.pwd)
26
+ if appliance_directory_valid?(Dir.pwd)
27
+ file= File.join(Dir.pwd, local_source)
28
+ self.class.class_variable_set('@@local_source', file) if File.exist?(file)
29
+ end
30
+ end
31
+
32
+ private
33
+
34
+ def appliance_directory_valid?(dir)
35
+ config_file= File.join(dir, '.sscrc')
36
+ File.exist?(config_file) && File.read(config_file).match(/appliance_id:\ *\d+/)
37
+ end
38
+
39
+ end
40
+
41
+ module InstanceMethods
42
+ include Thor::Actions
43
+
44
+ # Save data to local storage file
45
+ # @param [String] section The section of the document that is to be saved
46
+ # @param [Array] list The data in Array format which will be merged with existing data
47
+ def save(section, list)
48
+ safe_get_source_file do |source|
49
+ parsed_file= YAML::load(File.read(source))
50
+ # YAML::load returns false if file is empty
51
+ parsed_file= {} unless parsed_file
52
+ final_list= list
53
+ if parsed_file[section]
54
+ current_list= parsed_file[section]
55
+ final_list= current_list | final_list
56
+ end
57
+ parsed_file[section]= final_list
58
+ File.open(source, 'w') {|f| f.write parsed_file.to_yaml}
59
+ end
60
+ end
61
+
62
+ # Reads data from the local storage file
63
+ # @param [String] section (optional) This is the top-level section
64
+ # of the storage file that is to be read. It can be left blank to
65
+ # return all sections of the file
66
+ # @return [String] Either the whole file of the specified section
67
+ def read(section = nil)
68
+ safe_get_source_file do |source|
69
+ if section
70
+ parsed_file= YAML::load(File.read(source))
71
+ parsed_file[section]
72
+ else
73
+ File.read(source)
74
+ end
75
+ end
76
+ end
77
+
78
+ private
79
+
80
+
81
+ # Wrapper to check existence of source file and other sanity checks
82
+ # It takes a block with one argument - the path of the source file
83
+ def safe_get_source_file
84
+ source= self.class.class_variable_get('@@local_source')
85
+ source= File.join(Dir.pwd, source)
86
+ if File.exist?(source)
87
+ yield source
88
+ else
89
+ raise "Couldn't find the local source file" unless options.remote?
90
+ end
91
+ end
92
+
93
+ def find_file_id(file_name)
94
+ file_list= File.join(self.class.class_variable_get('@@local_source'), '.file_list')
95
+ parsed_file= YAML::load(File.read(file_list))
96
+ if parsed_file["list"]
97
+ files= parsed_file["list"].select{|i| i.keys[0] == file_name}
98
+ if files.length < 1
99
+ raise ArgumentError, "file not found"
100
+ else
101
+ files[0][file_name]["id"]
102
+ end
103
+ else
104
+ raise ArgumentError, "file not found"
105
+ end
106
+ end
107
+
108
+ def full_local_file_path(file)
109
+ full_path= File.join(self.class.class_variable_get('@@local_source'), file)
110
+ end
111
+
112
+ def show_file(file)
113
+ full_path= full_local_file_path(file)
114
+ if File.exist?(full_path)
115
+ File.read(full_path)
116
+ else
117
+ raise ArgumentError, "file not found"
118
+ end
119
+ end
120
+
121
+ def find_diff(remote, local)
122
+ `diff #{remote} #{local}`
123
+ end
124
+
125
+ def initiate_file(file_dir, file_name, id)
126
+ source_file= File.join(file_dir, file_name)
127
+ destination_file= full_local_file_path(file_name)
128
+ file_list= File.join(self.class.class_variable_get('@@local_source'), '.file_list')
129
+ if File.exist?(source_file)
130
+ FileUtils.cp(source_file, destination_file)
131
+ parsed_file= YAML::load(File.read(file_list)) || {}
132
+ File.open(file_list, 'w') do |f|
133
+ if id # if the file has been uploaded
134
+ parsed_file['list']= [] unless parsed_file['list']
135
+ parsed_file['list'] |= [{file_name => {
136
+ "id" => id,
137
+ "path" => file_dir}}]
138
+ else
139
+ parsed_file['add']= [] unless parsed_file['add']
140
+
141
+ parsed_file['add'] |= [{file_name => {
142
+ "path" => file_dir}}]
143
+ end
144
+ f.write(parsed_file.to_yaml)
145
+ end
146
+ destination_file
147
+ else
148
+ raise ArgumentError, "File does not exist"
149
+ end
150
+ end
151
+
152
+ def list_local_files
153
+ source= self.class.class_variable_get('@@local_source')
154
+ parsed_file= YAML::load File.read(File.join(source, '.file_list'))
155
+ parsed_file = {} unless parsed_file
156
+ parsed_file["list"]
157
+ end
158
+
159
+ def parse_file_list
160
+ source= self.class.class_variable_get('@@local_source')
161
+ file_list= File.read(File.join(source, '.file_list'))
162
+ YAML::load(file_list)
163
+ end
164
+
165
+ def write_to_file(file, data)
166
+ written= []
167
+ existing_lines= file.readlines.collect{|i| i.strip}
168
+ file.write("\n") if existing_lines.last != '' and existing_lines != []
169
+ data.each do |line|
170
+ unless existing_lines.include?( line )
171
+ file.write(line+"\n")
172
+ written << line
173
+ end
174
+ end
175
+ end
176
+
177
+ def file_list_empty?
178
+ safe_get_source_file do |source|
179
+ !YAML::load File.read(File.join(source, '.file_list'))
180
+ end
181
+ end
182
+
183
+ # Checks if the local source file has a list
184
+ # @return [Boolean] true if there is no list
185
+ def no_local_list?
186
+ safe_get_source_file do |source|
187
+ list= YAML::load(File.read source)
188
+ !list || list == nil || list == {} || list == []
189
+ end
190
+ end
191
+
192
+ end
193
+ end
194
+ end
@@ -0,0 +1,33 @@
1
+ require 'studio_api'
2
+
3
+ $LOAD_PATH.unshift(File.dirname(__FILE__))
4
+
5
+ module SSC::Handler; end
6
+
7
+ require 'helper'
8
+
9
+ module SSC
10
+ module Handler
11
+ class Base < Thor
12
+
13
+ include Helper
14
+ include DirectoryManager
15
+
16
+ API_URL= 'https://susestudio.com/api/v1/user'
17
+
18
+ def initialize(*args)
19
+ super
20
+
21
+ optional_connection_options= filter_options(options, [:timeout, :proxy])
22
+ connect(options.username, options.password, optional_connection_options)
23
+ @not_local= true if options.remote?
24
+ end
25
+ end
26
+ end
27
+ end
28
+
29
+ require 'appliance'
30
+ require 'repository'
31
+ require 'package'
32
+ require 'template'
33
+ require 'file'
@@ -0,0 +1,74 @@
1
+ module SSC
2
+ module Handler
3
+ class Appliance < Base
4
+
5
+ desc "appliance create APPLIANCE_NAME", "Create an appliance"
6
+ require_authorization
7
+ method_option :source_id, :type => :numeric, :required => true
8
+ method_option :arch, :type => :string
9
+ def create(appliance_name)
10
+ appliance_dir= File.join('.', appliance_name)
11
+ params= {:name => appliance_name}
12
+ params.merge!(:arch => options.arch) if options.arch
13
+ appliance= StudioApi::Appliance.clone(options.source_id, params)
14
+ appliance_dir= self.class.create_appliance_directory(appliance_dir, options.username, options.password, appliance.id)
15
+ say_array ["Created: ", appliance_dir,
16
+ File.join(appliance_dir, 'files'),
17
+ File.join(appliance_dir, 'repositories'),
18
+ File.join(appliance_dir, 'software') ]
19
+ end
20
+
21
+ desc "appliance list", "list all appliances"
22
+ require_authorization
23
+ def list
24
+ appliances= StudioApi::Appliance.find(:all)
25
+ print_table appliances.collect{|i| [i.id, i.name]}
26
+ end
27
+
28
+ desc "appliance info", "show details of a specific appliance"
29
+ require_appliance_id
30
+ def info
31
+ appliance= StudioApi::Appliance.find(options.appliance_id)
32
+ say_array ["#{appliance.id}: #{appliance.name}",
33
+ "Parent: ( #{appliance.parent.id} ) #{appliance.parent.name}",
34
+ "Download Url: #{download_url(appliance)}"]
35
+ end
36
+
37
+ desc "appliance destroy", "destroy the current appliance (within appliance directory only)"
38
+ require_appliance_id
39
+ def destroy
40
+ if appliance.destroy.code_type == Net::HTTPOK
41
+ say 'Appliance Successfully Destroyed', :red
42
+ else
43
+ say_array ['There was a problem with destroying the appliance.',
44
+ 'Make sure that you\'re in the appliance directory OR',
45
+ 'Have provided the --appliance_id option']
46
+ end
47
+ end
48
+
49
+ desc "appliance status", "gives status of the appliance"
50
+ require_appliance_id
51
+ def status
52
+ require_appliance do |appliance|
53
+ response= appliance.status
54
+ case response.state
55
+ when 'error'
56
+ say "Error: #{response.issues.issue.text}"
57
+ when 'ok'
58
+ say "Appliance Ok"
59
+ end
60
+ end
61
+ end
62
+
63
+ private
64
+
65
+ def download_url(appliance)
66
+ if appliance.builds.empty?
67
+ "No Build Yet"
68
+ else
69
+ appliance.builds.last.download_url
70
+ end
71
+ end
72
+ end
73
+ end
74
+ end