rightscale-cli 0.5.6 → 0.6.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -17,5 +17,4 @@
17
17
  require 'rightscale_cli/version'
18
18
  require 'rightscale_cli/config'
19
19
  require 'rightscale_cli/monkey_patches/client_attributes'
20
- #require 'rightscale_cli/logger'
21
20
  require 'rightscale_cli/rightscale_cli'
@@ -20,55 +20,65 @@ require 'rightscale_cli/logger'
20
20
  require 'ask_pass'
21
21
 
22
22
  class RightScaleCLI
23
+ # Represents a RightScale CLI Client
23
24
  class Client
24
25
  attr_accessor :client
25
26
  attr_accessor :render
26
-
27
+
27
28
  def initialize(options)
28
29
  config = RightScaleCLI::Config.new.directives
29
30
  config[:account_id] = options['account'] if options[:account]
30
31
  config[:email] = options['user'] if options[:user]
31
32
  config[:api_version] = options['api'] if options[:api]
33
+ config[:timeout] = nil
32
34
 
33
- if options['password'] || (!config[:password] && !config[:password_base64])
35
+ if options['password'] || \
36
+ (!config[:password] && \
37
+ !config[:password_base64] &&
38
+ !config[:access_token])
39
+ # fallback to asking for user password
34
40
  config[:password] = ask_pass
35
- config[:password_base64] = nil # set this to nil so it is not used by precedence
41
+ # set this to nil so it is not used by precedence
42
+ config[:password_base64] = nil
36
43
  end
37
44
 
38
45
  @options = options
39
46
  @client = RightApi::Client.new(config)
40
- @logger = RightScaleCLI::Logger.new()
47
+ @logger = RightScaleCLI::Logger.new
41
48
  end
42
49
 
43
50
  def get(resource)
44
51
  result = []
45
- @client.send(resource).index.each { |record|
46
- result.push(record.raw)
47
- }
48
- return result
52
+ @client.send(resource).index.each { |record| result.push(record.raw) }
53
+ result
49
54
  end
50
55
 
51
56
  def show(resource, resource_id, *args)
52
57
  if args.count > 0
53
58
  result = []
54
- records = @client.send(resource).index({ :id => resource_id }).show.send(args[0]).index
55
- records.each { |record|
56
- result.push(record.raw)
57
- }
59
+ records = @client.send(resource).index(id: resource_id)
60
+ .show.send(args[0]).index
61
+ records.each { |record| result.push(record.raw) }
58
62
  @logger.info("Resource count: #{result.count}.")
59
63
  else
60
- result = @client.send(resource).index({ :id => resource_id }).show.raw
64
+ result = @client.send(resource).index(id: resource_id).show.raw
61
65
  end
62
- return result
66
+ result
63
67
  end
64
68
 
65
69
  def create(resource, params)
66
- resource = @client.send("#{resource}s").create(resource => params)
70
+ if params[:cloud]
71
+ resource = @client.clouds(id: params[:cloud]).show.send("#{resource}s")
72
+ .create(params)
73
+ else
74
+ resource = @client.send("#{resource}s").create(params)
75
+ end
67
76
  @logger.info("Created #{resource.href}.")
77
+ resource.href
68
78
  end
69
79
 
70
80
  def destroy(resource, resource_id)
71
- resource = @client.send("#{resource}s").index({ :id => resource_id })
81
+ resource = @client.send("#{resource}s").index(id: resource_id)
72
82
  resource.destroy
73
83
  @logger.info("Deleted #{resource.href}.")
74
84
  end
@@ -19,66 +19,66 @@ require 'rightscale_cli/client'
19
19
  require 'rightscale_cli/logger'
20
20
 
21
21
  class RightScaleCLI
22
+ # Represents Clouds
22
23
  class Clouds < Thor
23
24
  namespace :clouds
24
25
 
25
26
  def initialize(*args)
26
27
  super
27
28
  @client = RightScaleCLI::Client.new(options)
