cloudstack-cli 0.0.1 → 0.0.2

Sign up to get free protection for your applications and to get access to all the features.
data/.gitignore CHANGED
@@ -3,3 +3,4 @@ results.html
3
3
  config/cloudstack.yml
4
4
  pkg
5
5
  html
6
+ *.gem
data/README.md CHANGED
@@ -16,6 +16,20 @@ Or install it yourself as:
16
16
 
17
17
  $ gem install cloudstack-cli
18
18
 
19
+ ## Setup
20
+
21
+ Create the initial configuration:
22
+
23
+ cs setup
24
+
25
+ cloudstack-cli expects to find a configuartion file with the API URL and your CloudStack credentials in your home directory named .cloudstack-cli.yml. If the file is located elsewhere you can specify the loaction using the --config option.
26
+
27
+ Example content of the configuration file:
28
+
29
+ :url: "https://my-cloudstack-server/client/api/"
30
+ :api_key: "cloudstack-api-key"
31
+ :secret_key: "cloudstack-api-secret"
32
+
19
33
  ## Usage
20
34
 
21
35
  See the help screen
@@ -6,18 +6,20 @@ require 'cloudstack-cli/version'
6
6
  Gem::Specification.new do |gem|
7
7
  gem.name = "cloudstack-cli"
8
8
  gem.version = CloudstackCli::VERSION
9
- gem.authors = ["niwo"]
9
+ gem.authors = ["Nik Wolfgramm"]
10
10
  gem.email = ["nik.wolfgramm@gmail.com"]
11
- gem.description = %q{Cloudstack CLI gives command line access to the CloudStack API commands.}
12
- gem.summary = %q{cloudstack-cli}
13
- gem.homepage = ""
11
+ gem.description = %q{cloudstack-cli is a CloudStack API client written in Ruby.}
12
+ gem.summary = %q{cloudstack-cli CloudStack API client}
13
+ gem.homepage = "https://bitbucket.org/swisstxt/cloudstack-cli"
14
14
 
15
15
  gem.files = `git ls-files`.split($/)
16
- gem.executables = gem.files.grep(%r{^bin/}).map{ |f| File.basename(f) }
16
+ gem.executables = ['cs']
17
17
  gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
18
18
  gem.require_paths = ["lib"]
19
+
19
20
  gem.add_development_dependency('rdoc')
20
21
  gem.add_development_dependency('rake', '~> 10.0.4')
22
+
21
23
  gem.add_dependency('thor', '~> 0.18.1')
22
24
  gem.add_dependency('net-ssh', '~> 2.6.7')
23
25
  gem.add_dependency('rainbow', '~> 1.1.4')
@@ -1,11 +1,40 @@
1
1
  module CloudstackCli
2
2
  class Cli < Thor
3
- class_option :config
3
+ include Thor::Actions
4
+
5
+ class_option :config, default: File.join(Dir.home, '.cloudstack-cli.yml'), aliases: '-c'
4
6
  class_option :verbose, type: :boolean
5
7
 
8
+ desc "setup", "initial setup of the Cloudstack connection"
9
+ option :url
10
+ option :api_key
11
+ option :secret_key
12
+ def setup(file = options[:config])
13
+ config = {}
14
+ unless options[:url]
15
+ say "What's the URL of your Cloudstack API?", :blue
16
+ say "Example: https://my-cloudstack-server/client/api/", :blue
17
+ config[:url] = ask("URL:", :magenta)
18
+ end
19
+
20
+ unless options[:api_key]
21
+ config[:api_key] = ask("API Key:", :magenta)
22
+ end
23
+
24
+ unless options[:secret_key]
25
+ config[:secret_key] = ask("Secret Key:", :magenta)
26
+ end
27
+
28
+ if File.exists? file
29
+ say "Warning: #{file} already exists.", :red
30
+ exit unless yes?("Overwrite [y/N]", :red)
31
+ end
32
+ File.open(file, 'w+') {|f| f.write(config.to_yaml) }
33
+ end
34
+
6
35
  desc "command COMMAND [arg1=val1 arg2=val2...]", "run a custom api command"
