rightscale-cli 0.5.6 → 0.6.0

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.
@@ -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