28
- @logger = RightScaleCLI::Logger.new()
29
+ @logger = RightScaleCLI::Logger.new
29
30
  end
30
31
 
31
32
  # include render options
32
33
  eval(IO.read("#{File.dirname(File.expand_path(__FILE__))}/render_options.rb"), binding)
33
34
 
34
- desc "list", "Lists all clouds."
35
- option :basic, :type => :boolean, :required => false
36
- def list()
35
+ desc 'list', 'lists all clouds connected to the account'
36
+ option :basic, type: :boolean, required: false
37
+ def list
37
38
  clouds = @client.get('clouds')
38
39
 
39
40
  if options[:basic]
40
- basic_fields = [ 'display_name', 'cloud_type', 'name' ]
41
+ basic_fields = %w('display_name', 'cloud_type', 'name')
41
42
  basic_clouds = []
42
- @client.get('clouds').each { |cloud|
43
- cloud_id = cloud['links'].select { |link| link['rel'] == 'instances' }.first['href'].split('/')[3]
44
- c = cloud.select{|x| basic_fields.include?(x)}
43
+ @client.get('clouds').each do |cloud|
44
+ cloud_id = cloud['links'].select { |link| link['rel'] == 'instances' }
45
+ .first['href'].split('/')[3]
46
+ c = cloud.select { |x| basic_fields.include?(x) }
45
47
  c['cloud_id'] = cloud_id.to_i
46
48
  basic_clouds.push(c)
47
- }
49
+ end
48
50
  clouds = basic_clouds
49
51
  end
50
52
 
51
53
  @client.render(clouds, 'clouds')
52
54
  end
53
55
 
54
- desc "show", "Shows a cloud."
56
+ desc 'show', 'shows a cloud'
55
57
  def show(cloud_id)
56
58
  @client.render(@client.show('clouds', cloud_id), 'cloud')
57
59
  end
58
60
 
59
- desc "search", "Searches for clouds by cloud type, name, description."
60
- option :name, :type => :string, :required => false
61
- option :cloud_type, :type => :string, :required => false
62
- option :description, :type => :string, :required => false
63
- def search()
61
+ desc 'search', 'searches for clouds by cloud type, name, description'
62
+ option :name, type: :string, required: false
63
+ option :cloud_type, type: :string, required: false
64
+ option :description, type: :string, required: false
65
+ def search
64
66
  filter = []
65
67
  filter.push("name==#{options[:name]}") if options[:name]
66
68
  filter.push("cloud_type==#{options[:cloud_type]}") if options[:cloud_type]
67
69
  filter.push("description==#{options[:cloud]}") if options[:description]
68
70
 
69
- @logger.info "Searching for clouds!"
71
+ @logger.info 'Searching for clouds!'
70
72
 
71
73
  puts "filter: #{filter}" if options[:debug]
72
-
73
- clouds = []
74
- @client.client.clouds.index(:filter => filter).each { |cloud|
75
- clouds.push(cloud.raw)
76
- }
77
74
 
75
+ clouds = []
76
+ @client.client.clouds.index(filter: filter)
77
+ .each { |cloud| clouds.push(cloud.raw) }
78
78
  @client.render(clouds, 'clouds')
79
79
  end
80
80
 
81
- def self.banner(task, namespace = true, subcommand = false)
81
+ def self.banner(task, _namespace = true, subcommand = false)
82
82
  "#{basename} #{task.formatted_usage(self, true, subcommand)}"
83
83
  end
84
84
  end
@@ -1,5 +1,5 @@
1
1
  # Author:: Chris Fordham (<chris@fordham-nagy.id.au>)
2
- # Copyright:: Copyright (c) 2013 Chris Fordham
2
+ # Copyright:: Copyright (c) 2013-2105 Chris Fordham
3
3
  # License:: Apache License, Version 2.0
4
4
  #
5
5
  # Licensed under the Apache License, Version 2.0 (the "License");