7
36
  def command(command, *args)
8
- client = CloudstackCli::Helper.new
37
+ client = CloudstackCli::Helper.new(options[:config])
9
38
  params = {'command' => command}
10
39
  args.each do |arg|
11
40
  arg = arg.split('=')
@@ -2,7 +2,7 @@ class Account < Thor
2
2
 
3
3
  desc 'list [NAME]', 'list accounts'
4
4
  def list(name = nil)
5
- cs_cli = CloudstackCli::Helper.new
5
+ cs_cli = CloudstackCli::Helper.new(options[:config])
6
6
  accounts = cs_cli.list_accounts(name)
7
7
  if accounts.size < 1
8
8
  puts "No accounts found"
@@ -2,7 +2,7 @@ class Domain < Thor
2
2
 
3
3
  desc 'list [NAME]', 'list domains'
4
4
  def list(name = nil)
5
- cs_cli = CloudstackCli::Helper.new
5
+ cs_cli = CloudstackCli::Helper.new(options[:config])
6
6
  domains = cs_cli.domains(name)
7
7
  if domains.size < 1
8
8
  puts "No domains found"
@@ -2,7 +2,7 @@ class Lb < Thor
2
2
  desc "list", "list load balancer rules"
3
3
  option :project
4
4
  def list
5
- cs_cli = CloudstackCli::Helper.new
5
+ cs_cli = CloudstackCli::Helper.new(options[:config])
6
6
  if options[:project]
7
7
  project = cs_cli.projects.select { |p| p['name'] == options[:project] }.first
8
8
  exit_now! "Project '#{options[:project]}' not found" unless project
@@ -24,7 +24,7 @@ class Lb < Thor
24
24
  option :public_port, :required => true
25
25
  option :private_port
26
26
  def create(name)
27
- cs_cli = CloudstackCli::Helper.new
27
+ cs_cli = CloudstackCli::Helper.new(options[:config])
28
28
  if options[:project]
29
29
  project = cs_cli.projects.select { |p| p['name'] == options[:project] }.first
30
30
  exit_now! "Project '#{options[:project]}' not found" unless project
@@ -44,7 +44,7 @@ class Lb < Thor
44
44
  option :project
45
45
  option :servers, required: true, type: :array, description: 'server names'
46
46
  def add(name)
47
- cs_cli = CloudstackCli::Helper.new
47
+ cs_cli = CloudstackCli::Helper.new(options[:config])
48
48
  if options[:project]
49
49
  project = cs_cli.projects.select { |p| p['name'] == options[:project] }.first
50
50
  exit_now! "Project '#{options[:project]}' not found" unless project
@@ -11,7 +11,7 @@ class Network < Thor
11
11
  option :project
12
12
  option :physical, type: :boolean
13
13
  def list
14
- cs_cli = CloudstackCli::Helper.new
14
+ cs_cli = CloudstackCli::Helper.new(options[:config])
15
15
  if options[:project]
16
16
  project = cs_cli.projects.select { |p| p['name'] == options[:project] }.first
17
17
  raise "Project '#{options[:project]}' not found" unless project
@@ -19,7 +19,6 @@ class Network < Thor
19
19
 
20
20
  if options[:physical]
21
21
  networks = cs_cli.physical_networks
22
-
23
22
  if networks.size < 1
24
23
  puts "No networks found"
25
24
  else
@@ -42,7 +41,6 @@ class Network < Thor
42
41
  end
43
42
  else
44
43
  networks = cs_cli.networks(project ? project['id'] : -1)
45
-
46
44
  if networks.size < 1
47
45
  puts "No networks found"
48
46
  else
@@ -4,7 +4,7 @@ class Offering < Thor
4
4
  desc 'list', 'list offerings by type [compute|network|storage]'
5
5
  option :domain
6
6
  def list(type='compute')
7
- cs_cli = CloudstackCli::Helper.new
7
+ cs_cli = CloudstackCli::Helper.new(options[:config])
8
8
  offerings = cs_cli.server_offerings(options[:domain])
9
9
 
