knife-sce 0.2.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.
@@ -0,0 +1,128 @@
1
+ #
2
+ # Author:: Rad Gruchalski (<radek@gruchalski.com>)
3
+ # License:: Apache License, Version 2.0
4
+ #
5
+ # Licensed under the Apache License, Version 2.0 (the "License");
6
+ # you may not use this file except in compliance with the License.
7
+ # You may obtain a copy of the License at
8
+ #
9
+ # http://www.apache.org/licenses/LICENSE-2.0
10
+ #
11
+ # Unless required by applicable law or agreed to in writing, software
12
+ # distributed under the License is distributed on an "AS IS" BASIS,
13
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
+ # See the License for the specific language governing permissions and
15
+ # limitations under the License.
16
+ #
17
+
18
+ class String
19
+ def is_number?
20
+ true if Float(self) rescue false
21
+ end
22
+ end
23
+
24
+ require 'chef/knife'
25
+
26
+ class Chef
27
+ class Knife
28
+ module SceBase
29
+
30
+ # :nodoc:
31
+ # Would prefer to do this in a rational way, but can't be done b/c of
32
+ # Mixlib::CLI's design :(
33
+ def self.included(includer)
34
+ includer.class_eval do
35
+
36
+ deps do
37
+ require 'fog'
38
+ require 'readline'
39
+ require 'chef/json_compat'
40
+ end
41
+
42
+ option :ibm_username,
43
+ :short => "-A USERNAME",
44
+ :long => "--ibm-username USERNAME",
45
+ :description => "Your IBM SCE username",
46
+ :proc => Proc.new { |key| Chef::Config[:knife][:ibm_username] = key }
47
+
48
+ option :ibm_password,
49
+ :short => "-K PASSWORD",
50
+ :long => "--ibm-password PASSWORD",
51
+ :description => "Your SCE password",
52
+ :proc => Proc.new { |key| Chef::Config[:knife][:ibm_password] = key }
53
+ end
54
+ end
55
+
56
+ def connection
57
+ @connection ||= begin
58
+ connection = Fog::Compute.new(
59
+ :provider => 'IBM',
60
+ :ibm_username => Chef::Config[:knife][:ibm_username],
61
+ :ibm_password => Chef::Config[:knife][:ibm_password]
62
+ )
63
+ end
64
+ end
65
+
66
+ def connection_storage
67
+ @connection_storage ||= begin
68
+ connection_storage = Fog::Storage.new(
69
+ :provider => 'IBM',
70
+ :ibm_username => Chef::Config[:knife][:ibm_username],
71
+ :ibm_password => Chef::Config[:knife][:ibm_password]
72
+ )
73
+ end
74
+ end
75
+
76
+ def locate_config_value(key)
77
+ key = key.to_sym
78
+ config[key] || Chef::Config[:knife][key]
79
+ end
80
+
81
+ def datacenter_id
82
+ id = nil
83
+ if locate_config_value(:datacenter).to_s.is_number?
84
+ location = connection.locations.get( locate_config_value(:datacenter) )
85
+ if !location.nil?
86
+ id = location.id.to_s
87
+ else
88
+ ui.error("Location ID #{locate_config_value(:datacenter)} is invalid. Use knife sce location list to learn what IDs or textual locations are available.")
89
+ exit 1
90
+ end
91
+ else
92
+ connection.locations.all.each do |location|
93
+ if location.name.to_s.split(",").first.downcase.eql?( locate_config_value(:datacenter).downcase )
94
+ id = location.id.to_s
95
+ end
96
+ end
97
+ end
98
+
99
+ if id.nil?
100
+ ui.error("Location #{locate_config_value(:datacenter)} is invalid. Use knife sce location list to learn what IDs or textual locations are available.")
101
+ exit 1
102
+ end
103
+
104
+ id
105
+ end
106
+
107
+ def msg_pair(label, value, color=:cyan)
108
+ if value && !value.to_s.empty?
109
+ puts "#{ui.color(label, color)}: #{value}"
110
+ end
111
+ end
112
+
113
+ def validate!(keys=[:ibm_username, :ibm_password])
114
+ errors = []
115
+ keys.each do |k|
116
+ pretty_key = k.to_s.gsub(/_/, ' ').gsub(/\w+/){ |w| (w =~ /(ssh)|(aws)/i) ? w.upcase : w.capitalize }
117
+ if Chef::Config[:knife][k].nil?
118
+ errors << "You did not provide a valid '#{pretty_key}' value."
119
+ end
120
+ end
121
+ if errors.each{|e| ui.error(e)}.any?
122
+ exit 1
123
+ end
124
+ end
125
+
126
+ end
127
+ end
128
+ end
@@ -0,0 +1,82 @@
1
+ #
2
+ # Author:: Rad Gruchalski (<radek@gruchalski.com>)
3
+ # License:: Apache License, Version 2.0
4
+ #
5
+ # Licensed under the Apache License, Version 2.0 (the "License");
6
+ # you may not use this file except in compliance with the License.
7
+ # You may obtain a copy of the License at
8
+ #
9
+ # http://www.apache.org/licenses/LICENSE-2.0
10
+ #
11
+ # Unless required by applicable law or agreed to in writing, software
12
+ # distributed under the License is distributed on an "AS IS" BASIS,
13
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
+ # See the License for the specific language governing permissions and
15
+ # limitations under the License.
16
+ #
17
+
18
+ require 'chef/knife/sce_base'
19
+
20
+ class Chef
21
+ class Knife
22
+ class SceImageDescribe < Knife
23
+
24
+ include Knife::SceBase
25
+
26
+ banner "knife sce image describe IMAGE_ID [IMAGE_ID]"
27
+
28
+ def run
29
+
30
+ validate!
31
+
32
+ @name_args.each do |image_id|
33
+
34
+ begin
35
+ @image = connection.images.get(image_id)
36
+ rescue Excon::Errors::InternalServerError => e
37
+ if image_id.is_number?
38
+ ui.error e.inspect
39
+ exit 1
40
+ end
41
+ # is not a number and we received an error, ignore, API likes numbers only, we try to fetch the image by the name
42
+ end
43
+
44
+ if @image.nil?
45
+ connection.images.all.each do |i|
46
+ if i.name.to_s == image_id
47
+ @image = i
48
+ end
49
+ end
50
+ end
51
+
52
+ msg_pair("Image ID", @image.id.to_s)
53
+ msg_pair("Name", @image.name.to_s)
54
+ msg_pair("Location", connection.locations.get(@image.location).name.to_s)
55
+ msg_pair("Description", @image.description.to_s)
56
+ msg_pair("Visbility", @image.visibility.to_s)
57
+ msg_pair("Platform", @image.platform.to_s)
58
+ msg_pair("Architecture", @image.architecture.to_s)
59
+ msg_pair("Owner", @image.owner.to_s)
60
+ msg_pair("State", @image.state.to_s)
61
+ msg_pair("Manifest", @image.manifest.to_s)
62
+ msg_pair("Product codes", ":")
63
+ @image.product_codes.each do |pc|
64
+ msg_pair(" -> ", pc)
65
+ end
66
+ msg_pair("Supported instance types", ":")
67
+ @image.supported_instance_types.each do |sit|
68
+ msg_pair(" -> ", sit.id.to_s)
69
+ msg_pair(" ", sit.label.to_s)
70
+ msg_pair(" ", sit.detail.to_s)
71
+ msg_pair(" ", "Price: #{sit.price['rate']}#{sit.price['currencyCode']}/#{sit.price['pricePerQuantity']}#{sit.price['unitOfMeasure']}")
72
+ end
73
+ msg_pair("Documentation", @image.documentation.to_s)
74
+
75
+ puts "\n"
76
+
77
+ end
78
+ end
79
+
80
+ end
81
+ end
82
+ end
@@ -0,0 +1,55 @@
1
+ #
2
+ # Author:: Rad Gruchalski (<radek@gruchalski.com>)
3
+ # License:: Apache License, Version 2.0
4
+ #
5
+ # Licensed under the Apache License, Version 2.0 (the "License");
6
+ # you may not use this file except in compliance with the License.
7
+ # You may obtain a copy of the License at
8
+ #
9
+ # http://www.apache.org/licenses/LICENSE-2.0
10
+ #
11
+ # Unless required by applicable law or agreed to in writing, software
12
+ # distributed under the License is distributed on an "AS IS" BASIS,
13
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
+ # See the License for the specific language governing permissions and
15
+ # limitations under the License.
16
+ #
17
+
18
+ require 'chef/knife'
19
+
20
+ class Chef
21
+ class Knife
22
+ class SceInstanceData < Knife
23
+
24
+ deps do
25
+ require 'chef/json_compat'
26
+ end
27
+
28
+ banner "knife sce instance data (options)"
29
+
30
+ option :edit,
31
+ :short => "-e",
32
+ :long => "--edit",
33
+ :description => "Edit the instance data"
34
+
35
+ option :run_list,
36
+ :short => "-r RUN_LIST",
37
+ :long => "--run-list RUN_LIST",
38
+ :description => "Comma separated list of roles/recipes to apply",
39
+ :proc => lambda { |o| o.split(/[\s,]+/) },
40
+ :default => []
41
+
42
+ def run
43
+ data = {
44
+ "chef_server" => Chef::Config[:chef_server_url],
45
+ "validation_client_name" => Chef::Config[:validation_client_name],
46
+ "validation_key" => IO.read(Chef::Config[:validation_key]),
47
+ "attributes" => { "run_list" => config[:run_list] }
48
+ }
49
+ data = edit_data(data) if config[:edit]
50
+ ui.output(data)
51
+ end
52
+ end
53
+ end
54
+ end
55
+
@@ -0,0 +1,58 @@
1
+ #
2
+ # Author:: Rad Gruchalski (<radek@gruchalski.com>)
3
+ # License:: Apache License, Version 2.0
4
+ #
5
+ # Licensed under the Apache License, Version 2.0 (the "License");
6
+ # you may not use this file except in compliance with the License.
7
+ # You may obtain a copy of the License at
8
+ #
9
+ # http://www.apache.org/licenses/LICENSE-2.0
10
+ #
11
+ # Unless required by applicable law or agreed to in writing, software
12
+ # distributed under the License is distributed on an "AS IS" BASIS,
13
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
+ # See the License for the specific language governing permissions and
15
+ # limitations under the License.
16
+ #
17
+
18
+ require 'chef/knife/sce_base'
19
+
20
+ class Chef
21
+ class Knife
22
+ class SceKeyCreate < Knife
23
+
24
+ include Knife::SceBase
25
+
26
+ banner "knife sce key create KEYNAME"
27
+
28
+ def run!(key_name)
29
+ @key = connection.keys.create(:name => key_name)
30
+ @key
31
+ end
32
+
33
+ def run
34
+
35
+ $stdout.sync = true
36
+
37
+ validate!
38
+
39
+ @key = run!(config[:name])
40
+
41
+ msg_pair("Name", @key.name.to_s)
42
+ msg_pair("Default", (@key.default ? "Yes" : "No"))
43
+ msg_pair("Key", @key.public_key.to_s)
44
+
45
+ end
46
+
47
+ def validate!
48
+
49
+ super
50
+
51
+ raise "No key name specified." if @name_args.length == 0
52
+ config[:name] = @name_args[0]
53
+
54
+ end
55
+
56
+ end
57
+ end
58
+ end
@@ -0,0 +1,66 @@
1
+ #
2
+ # Author:: Rad Gruchalski (<radek@gruchalski.com>)
3
+ # License:: Apache License, Version 2.0
4
+ #
5
+ # Licensed under the Apache License, Version 2.0 (the "License");
6
+ # you may not use this file except in compliance with the License.
7
+ # You may obtain a copy of the License at
8
+ #
9
+ # http://www.apache.org/licenses/LICENSE-2.0
10
+ #
11
+ # Unless required by applicable law or agreed to in writing, software
12
+ # distributed under the License is distributed on an "AS IS" BASIS,
13
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
+ # See the License for the specific language governing permissions and
15
+ # limitations under the License.
16
+ #
17
+
18
+ require 'chef/knife/sce_base'
19
+
20
+ class Chef
21
+ class Knife
22
+ class SceKeyDelete < Knife
23
+
24
+ include Knife::SceBase
25
+
26
+ banner "knife sce key delete KEYNAME"
27
+
28
+ def run!(key)
29
+ key.destroy
30
+ end
31
+
32
+ def run
33
+
34
+ $stdout.sync = true
35
+
36
+ validate!
37
+
38
+ @key = connection.keys.get(config[:name])
39
+
40
+ raise "Key #{config[:name]} does not exist." if @key.nil?
41
+
42
+ msg_pair("Name", @key.name.to_s)
43
+ msg_pair("Instances", @key.instance_ids.join(", ").to_s)
44
+ msg_pair("Default", (@key.default ? "Yes" : "No"))
45
+
46
+ puts "\n"
47
+ confirm("Do you really want to delete this key")
48
+
49
+ run!(@key)
50
+
51
+ ui.warn("Deleted key #{@key.name.to_s}")
52
+
53
+ end
54
+
55
+ def validate!
56
+
57
+ super
58
+
59
+ raise "No key name specified." if @name_args.length == 0
60
+ config[:name] = @name_args[0]
61
+
62
+ end
63
+
64
+ end
65
+ end
66
+ end
@@ -0,0 +1,61 @@
1
+ #
2
+ # Author:: Rad Gruchalski (<radek@gruchalski.com>)
3
+ # License:: Apache License, Version 2.0
4
+ #
5
+ # Licensed under the Apache License, Version 2.0 (the "License");
6
+ # you may not use this file except in compliance with the License.
7
+ # You may obtain a copy of the License at
8
+ #
9
+ # http://www.apache.org/licenses/LICENSE-2.0
10
+ #
11
+ # Unless required by applicable law or agreed to in writing, software
12
+ # distributed under the License is distributed on an "AS IS" BASIS,
13
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
+ # See the License for the specific language governing permissions and
15
+ # limitations under the License.
16
+ #
17
+
18
+ require 'chef/knife/sce_base'
19
+
20
+ class Chef
21
+ class Knife
22
+ class SceKeyGet < Knife
23
+
24
+ include Knife::SceBase
25
+
26
+ banner "knife sce key get KEYNAME"
27
+
28
+ def run!(key_name)
29
+ @key = connection.keys.get(key_name)
30
+ @key
31
+ end
32
+
33
+ def run
34
+
35
+ $stdout.sync = true
36
+
37
+ validate!
38
+
39
+ @key = run!(config[:name])
40
+
41
+ raise "Key #{config[:name]} does not exist." if @key.nil?
42
+
43
+ msg_pair("Name", @key.name.to_s)
44
+ msg_pair("Instances", @key.instance_ids.join(", ").to_s)
45
+ msg_pair("Default", (@key.default ? "Yes" : "No"))
46
+ msg_pair("Key", @key.public_key.to_s)
47
+
48
+ end
49
+
50
+ def validate!
51
+
52
+ super
53
+
54
+ raise "No key name specified." if @name_args.length == 0
55
+ config[:name] = @name_args[0]
56
+
57
+ end
58
+
59
+ end
60
+ end
61
+ end
@@ -0,0 +1,61 @@
1
+ #
2
+ # Author:: Rad Gruchalski (<radek@gruchalski.com>)
3
+ # License:: Apache License, Version 2.0
4
+ #
5
+ # Licensed under the Apache License, Version 2.0 (the "License");
6
+ # you may not use this file except in compliance with the License.
7
+ # You may obtain a copy of the License at
8
+ #
9
+ # http://www.apache.org/licenses/LICENSE-2.0
10
+ #
11
+ # Unless required by applicable law or agreed to in writing, software
12
+ # distributed under the License is distributed on an "AS IS" BASIS,
13
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
+ # See the License for the specific language governing permissions and
15
+ # limitations under the License.
16
+ #
17
+
18
+ require 'chef/knife/sce_base'
19
+
20
+ class Chef
21
+ class Knife
22
+ class SceKeyList < Knife
23
+
24
+ include Knife::SceBase
25
+
26
+ banner "knife sce key list"
27
+
28
+ def run!
29
+ connection.keys.all
30
+ end
31
+
32
+ def run
33
+
34
+ $stdout.sync = true
35
+
36
+ validate!
37
+
38
+ keys = run!
39
+
40
+ key_list = [
41
+ ui.color('Name', :bold),
42
+ ui.color('Default', :bold),
43
+ ui.color("Modified at", :bold),
44
+ ui.color('Instances', :bold)
45
+ ].flatten.compact
46
+
47
+ output_column_count = key_list.length
48
+
49
+ keys.each do |k|
50
+ key_list << k.name.to_s
51
+ key_list << (k.default ? "*" : " ")
52
+ key_list << Time.at(k.modified_at/1000).to_datetime.to_s
53
+ key_list << k.instance_ids.join(", ").to_s
54
+ end
55
+
56
+ puts ui.list(key_list, :uneven_columns_across, output_column_count)
57
+
58
+ end
59
+ end
60
+ end
61
+ end
@@ -0,0 +1,105 @@
1
+ #
2
+ # Author:: Rad Gruchalski (<radek@gruchalski.com>)
3
+ # License:: Apache License, Version 2.0
4
+ #
5
+ # Licensed under the Apache License, Version 2.0 (the "License");
6
+ # you may not use this file except in compliance with the License.
7
+ # You may obtain a copy of the License at
8
+ #
9
+ # http://www.apache.org/licenses/LICENSE-2.0
10
+ #
11
+ # Unless required by applicable law or agreed to in writing, software
12
+ # distributed under the License is distributed on an "AS IS" BASIS,
13
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
+ # See the License for the specific language governing permissions and
15
+ # limitations under the License.
16
+ #
17
+
18
+ require 'chef/knife/sce_base'
19
+
20
+ class Chef
21
+ class Knife
22
+ class SceLocationList < Knife
23
+
24
+ include Knife::SceBase
25
+
26
+ banner "knife sce location list (options)"
27
+
28
+ option :description,
29
+ :short => "-L",
30
+ :long => "--with-description",
31
+ :boolean => true,
32
+ :default => false,
33
+ :description => "Display description of the location"
34
+
35
+ option :capabilities,
36
+ :short => "-C",
37
+ :long => "--with-capabilities",
38
+ :boolean => true,
39
+ :default => false,
40
+ :description => "Display capabilities"
41
+
42
+ def run!
43
+ connection.locations.all
44
+ end
45
+
46
+ def run
47
+ $stdout.sync = true
48
+
49
+ validate!
50
+
51
+ location_list = [
52
+ ui.color('Location ID', :bold),
53
+ ui.color("Name", :bold),
54
+ ui.color('Location', :bold),
55
+ if config[:description]
56
+ ui.color('Description', :bold)
57
+ end,
58
+ if config[:capabilities]
59
+ ui.color('Capabilities', :bold)
60
+ end
61
+ ].flatten.compact
62
+
63
+ output_column_count = location_list.length
64
+
65
+ locations = run!
66
+
67
+ locations.each do |location|
68
+ location_list << location.id.to_s
69
+ location_list << location.name.to_s
70
+ location_list << location.location.to_s
71
+ if config[:description]
72
+ location_list << location.description.to_s
73
+ end
74
+ if config[:capabilities]
75
+ if location.capabilities.length > 0
76
+ tabs = "\t"
77
+ tabs = "#{tabs}\t" if location.capabilities[0]["id"].to_s.length < 25
78
+ location_list << "#{location.capabilities[0]["id"].to_s}:#{tabs}#{location.capabilities[0]["entries"].to_s}"
79
+ else
80
+ location_list << " "
81
+ end
82
+ end
83
+
84
+ if config[:capabilities]
85
+ (1...location.capabilities.length).each do |index|
86
+ location_list << " "
87
+ location_list << " "
88
+ location_list << " "
89
+ if config[:description]
90
+ location_list << " "
91
+ end
92
+ tabs = "\t"
93
+ tabs = "#{tabs}\t" if location.capabilities[index]["id"].to_s.length < 25
94
+ location_list << "#{location.capabilities[index]["id"].to_s}:#{tabs}#{location.capabilities[index]["entries"].to_s}"
95
+ end
96
+ end
97
+
98
+ end
99
+
100
+ puts ui.list(location_list, :uneven_columns_across, output_column_count)
101
+
102
+ end
103
+ end
104
+ end
105
+ end