@@ -18,27 +18,32 @@ require 'yaml'
18
18
  require 'fileutils'
19
19
 
20
20
  class RightScaleCLI
21
+ # Represents a RightScale CLI configuration
21
22
  class Config
22
23
  attr_accessor :template_path, :config_home, :config_path, :directives
23
24
 
24
- def initialize(*args)
25
- @template_path = File.join(File.dirname(__FILE__), '..', 'templates', 'right_api_client.yml.erb')
25
+ def initialize(*)
26
+ @template_path = File.join(File.dirname(__FILE__),
27
+ '..', 'templates', 'right_api_client.yml.erb')
26
28
  @config_home = File.join(ENV['HOME'], '.rightscale')
27
29
  @config_path = File.join(@config_home, 'right_api_client.yml')
28
30
 
29
- Dir.mkdir(@config_home) unless File.exists?(@config_home)
31
+ Dir.mkdir(@config_home) unless File.exist?(@config_home)
30
32
  FileUtils.touch(@config_path)
31
-
33
+
32
34
  # write a fresh file if it does not load/parse
33
35
  unless YAML.load_file(@config_path)
34
36
  @directives = {
35
- :account_id => '',
36
- :email => '',
37
- :password_base64 => '',
38
- :api_url => 'https://us-4.rightscale.com',
39
- :api_version => '1.5'
37
+ account_id: '',
38
+ email: nil,
39
+ password_base64: '',
40
+ access_token: '',
41
+ api_url: 'https://us-4.rightscale.com',
42
+ api_version: '1.5'
40
43
  }
41
- File.open(@config_path, 'w') {|f| f.write(ERB.new(IO.read(@template_path)).result(binding)) }
44
+ File.open(@config_path, 'w') do |f|
45
+ f.write(ERB.new(IO.read(@template_path)).result(binding))
46
+ end
42
47
  end
43
48
 
44
49
  # load/reload the directives from the file
@@ -20,6 +20,7 @@ require 'rightscale_cli/config'
20
20
  require 'rightscale_cli/logger'
21
21
  require 'rightscale_cli/client'
22
22
  require 'ask_pass'
23
+ require 'yesno'
23
24
  require 'erb'
24
25
  require "base64"
25
26
 
@@ -58,6 +59,18 @@ class RightScaleCLI
58
59
  update_conf
59
60
  end
60
61
 
62
+ desc "oauth", "Configure the RightScale OAuth access token for the client."
63
+ def oauth()
64
+ @directives.merge!( { :access_token => ask("RightScale API access token:") })
65
+ update_conf
66
+ end
67
+
68
+ desc 'refresh', 'configure the RightScale refresh token for the client'
69
+ def refresh()
70
+ @directives.merge!( { :refresh_token => ask('RightScale API refresh token:') })
71
+ update_conf
72
+ end
73
+
61
74
  desc "api", "Configure the RightScale API version used by the client."
62
75
  def api()
63
76
  @directives.merge!( { :api_version => ask("RightScale API version (e.g. 1.5):") })
@@ -66,7 +79,8 @@ class RightScaleCLI
66
79
 
67
80
  desc "shard", "Configure the RightScale shard used by the client."
68
81
  def shard()
69
- @directives.merge!( { :api_url => "https://#{ask("RightScale shard (e.g. us-4.rightscale.com):")}" })
82
+ shard = ask("RightScale shard (e.g. us-4.rightscale.com):")
83
+ @directives.merge!( { :api_url => "https://#{shard}", :token_endpoint => "https://#{shard}/api/oauth2" })
70
84
  update_conf
71
85
  end
72
86
 
@@ -81,9 +95,18 @@ class RightScaleCLI
81
95
  account
82
96
  user
83
97
  password
98
+ # do not ask for the api access token as we'll generate this from the refresh token
99
+ # oauth
100
+ refresh
84
101
  shard
85
102
  api
86
103
  puts 'Configuration saved.'