10
10
  offerings.group_by{|o| o["domain"]}.each_value do |offers|
@@ -47,20 +47,20 @@ class Offering < Thor
47
47
  option :tags
48
48
  def create(name)
49
49
  options[:name] = name
50
- cs_cli = CloudstackCli::Helper.new
50
+ cs_cli = CloudstackCli::Helper.new(options[:config])
51
51
  puts "OK" if cs_cli.create_offering(options)
52
52
  end
53
53
 
54
54
  desc 'delete ID', 'delete offering'
55
55
  def delete(id)
56
- cs_cli = CloudstackCli::Helper.new
56
+ cs_cli = CloudstackCli::Helper.new(options[:config])
57
57
  puts "OK" if cs_cli.delete_offering(id)
58
58
  end
59
59
 
60
60
 
61
61
  desc 'sort', 'sort by cpu and memory grouped by domain'
62
62
  def sort
63
- cs_cli = CloudstackCli::Helper.new
63
+ cs_cli = CloudstackCli::Helper.new(options[:config])
64
64
  offerings = cs_cli.server_offerings(options[:domain])
65
65
  sortkey = -1
66
66
  offerings.group_by{|o| o["domain"]}.each_value do |offers|
@@ -2,7 +2,7 @@ class Project < Thor
2
2
 
3
3
  desc "list", "list projects"
4
4
  def list
5
- cs_cli = CloudstackCli::Helper.new
5
+ cs_cli = CloudstackCli::Helper.new(options[:config])
6
6
  projects = cs_cli.projects
7
7
  if projects.size < 1
8
8
  puts "No projects found"
@@ -2,7 +2,7 @@ class Publicip < Thor
2
2
 
3
3
  desc "remove ID", "remove public IP address"
4
4
  def remove(id)
5
- cs_cli = CloudstackCli::Helper.new
5
+ cs_cli = CloudstackCli::Helper.new(options[:config])
6
6
  puts "OK" if cs_cli.remove_publicip(id)
7
7
  end
8
8
 
@@ -1,15 +1,18 @@
1
1
  class Router < Thor
2
+ include Thor::Actions
2
3
  include CommandLineReporter
3
4
 
4
5
  desc "list", "list virtual routers"
5
6
  option :project
6
7
  option :account
8
+ option :zone
7
9
  option :status, desc: "Running or Stopped"
8
10
  option :redundant_state, desc: "MASTER, BACKUP or UNKNOWN"
9
11
  option :listall, type: :boolean
10
12
  option :text, type: :boolean, desc: "text output (only the instance name)"
13
+ option :command, desc: "command to execute for each router: START or STOP"
11
14
  def list
12
- cs_cli = CloudstackCli::Helper.new
15
+ cs_cli = CloudstackCli::Helper.new(options[:config])
13
16
  if options[:project]
14
17
  project = cs_cli.projects.select { |p| p['name'] == options[:project] }.first
15
18
  raise "Project '#{options[:project]}' not found" unless project
@@ -21,6 +24,7 @@ class Router < Thor
21
24
  account: options[:account],
22
25
  projectid: projectid,
23
26
  status: options[:status],
27
+ zone: options[:zone]
24
28
  },
25
29
  options[:redundant_state]
26
30
  )
@@ -33,7 +37,8 @@ class Router < Thor
33
37
  {
34
38
  account: options[:account],
35
39
  projectid: project['id'],
36
- status: options[:status]
40
+ status: options[:status],
41
+ zone: options[:zone]
37
42
  },
38
43
  options[:redundant_state]
39
44
  )
@@ -70,24 +75,44 @@ class Router < Thor
70
75
  end
71
76
  end
72
77
 
78
+ if options[:command]
79
+ case options[:command].downcase
80
+ when "start"
81
+ exit unless yes?("Start the routers above? [y/N]:", :magenta)
82
+ routers.each do |router|
83
+ say "Start router #{router['name']}"
84
+ cs_cli.start_router router['id']
85
+ end
86
+ when "stop"
87
+ exit unless yes?("Stop the routers above? [y/N]:", :magenta)
88
+ routers.each do |router|
89
+ say "Stop router #{router['name']}"
90
+ cs_cli.stop_router router['id']
91
+ end
92
+ else
93
+ say "Command #{options[:command]} not supported", :red
94
+ exit
95
+ end
96
+ end
73
97
  end
