knife-joyent 0.3.6 → 0.4.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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 97840b8a3ec364a32ca0735ec200d7f0a0823351
4
- data.tar.gz: 298e8434baa3a3c1d469fa0a39b748c3f04af02f
3
+ metadata.gz: 45293468ec017cf7ebb0f58f4a0d3a95531dad56
4
+ data.tar.gz: bfe1d3c0b2da13606dc83038fb815ca2e7dd0532
5
5
  SHA512:
6
- metadata.gz: b24792faf5a1d8b15c6e1ba29630a5f1213fe95872d863b94664dc52f0de3017204b117916584b4d2df4044378ac2d1e6670987c5f4212fd09088eb17079f0b0
7
- data.tar.gz: 16b9f5f771f78863116eb109397c467e459b348ca0e3b1d27da71c3bd711570575f617c9a930ab503319566fd859ab707f4c6ff361d4d494ebf9144ccb2a7da2
6
+ metadata.gz: 97084d24162cf1f927515cd3b64a097fed154c04b9c4937a1df969aa2f329e5fbdfd69c78f8e07320409a0ced22d26585ab2a41f44c896e55ac199d5216e9784
7
+ data.tar.gz: 58c05b85366ac511235eb3bd10847694333f0e17ca3bb595254505bcf743c578b1dd515dea310181aa92afe0b6fc46ee247b6ee11a43380354996f8d782d1ef7
data/README.md CHANGED
@@ -43,17 +43,26 @@ Currently available commands:
43
43
  knife joyent tag delete <server_id> -A
44
44
  knife joyent tag list <server_id>
45
45
 
46
+ # requires joyent_version 7.1+
47
+ knife joyent server fw enable <server_id>
48
+ knife joyent server fw disable <server_id>
49
+ knife joyent fw get <fwrule_id>
50
+ knife joyent fw create (options)
51
+ knife joyent fw list <server_id>
52
+ knife joyent fw update <rule_id> (options)
53
+ knife joyent fw delete <rule_id> (options)
54
+
46
55
  ## Example Usage
47
56
 
48
57
  The following command will provision an Ubuntu 12.04 with 1GB of memory and bootstrap it with chef
49
58
 
50
59
  # knife joyent server create \
51
- > --joyent-api-version '~7.0' \
52
- > --flavor "Small 1GB" \
53
- > --networks 42325ea0-eb62-44c1-8eb6-0af3e2f83abc,c8cde927-6277-49ca-82a3-741e8b23b02f \
54
- > --image d2ba0f30-bbe8-11e2-a9a2-6bc116856d85 \
55
- > --node-name 'cookbuntu0' \
56
- > --server-name 'cookbuntu0'
60
+ --joyent-api-version '~7.0' \
61
+ --flavor "Small 1GB" \
62
+ --networks 42325ea0-eb62-44c1-8eb6-0af3e2f83abc,c8cde927-6277-49ca-82a3-741e8b23b02f \
63
+ --image d2ba0f30-bbe8-11e2-a9a2-6bc116856d85 \
64
+ --node-name 'cookbuntu0' \
65
+ --server-name 'cookbuntu0'
57
66
 
58
67
  Creating machine cookbuntu0
59
68
  Waiting for Server to be Provisioned
@@ -111,7 +120,7 @@ to automatically unlock the key for authentication.
111
120
  **``joyent_api_url``**
112
121
 
113
122
  Specifies a custom CloudAPI endpoint, this is required if you want to manage