104
+ if @directives[:refresh_token]
105
+ puts 'Refresh API token now? (y/n):'
106
+ if yesno
107
+ system 'rs refresh token'
108
+ end
109
+ end
87
110
  end
88
111
 
89
112
  #default_task :all
@@ -18,44 +18,61 @@ require 'thor'
18
18
  require 'yaml'
19
19
  require 'rightscale_cli/client'
20
20
  require 'rightscale_cli/logger'
21
+ require 'rightscale_cli/config'
22
+ require 'deployment_cat'
23
+ require 'right_api_client'
21
24
 
22
25
  class RightScaleCLI
26
+ # Represents RightScale Deployments
23
27
  class Deployments < Thor
24
28
  namespace :deployments
25
29
 
26
30
  def initialize(*args)
27
31
  super
28
32
  @client = RightScaleCLI::Client.new(options)
29
- @logger = RightScaleCLI::Logger.new()
33
+ @logger = RightScaleCLI::Logger.new
34
+ @config = RightScaleCLI::Config.new.directives
30
35
  end
31
36
 
32
- # include render options
33
- eval(IO.read("#{File.dirname(File.expand_path(__FILE__))}/render_options.rb"), binding)
37
+ class_option :xml,
38
+ type: :boolean,
39
+ default: false,
40
+ aliases: '-X',
41
+ required: false,
42
+ desc: 'returns xml'
43
+ class_option :json,
44
+ type: :boolean,
45
+ default: false,
46
+ aliases: '-J',
47
+ required: false,
48
+ desc: 'returns json'
34
49
 
35
- desc "list", "Lists all deployments."
36
- def list()
50
+ desc 'list', 'Lists all deployments'
51
+ def list
37
52
  @client.render(@client.get('deployments'), 'deployments')
38
53
  end
39
54
 
40
- desc "create", "Creates a deployment."
55
+ desc 'create', 'Creates a deployment'
41
56
  def create(name, description)
42
- @client.create('deployment', { :name => name, :description => description })
57
+ @client.create('deployment', name: name, description: description)
43
58
  end
44
59
 
45
- desc "destroy", "Deletes a deployment."
60
+ desc 'destroy', 'Deletes a deployment'
46
61
  def destroy(deployment_id)
47
62
  @client.destroy('deployment', deployment_id)
48
63
  end
49
64
 
50
- desc "servers", "Lists servers in a deployment."
65
+ desc 'servers', 'Lists servers in a deployment'
51
66
  def servers(deployment)
52
67
  @logger.info("Retrieving all servers in deployment, #{deployment}...")
53
- @client.render(@client.show('deployments', deployment, 'servers'), 'servers')
68
+ @client.render(@client.show('deployments', deployment, 'servers'),
69
+ 'servers')
54
70
  end
55
71
 
56
- desc "terminate", "Terminates all servers in a deployment."
72
+ desc 'terminate', 'Terminates all servers in a deployment'
57
73
  def terminate(deployment_id)
58
- @client.client.deployments.index(:id=> deployment_id).show.servers.index.each do |server|
74
+ @client.client.deployments.index(id: deployment_id)
75
+ .show.servers.index.each do |server|
59
76
  unless server.state == 'inactive'
60
77
  @logger.info "Terminating #{server.href} (state: #{server.state}.)"
61
78
  server.terminate
@@ -63,7 +80,14 @@ class RightScaleCLI
63
80
  end
64
81
  end
65
82
 
66
- def self.banner(task, namespace = true, subcommand = false)
83
+ desc 'export', 'Exports a deployment into a CAT file'
84
+ def export(deployment_id)
85
+ @config[:timeout] = nil
86
+ @client = RightApi::Client.new(@config)
87
+ deployment_to_cat_file @client, deployment_id, nil, nil
88
+ end
89
+
90
+ def self.banner(task, _namespace = true, subcommand = false)
67
91
  "#{basename} #{task.formatted_usage(self, true, subcommand)}"
68
92
  end
69
93
  end