74
98
 
75
- desc "stop NAME", "stop virtual router"
76
- option :project
77
-
78
- def stopall
79
-
99
+ desc "stop ID", "stop virtual router"
100
+ def stop(id)
101
+ exit unless yes?("Stop the router with ID #{id}?", :magenta)
102
+ cs_cli = CloudstackCli::Helper.new(options[:config])
103
+ cs_cli.stop_router id
80
104
  end
81
105
 
82
- desc "start NAME", "start virtual router"
83
- option :project
84
- def start
85
-
106
+ desc "start ID", "start virtual router"
107
+ def start(id)
108
+ exit unless yes?("Start the router with ID #{id}?", :magenta)
109
+ cs_cli = CloudstackCli::Helper.new(options[:config])
110
+ cs_cli.start_router id
86
111
  end
87
112
 
88
113
  desc "destroy ID", "destroy virtual router"
89
114
  def destroy(id)
90
- cs_cli = CloudstackCli::Helper.new
115
+ cs_cli = CloudstackCli::Helper.new(options[:config])
91
116
  puts "OK" if cs_cli.destroy_router(name)
92
117
  end
93
118
 
@@ -6,7 +6,7 @@ class Server < Thor
6
6
  option :project
7
7
  option :account
8
8
  def list
9
- cs_cli = CloudstackCli::Helper.new
9
+ cs_cli = CloudstackCli::Helper.new(options[:config])
10
10
  if options[:project]
11
11
  project = cs_cli.projects.select { |p| p['name'] == options[:project] }.first
12
12
  exit_now! "Project '#{options[:project]}' not found" unless project
@@ -3,7 +3,7 @@ class Template < Thor
3
3
  desc 'list', 'list templates by type [featured|self|self-executable|executable|community]'
4
4
  option :project
5
5
  def list(type='featured')
6
- cs_cli = CloudstackCli::Helper.new
6
+ cs_cli = CloudstackCli::Helper.new(options[:config])
7
7
 
8
8
  if options[:project]
9
9
  project = cs_cli.projects.select { |p| p['name'] == options[:project] }.first
@@ -2,7 +2,7 @@ class Volume < Thor
2
2
  desc "list", "list networks"
3
3
  option :project
4
4
  def list
5
- cs_cli = CloudstackCli::Helper.new
5
+ cs_cli = CloudstackCli::Helper.new(options[:config])
6
6
  if options[:project]
7
7
  project = cs_cli.projects.select { |p| p['name'] == options[:project] }.first
8
8
  raise "Project '#{options[:project]}' not found" unless project
@@ -2,7 +2,7 @@ class Zone < Thor
2
2
 
3
3
  desc "list", "list zones"
4
4
  def list
5
- cs_cli = CloudstackCli::Helper.new
5
+ cs_cli = CloudstackCli::Helper.new(options[:config])
6
6
  zones = cs_cli.zones
7
7
  if zones.size < 1
8
8
  puts "No projects found"
@@ -4,11 +4,12 @@ module CloudstackCli
4
4
 
5
5
  attr_reader :cs
6
6
 
7
- def initialize
7
+ def initialize(config_file)
8
+ @config_file = config_file
8
9
  @cs = CloudstackClient::Connection.new(
9
- options[:cloudstack_url],
10
- options[:cloudstack_api_key],
11
- options[:cloudstack_secret_key]
10
+ options[:url],
11
+ options[:api_key],
12
+ options[:secret_key]
12
13
  )
13
14
  end
14
15
 
@@ -175,8 +176,16 @@ module CloudstackCli
175
176
  @cs.destroy_router(id)
176
177
  end
177
178
 
179
+ def start_router(id)
180
+ @cs.start_router(id)
181
+ end
182
+
183
+ def stop_router(id)
184
+ @cs.stop_router(id)
185
+ end
186
+
178
187
  def options