114
- machines located in another datacenter or if you want to interface with any CloudAPI
123
+ machines located in another datacenter or if you want to interface with any CloudAPI
115
124
  instance powered by [SmartDataCenter](http://www.joyent.com/products/smartdatacenter/).
116
125
 
117
126
  Defaults to us-west-1
@@ -141,7 +150,7 @@ the form of a hash with a single level of nesting. See the
141
150
  By default, knife-joyent will use the version of the Joyent Cloud API that fog prefers. This
142
151
  can be overridden in knife.rb as follows:
143
152
 
144
- knife[:joyent_version] = "~7.0"
153
+ knife[:joyent_version] = "~7.1"
145
154
 
146
155
  Some command line options to knife-joyent subcommands may depend on the Joyent API version set.
147
156
 
@@ -82,6 +82,19 @@ class Chef
82
82
  config[key] || Chef::Config[:knife][key]
83
83
  end
84
84
 
85
+ def output_error_response(res)
86
+ if (res.body['message'])
87
+ ui.error ui.color(res.body["message"], :white)
88
+ end
89
+
90
+ if (res.body["errors"])
91
+ errors = res.body["errors"]
92
+ errors.each do |e|
93
+ ui.error("[#{e["field"]}] #{e["message"]}")
94
+ end
95
+ end
96
+ end
97
+
85
98
  def msg_pair(label, value = nil)
86
99
  if value && !value.empty?
87
100
  puts "#{ui.color(label, :cyan)}: #{value}"
@@ -9,13 +9,12 @@ class Chef
9
9
  banner "knife joyent flavor list <options>"
10
10
 
11
11
  def run
12
-
13
12
  flavor_list = [
14
13
  ui.color('Name', :bold),
15
14
  ui.color(' RAM', :bold),
16
15
  ui.color(' Disk', :bold),
17
16
  ui.color(' Swap', :bold),
18
- ui.color('Price $/Hr', :bold),
17
+ ui.color('$ Per Month', :bold),
19
18
  ]
20
19
 
21
20
  self.connection.flavors.sort_by(&:memory).each do |flavor|
@@ -23,7 +22,7 @@ class Chef
23
22
  flavor_list << "#{sprintf "%6.2f", flavor.memory/1024.0} GB"
24
23
  flavor_list << "#{sprintf "%6.0f", flavor.disk/1024.0} GB"
25
24
  flavor_list << "#{sprintf "%5.0f", flavor.swap/1024.0} GB"
26
- flavor_list << (pricing[flavor.name.to_s] ? sprintf("$%.3f", pricing[flavor.name.to_s]) : "")
25
+ flavor_list << pricing.monthly_formatted_price_for_flavor(flavor.name.to_s, 10)
27
26
  end
28
27
 
29
28
  puts ui.list(flavor_list, :uneven_columns_across, 5)
@@ -31,3 +30,4 @@ class Chef
31
30
  end
32
31
  end
33
32
  end
33
+
@@ -0,0 +1,48 @@
1
+ require 'chef/knife/joyent_base'
2
+ require 'pp'
3
+
4
+ class Chef
5
+ class Knife
6
+ class JoyentFwCreate < Knife
7
+
8
+ include Knife::JoyentBase
9
+
10
+ banner "knife joyent fw create (options)"
11
+
12
+ option :rule,
13
+ :long => "--rule RULE",
14
+ :description => "Firewall Rule Content"
15
+
16
+ option :enabled,
17
+ :long => "--enabled",
18
+ :boolean => true,
19
+ :description => "Enable/Disable Rule"
20
+
21
+ def run
22
+ unless config[:rule]
23
+ show_usage
24
+ exit 1
25
+ end
26
+
27
+ res = self.connection.request(
28
+ :method => "POST",
29
+ :path => "/my/fwrules",
30
+ :body => {
31
+ "enabled" => config[:enabled],
32
+ "rule" => config[:rule],
33
+ }
34
+ )
35
+
36
+ unless res.status == 201
37
+ output_error_response(res)
38
+ else
39
+ r = res.body
40
+
41
+ ui.info "Created Firewall Rule: #{r["id"]}"
42
+ msg_pair "RULE", r["rule"]
43
+ msg_pair "ENABLED", (r["enabled"] ? ui.color("✓ YES", :cyan) : "✗ NO")
44
+ end
45
+ end
46
+ end
47
+ end
48
+ end
@@ -0,0 +1,39 @@
1
+ require 'chef/knife/joyent_base'
2
+
3
+ class Chef
4
+ class Knife
5
+ class JoyentFwDelete < Knife
6
+
7
+ include Knife::JoyentBase
8
+
9
+ banner "knife joyent fw delete <fw_id>"
10
+
11
+ def run
12
+ unless name_args.size === 1
13
+ show_usage
14
+ exit 1
15
+ end
16
+
17
+ id = name_args.first
18
+ # puts id
19
+ res = self.connection.request(
20
+ :method => "DELETE",
21
+ :path => "/my/fwrules/#{id}"
22
+ )
23
+
24
+ rules = [
25
+ ui.color('ID', :bold),
26
+ ui.color('Enabled', :bold),
27
+ ui.color('Rule', :bold),
28
+ ]
29
+
30
+ if res.status == 204
31
+ ui.info "Rule #{id} Deleted."
32
+ else
33
+ self.output_error_response(res)
34
+ end
35
+
36
+ end
37
+ end
38
+ end
39
+ end
@@ -0,0 +1,43 @@
1
+ require 'chef/knife/joyent_base'
2
+
3
+ class Chef
4
+ class Knife
5
+ class JoyentFwGet < Knife
6
+
7
+ include Knife::JoyentBase
8
+
9
+ banner "knife joyent fw get <fw_id>"
10
+
11
+ def run
12
+ unless name_args.size === 1
13
+ show_usage
14
+ exit 1
15
+ end
16
+
17
+ id = name_args.first
18
+ # puts id
19
+ res = self.connection.request(
20
+ :method => "GET",
21
+ :path => "/my/fwrules/#{id}"
22
+ )
23
+
24
+ rules = [
25
+ ui.color('ID', :bold),
26
+ ui.color('Enabled', :bold),
27
+ ui.color('Rule', :bold),
28
+ ]
29
+
30
+ if (res.status == 422)
31
+ output_error_response(res)
32
+ else
33
+ r = res.body
34
+ rules << r["id"]
35
+ rules << (r["enabled"] ? ui.color("✓", :cyan) : "✗")
36
+ rules << r["rule"]
37
+ ui.list(rules, :uneven_columns_across, 3)
38
+ end
39
+
40
+ end
41
+ end
42
+ end
43
+ end
@@ -0,0 +1,43 @@
1
+ require 'chef/knife/joyent_base'
2
+
3
+ class Chef
4
+ class Knife
5
+ class JoyentFwList < Knife
6
+
7
+ include Knife::JoyentBase
8
+
9
+ banner "knife joyent fw list"
10
+
11
+ def run
12
+ if name_args.size > 0
13
+ id = name_args.first
14
+ res = self.connection.request(
15
+ :method => "GET",
16
+ :path => "/my/machines/#{id}/fwrules"
17
+ )
18
+ else
19
+ res = self.connection.request(
20
+ :method => "GET",
21
+ :path => "/my/fwrules"
22
+ )
23
+ end
24
+
25
+ if res.status == 200
26
+ rules = [
27
+ ui.color('ID', :bold),
28
+ ui.color('Enabled', :bold),
29
+ ui.color('Rule', :bold),
30
+ ]
31
+
32
+ res[:body].each do |r|
33
+ rules << r["id"]
34
+ rules << (r["enabled"] ? ui.color("✓", :cyan) : "✗")
35
+ rules << r["rule"]
36
+ end
37
+ else
38
+ output_error_response(res)
39
+ end
40
+ end
41
+ end
42
+ end
43
+ end
@@ -0,0 +1,49 @@
1
+ require 'chef/knife/joyent_base'
2
+ require 'pp'
3
+
4
+ class Chef
5
+ class Knife
6
+ class JoyentFwUpdate < Knife
7
+
8
+ include Knife::JoyentBase
9
+
10
+ banner "knife joyent fw update <rule_id> (options)"
11
+
12
+ option :rule,
13
+ :long => "--rule RULE",
14
+ :description => "Firewall Rule Content"
15
+
16
+ option :enabled,
17
+ :long => "--enabled",
18
+ :boolean => true,
19
+ :description => "Enable/Disable Rule"
20
+
21
+ def run
22
+ id = name_args.first
23
+ unless id || (!config.key?(:rule) || !config.key?(:enabled))
24
+ show_usage
25
+ exit 1
26
+ end
27
+
28
+ res = self.connection.request(
29
+ :method => "POST",
30
+ :path => "/my/fwrules/#{id}",
31
+ :body => {
32
+ "enabled" => config[:enabled],
33
+ "rule" => config[:rule],
34
+ }
35
+ )
36
+
37
+ unless res.status == 200
38
+ output_error_response(res)
39
+ else
40
+ r = res.body
41
+
42
+ ui.info "Created Firewall Rule: #{r["id"]}"
43
+ msg_pair "RULE", r["rule"]
44
+ msg_pair "ENABLED", (r["enabled"] ? ui.color("✓ YES", :cyan) : "✗ NO")
45
+ end
46
+ end
47
+ end
48
+ end
49
+ end
@@ -0,0 +1,34 @@
1
+ require 'chef/knife/joyent_base'
2
+
3
+ class Chef
4
+ class Knife
5
+ class JoyentServerFwDisable < Knife
6
+
7
+ include Knife::JoyentBase
8
+
9
+ banner "knife joyent server fw disable <server_id>"
10
+
11
+ def run
12
+ unless name_args.size === 1
13
+ show_usage
14
+ exit 1
15
+ end
16
+
17
+ id = name_args.first
18
+
19
+ path = "/my/machines/#{id}"
20
+ res = self.connection.request(
21
+ :method => "POST",
22
+ :path => path,
23
+ :query => {"action" => "disable_firewall"}
24
+ )
25
+
26
+ if (res.status == 202)
27
+ puts ui.color("Firewall Disabled for server #{id}", :cyan)
28
+ else
29
+ output_error_response(res)
30
+ end
31
+ end
32
+ end
33
+ end
34
+ end
@@ -0,0 +1,33 @@
1
+ require 'chef/knife/joyent_base'
2
+
3
+ class Chef
4
+ class Knife
5
+ class JoyentServerFwEnable < Knife
6
+
7
+ include Knife::JoyentBase
8
+
9
+ banner "knife joyent server fw enable <server_id>"
10
+
11
+ def run
12
+ unless name_args.size === 1
13
+ show_usage
14
+ exit 1
15
+ end
16
+
17
+ id = name_args.first
18
+ # puts id
19
+ res = self.connection.request(
20
+ :method => "POST",
21
+ :path => "/my/machines/#{id}",
22
+ :query => {"action" => "enable_firewall"}
23
+ )
24
+
25
+ if (res.status === 202)
26
+ ui.info ui.color("Firewall Enabled for server #{id}", :cyan)
27
+ else
28
+ output_error_response(res)
29
+ end
30
+ end
31
+ end
32
+ end
33
+ end
@@ -9,6 +9,9 @@ class Chef
9
9
  banner "knife joyent server list <options>"
10
10
 
11
11
  def run
12
+ columns = 11
13
+ price_column_width = 11
14
+
12
15
  servers = [
13
16
  ui.color('ID', :bold),
14
17
  ui.color('Name', :bold),
@@ -19,9 +22,12 @@ class Chef
19
22
  ui.color('IPs', :bold),
20
23
  ui.color(' RAM', :bold),
21
24
  ui.color(' Disk', :bold),
25
+ ui.color('Price $/Month'),
22
26
  ui.color('Tags', :bold)
23
27
  ]
24
28
 
29
+ total_cost = 0
30
+
25
31
  self.connection.servers.sort do |a, b|
26
32
  (a.name || '') <=> (b.name || '')
27
33
  end.each do |s|
@@ -29,23 +35,27 @@ class Chef
29
35
  servers << s.name
30
36
 
31
37
  servers << case s.state
32
- when 'running'
33
- ui.color(s.state, :green)
34
- when 'stopping', 'provisioning'
35
- ui.color(s.state, :yellow)
36
- when 'stopped'
37
- ui.color(s.state, :red)
38
- else
39
- ui.color('unknown', :red)
40
- end
38
+ when 'running'
39
+ ui.color(s.state, :green)
40
+ when 'stopping', 'provisioning'
41
+ ui.color(s.state, :yellow)
42
+ when 'stopped'
43
+ ui.color(s.state, :red)
44
+ else
45
+ ui.color('unknown', :red)
46
+ end
47
+
48
+ flavor = s.respond_to?(:attributes) ? s.attributes["package"] : 'unknown'
41
49
 
42
50
  servers << s.type
43
51
  servers << s.dataset
44
- servers << (s.respond_to?(:attributes) ? s.attributes["package"] : 'unknown')
52
+ servers << flavor
45
53
  servers << s.ips.join(",")
46
54
  servers << "#{sprintf "%6.2f", s.memory/1024.0} GB"
47
55
  servers << "#{sprintf "%5.0f", s.disk/1024} GB"
56
+ servers << pricing.monthly_formatted_price_for_flavor(flavor, price_column_width)
48
57
 
58
+ total_cost += (pricing[flavor] || 0)
49
59
 
50
60
  if (s.tags rescue nil)
51
61
  servers << (show_tags? ? s.tags.map { |k, v| "#{k}:#{v}" }.join(' ') : "")
@@ -54,7 +64,12 @@ class Chef
54
64
  end
55
65
  end
56
66
 
57
- puts ui.list(servers, :uneven_columns_across, 10)
67
+ (columns - 3).times{servers << ""}
68
+ servers << " Total"
69
+ servers << pricing.formatted_price_for_value(total_cost * pricing.class::HOURS_PER_MONTH,
70
+ price_column_width)
71
+
72
+ puts ui.list(servers, :uneven_columns_across, columns)
58
73
  end
59
74
 
60
75
  def show_tags?
File without changes
@@ -5,6 +5,7 @@ module KnifeJoyent
5
5
  module Pricing
6
6
  class Config < ::Hash
7
7
  JOYENT_URL = "http://www.joyent.com/products/compute-service/pricing"
8
+ HOURS_PER_MONTH = 720
8
9
 
9
10
  def initialize
10
11
  super
@@ -20,6 +21,24 @@ module KnifeJoyent
20
21
  parse_html_document Nokogiri::HTML(File.read(filename))
21
22
  end
22
23
 
24
+ def monthly_price_for_flavor(flavor_name)
25
+ self[flavor_name] ? sprintf("$%.2f", self[flavor_name] * HOURS_PER_MONTH) : ""
26
+ end
27
+
28
+ def monthly_formatted_price_for_flavor(flavor, width = 10)
29
+ self[flavor] ? formatted_price_for_value(self[flavor] * HOURS_PER_MONTH, width) : ""
30
+ end
31
+
32
+ def formatted_price_for_value(value, width = 10)
33
+ sprintf("%#{width}s", currency_format(sprintf("$%.2f", value)))
34
+ end
35
+
36
+ # Returns string formatted with commas in the middle, such as "9,999,999"
37
+ def currency_format string
38
+ while string.sub!(/(\d+)(\d\d\d)/,'\1,\2'); end
39
+ string
40
+ end
41
+
23
42
  private
24
43
 
25
44
  def parse_html_document doc
@@ -40,3 +59,4 @@ module KnifeJoyent
40
59
  end
41
60
  end
42
61
  end
62
+
@@ -1,3 +1,3 @@
1
1
  module KnifeJoyent
2
- VERSION = "0.3.6"
2
+ VERSION = "0.4.0"
3
3
  end
@@ -1,26 +1,42 @@
1
1
  require_relative '../spec_helper'
2
2
 
3
3
 
4
-
5
4
  describe KnifeJoyent::Pricing::Config do
6
- context "URL Scraper" do
7
-
8
- let(:config) { KnifeJoyent::Pricing::Config.new() }
5
+ let(:config) { KnifeJoyent::Pricing::Config.new() }
9
6
 
10
- let(:prices) { { "g3-standard-48-smartos" => 1.536,
11
- "g3-standard-0.625-smartos" => 0.02,
12
- "g3-standard-30-kvm" => 0.960 } }
7
+ let(:prices) { {"g3-standard-48-smartos" => 1.536,
8
+ "g3-standard-0.625-smartos" => 0.02,
9
+ "g3-standard-30-kvm" => 0.960} }
13
10
 
14
- def verify
15
- prices.keys.each do |flavor|
16
- config[flavor].should eql(prices[flavor])
17
- end
11
+ def verify
12
+ prices.keys.each do |flavor|
13
+ config[flavor].should eql(prices[flavor])
18
14
  end
15
+ end
19
16
 
20
- it "should load pricing configuration hash from Joyent Website" do
21
- config.from_uri
22
- verify
23
- end
17
+ it "should load pricing configuration hash from Joyent Website" do
18
+ config.from_uri
19
+ verify
20
+ end
24
21
 
22
+ context "#monthly_price_for_flavor" do
23
+ it "should return properly formatted monthly price" do
24
+ expect(config.monthly_price_for_flavor "g3-standard-0.625-smartos").to eql("$14.40")
25
+ expect(config.monthly_price_for_flavor "g3-standard-30-kvm").to eql("$691.20")
26
+ end
27
+ end
28
+ context "#monthly_formatted_price_for_flavor" do
29
+ it "should return properly formatted monthly price" do
30
+ expect(config.monthly_formatted_price_for_flavor "g3-standard-48-smartos").to eql(" $1,105.92")
31
+ end
32
+ it "should return blank when no match was found" do
33
+ expect(config.monthly_formatted_price_for_flavor "asdfkasdfasdlfkjasl;dkjf").to eql("")
34
+ end
35
+ end
36
+ context "#formatted_price_for_value" do
37
+ it "should return properly formatted price" do
38
+ expect(config.formatted_price_for_value 24566.34).to eql("$24,566.34")
39
+ expect(config.formatted_price_for_value 4566.34).to eql(" $4,566.34")
40
+ end
25
41
  end
26
42
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: knife-joyent
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.3.6
4
+ version: 0.4.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Kevin Chan
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2013-11-19 00:00:00.000000000 Z
11
+ date: 2014-01-14 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: fog
@@ -100,6 +100,11 @@ files:
100
100
  - knife-joyent.gemspec
101
101
  - lib/chef/knife/joyent_base.rb
102
102
  - lib/chef/knife/joyent_flavor_list.rb
103
+ - lib/chef/knife/joyent_fw_create.rb
104
+ - lib/chef/knife/joyent_fw_delete.rb
105
+ - lib/chef/knife/joyent_fw_get.rb
106
+ - lib/chef/knife/joyent_fw_list.rb
107
+ - lib/chef/knife/joyent_fw_update.rb
103
108
  - lib/chef/knife/joyent_image_list.rb
104
109
  - lib/chef/knife/joyent_key_add.rb
105
110
  - lib/chef/knife/joyent_key_delete.rb
@@ -107,6 +112,8 @@ files:
107
112
  - lib/chef/knife/joyent_network_list.rb
108
113
  - lib/chef/knife/joyent_server_create.rb
109
114
  - lib/chef/knife/joyent_server_delete.rb
115
+ - lib/chef/knife/joyent_server_fw_disable.rb
116
+ - lib/chef/knife/joyent_server_fw_enable.rb
110
117
  - lib/chef/knife/joyent_server_list.rb
111
118
  - lib/chef/knife/joyent_server_metadata_delete.rb
112
119
  - lib/chef/knife/joyent_server_metadata_update.rb
@@ -121,6 +128,7 @@ files:
121
128
  - lib/chef/knife/joyent_tag_delete.rb
122
129
  - lib/chef/knife/joyent_tag_list.rb
123
130
  - lib/knife-joyent.rb
131
+ - lib/knife-joyent/fw.rb
124
132
  - lib/knife-joyent/pricing.rb
125
133
  - lib/knife-joyent/pricing/config.rb
126
134
  - lib/knife-joyent/version.rb