@@ -22,6 +22,17 @@ class RightScaleCLI
22
22
  class Instances < Thor
23
23
  namespace :instances
24
24
 
25
+ def initialize(*args)
26
+ super
27
+ @client = RightScaleCLI::Client.new(options)
28
+ @logger = RightScaleCLI::Logger.new()
29
+ end
30
+
31
+ # include render options
32
+ eval(IO.read(
33
+ "#{File.dirname(File.expand_path(__FILE__))}/render_options.rb"), binding
34
+ )
35
+
25
36
  desc "list", "Lists all instances for a given cloud."
26
37
  option :cloud, :desc => 'The cloud to filter on.', :type => :string, :required => true
27
38
  option :datacenter, :desc => 'The href of the datacenter to filter on', :type => :string, :required => false
@@ -37,9 +48,7 @@ class RightScaleCLI
37
48
  option :server_template, :desc => 'The href of the ServerTemplate to filter on.', :type => :string, :required => false
38
49
  option :state, :desc => 'The state of Instances to filter on.', :type => :string, :required => false
39
50
  def list()
40
- instances = []
41
51
  filter = []
42
-
43
52
  filter.push("datacenter_href==#{options[:datacenter]}") if options[:datacenter]
44
53
  filter.push("deployment_href==#{options[:deployment]}") if options[:deployment]
45
54
  filter.push("name==#{options[:private_ip]}") if options[:name]
@@ -55,7 +64,21 @@ class RightScaleCLI
55
64
 
56
65
  @logger.debug "filter: #{filter}" if options[:debug]
57
66
 
58
- @client.render(@client.clent.clouds(:id => options[:cloud]).show.instances(:filter => filter).index)
67
+ instances = []
68
+ @client.client.clouds(:id => options[:cloud]).show.instances(:filter => filter).index.each do |instance|
69
+ instance_href = instance.href
70
+ instance = instance.raw
71
+ instance['href'] = instance_href
72
+ instances.push(instance)
73
+ end
74
+ @client.render(instances, 'instances')
75
+ end
76
+
77
+ desc "show", "Shows attributes of a single instance."
78
+ option :cloud, :desc => 'The cloud to filter on.', :type => :string, :required => true
79
+ def show(instance_id)
80
+ filter = []
81
+ @client.render(@client.client.clouds(:id => options[:cloud]).show.instances.index(:id => instance_id).show.raw, 'instance')
59
82
  end
60
83
 
61
84
  desc "run-exec", "Runs a chef recipe or rightscript on instances of a given cloud."
@@ -18,15 +18,17 @@ require 'logger'
18
18
  require 'rightscale_cli/config'
19
19
 
20
20
  class RightScaleCLI
21
+ # Represents a RightScale CLI Logger
21
22
  class Logger
22
23
  attr_accessor :log
23
-
24
- def initialize(*args)
24
+
25
+ def initialize(*)
25
26
  @log_init_msg = 'Initializing Logging using '
26
27
 
27
28
  if ENV['RIGHT_API_CLIENT_LOG']
28
- if File.exists?(ENV['RIGHT_API_CLIENT_LOG'])
29
- file = File.open(ENV['RIGHT_API_CLIENT_LOG'], File::WRONLY | File::APPEND)
29
+ if File.exist?(ENV['RIGHT_API_CLIENT_LOG'])
30
+ file = File.open(ENV['RIGHT_API_CLIENT_LOG'],
31
+ File::WRONLY | File::APPEND)
30
32
  else
31
33
  file = ENV['RIGHT_API_CLIENT_LOG']
32
34
  end
@@ -38,14 +40,14 @@ class RightScaleCLI
38
40
  end
39
41
  end
40
42
 
41
- def init_message()
43
+ def init_message
42
44
  @log.info @log_init_msg
43
45
  end
44
46
 
45
47
  def info(msg)
46
48
  @log.info msg
47
49
  end
48
-
50
+
49
51
  def debug(msg)
50
52
  @log.debug msg
51
53
  end