179
- @options ||= CloudstackClient::ConnectionHelper.load_configuration()
188
+ @options ||= CloudstackClient::ConnectionHelper.load_configuration(@config_file)
180
189
  end
181
190
 
182
191
  def print_options(options, attr = 'name')
@@ -1,3 +1,3 @@
1
1
  module CloudstackCli
2
- VERSION = "0.0.1"
2
+ VERSION = "0.0.2"
3
3
  end
@@ -728,7 +728,14 @@ module CloudstackClient
728
728
  'listall' => 'true',
729
729
  'isrecursive' => 'true'
730
730
  }
731
- params['zone'] = args[:zone] if args[:zone]
731
+ if args[:zone]
732
+ zone = get_zone(args[:zone])
733
+ unless zone
734
+ puts "Error: Zone #{args[:zone]} not found"
735
+ exit 1
736
+ end
737
+ params['zoneid'] = zone['id']
738
+ end
732
739
  params['projectid'] = args[:projectid] if args[:projectid]
733
740
  params['state'] = args[:status] if args[:status]
734
741
  params['name'] = args[:name] if args[:name]
@@ -754,6 +761,30 @@ module CloudstackClient
754
761
  json['router'].first
755
762
  end
756
763
 
764
+ ##
765
+ # Start virtual router.
766
+
767
+ def start_router(id)
768
+ params = {
769
+ 'command' => 'startRouter',
770
+ 'id' => id
771
+ }
772
+
773
+ json = send_async_request(params)
774
+ end
775
+
776
+ ##
777
+ # Stop virtual router.
778
+
779
+ def stop_router(id)
780
+ params = {
781
+ 'command' => 'stopRouter',
782
+ 'id' => id
783
+ }
784
+
785
+ json = send_async_request(params)
786
+ end
787
+
757
788
  ##
758
789
  # Lists accounts.
759
790
 
@@ -1,10 +1,11 @@
1
1
  module CloudstackClient
2
2
  class ConnectionHelper
3
- def self.load_configuration(config_file = File.join(File.dirname(__FILE__), '..', '..', 'config', 'cloudstack.yml'))
3
+ def self.load_configuration(config_file)
4
4
  begin
5
5
  return YAML::load(IO.read(config_file))
6
6
  rescue Exception => e
7
- puts "Unable to load '#{config_file}' : #{e}".color(:red)
7
+ $stderr.puts "Can't find the config file '#{config_file}'"
8
+ $stderr.puts "Please see https://bitbucket.org/swisstxt/cloudstack-cli under 'Setup'"
8
9
  exit
9
10
  end
10
11
  end
metadata CHANGED
@@ -1,15 +1,15 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: cloudstack-cli
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.1
4
+ version: 0.0.2
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
8
- - niwo
8
+ - Nik Wolfgramm
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2013-07-19 00:00:00.000000000 Z
12
+ date: 2013-07-22 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: rdoc
@@ -107,7 +107,7 @@ dependencies:
107
107
  - - ~>
108
108
  - !ruby/object:Gem::Version
109
109
  version: 3.2.1
110
- description: Cloudstack CLI gives command line access to the CloudStack API commands.
110
+ description: cloudstack-cli is a CloudStack API client written in Ruby.
111
111
  email:
112
112
  - nik.wolfgramm@gmail.com
113
113
  executables:
@@ -144,7 +144,7 @@ files:
144
144
  - lib/cloudstack-client/ssh_command.rb
145
145
  - lib/cloudstack_cli.rb
146
146
  - lib/cloudstack_client.rb
147
- homepage: ''
147
+ homepage: https://bitbucket.org/swisstxt/cloudstack-cli
148
148
  licenses: []
149
149
  post_install_message:
150
150
  rdoc_options: []
@@ -167,5 +167,5 @@ rubyforge_project:
167
167
  rubygems_version: 1.8.23
168
168
  signing_key:
169
169
  specification_version: 3
170
- summary: cloudstack-cli
170
+ summary: cloudstack-cli CloudStack API client
171
171
  test_files: []