knife-clc 0.0.1.pre
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 +7 -0
- data/LICENSE +201 -0
- data/README.md +295 -0
- data/lib/chef/knife/clc_base.rb +71 -0
- data/lib/chef/knife/clc_datacenter_list.rb +35 -0
- data/lib/chef/knife/clc_group_create.rb +111 -0
- data/lib/chef/knife/clc_group_list.rb +109 -0
- data/lib/chef/knife/clc_ip_create.rb +129 -0
- data/lib/chef/knife/clc_ip_delete.rb +48 -0
- data/lib/chef/knife/clc_operation_show.rb +38 -0
- data/lib/chef/knife/clc_server_create.rb +595 -0
- data/lib/chef/knife/clc_server_delete.rb +38 -0
- data/lib/chef/knife/clc_server_list.rb +119 -0
- data/lib/chef/knife/clc_server_power_off.rb +38 -0
- data/lib/chef/knife/clc_server_power_on.rb +38 -0
- data/lib/chef/knife/clc_server_reboot.rb +38 -0
- data/lib/chef/knife/clc_server_show.rb +188 -0
- data/lib/chef/knife/clc_template_list.rb +91 -0
- data/lib/clc/client.rb +204 -0
- data/lib/clc/cloud_exceptions.rb +39 -0
- data/lib/clc.rb +2 -0
- data/lib/knife-clc/version.rb +5 -0
- metadata +250 -0
@@ -0,0 +1,119 @@
|
|
1
|
+
require 'chef/knife/clc_base'
|
2
|
+
|
3
|
+
class Chef
|
4
|
+
class Knife
|
5
|
+
class ClcServerList < Knife
|
6
|
+
include Knife::ClcBase
|
7
|
+
|
8
|
+
banner 'knife clc server list (options)'
|
9
|
+
|
10
|
+
option :clc_datacenter,
|
11
|
+
:long => '--datacenter ID',
|
12
|
+
:description => 'Short string representing the data center you are querying',
|
13
|
+
:on => :head
|
14
|
+
|
15
|
+
option :clc_all,
|
16
|
+
:long => '--all',
|
17
|
+
:boolean => true,
|
18
|
+
:default => false,
|
19
|
+
:description => 'The attribute to return a list of all servers from all datacenters',
|
20
|
+
:on => :head
|
21
|
+
|
22
|
+
option :clc_chef_nodes,
|
23
|
+
:long => '--chef-nodes',
|
24
|
+
:boolean => true,
|
25
|
+
:default => false,
|
26
|
+
:description => 'Wherever to include Chef node names in the listing or not',
|
27
|
+
:on => :head
|
28
|
+
|
29
|
+
def execute
|
30
|
+
servers = cloud_servers
|
31
|
+
merge_public_ips!(servers)
|
32
|
+
merge_chef_nodes!(servers) if config[:clc_chef_nodes]
|
33
|
+
|
34
|
+
context[:servers] = servers
|
35
|
+
|
36
|
+
render
|
37
|
+
end
|
38
|
+
|
39
|
+
def merge_public_ips!(servers)
|
40
|
+
servers.map! do |server|
|
41
|
+
ip_link = server['links'].find { |link| link['rel'] == 'publicIPAddress' }
|
42
|
+
server['publicIP'] = ip_link['id'] if ip_link
|
43
|
+
server
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
def merge_chef_nodes!(servers)
|
48
|
+
nodes = Chef::Node.list(true).values
|
49
|
+
servers.map! do |server|
|
50
|
+
existing_node = nodes.find { |node| node['machinename'] == server['name'] }
|
51
|
+
server['chefNode'] = existing_node.name if existing_node
|
52
|
+
server
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
def cloud_servers
|
57
|
+
if config[:clc_datacenter]
|
58
|
+
connection.list_servers(config[:clc_datacenter])
|
59
|
+
elsif config[:clc_all]
|
60
|
+
datacenters = connection.list_datacenters
|
61
|
+
|
62
|
+
datacenters.map do |dc|
|
63
|
+
connection.list_servers(dc['id'])
|
64
|
+
end.flatten
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
def headers
|
69
|
+
{
|
70
|
+
'id' => 'ID',
|
71
|
+
'name' => 'Name',
|
72
|
+
'publicIP' => 'Public IP',
|
73
|
+
'chefNode' => 'Chef Node',
|
74
|
+
'groupId' => 'Group',
|
75
|
+
'osType' => 'OS Type',
|
76
|
+
'status' => 'Status',
|
77
|
+
'locationId' => 'DC'
|
78
|
+
}
|
79
|
+
end
|
80
|
+
|
81
|
+
def fields
|
82
|
+
# TODO AS: Displaying shortened list of fields for now
|
83
|
+
# default_fields = %w(id name publicIP groupId locationId osType status)
|
84
|
+
default_fields = %w(name publicIP status)
|
85
|
+
config[:clc_chef_nodes] ? default_fields.insert(3, 'chefNode') : default_fields
|
86
|
+
end
|
87
|
+
|
88
|
+
def filters
|
89
|
+
{
|
90
|
+
'publicIP' => ->(ip) { ip || '-' },
|
91
|
+
'chefNode' => ->(name) { name || '-' }
|
92
|
+
}
|
93
|
+
end
|
94
|
+
|
95
|
+
def width_limits
|
96
|
+
{
|
97
|
+
'chefNode' => 21,
|
98
|
+
'status' => 15
|
99
|
+
}
|
100
|
+
end
|
101
|
+
|
102
|
+
def render
|
103
|
+
ui.info Hirb::Helpers::AutoTable.render(context[:servers],
|
104
|
+
:headers => headers,
|
105
|
+
:fields => fields,
|
106
|
+
:filters => filters,
|
107
|
+
:max_fields => width_limits,
|
108
|
+
:resize => false,
|
109
|
+
:description => false)
|
110
|
+
end
|
111
|
+
|
112
|
+
def parse_and_validate_parameters
|
113
|
+
if config[:clc_datacenter].nil? && !config[:clc_all]
|
114
|
+
errors << 'Datacenter ID is required'
|
115
|
+
end
|
116
|
+
end
|
117
|
+
end
|
118
|
+
end
|
119
|
+
end
|
@@ -0,0 +1,38 @@
|
|
1
|
+
require 'chef/knife/clc_base'
|
2
|
+
|
3
|
+
class Chef
|
4
|
+
class Knife
|
5
|
+
class ClcServerPowerOff < Knife
|
6
|
+
include Knife::ClcBase
|
7
|
+
|
8
|
+
banner 'knife clc server power_off ID (options)'
|
9
|
+
|
10
|
+
option :clc_wait,
|
11
|
+
:long => '--wait',
|
12
|
+
:description => 'Wait for operation completion',
|
13
|
+
:boolean => true,
|
14
|
+
:default => false,
|
15
|
+
:on => :head
|
16
|
+
|
17
|
+
def parse_and_validate_parameters
|
18
|
+
unless name_args[0]
|
19
|
+
errors << 'Server ID is required'
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
def execute
|
24
|
+
ui.info 'Requesting server power off...'
|
25
|
+
links = connection.power_off_server(name_args[0])
|
26
|
+
|
27
|
+
if config[:clc_wait]
|
28
|
+
connection.wait_for(links['operation']['id']) { putc '.' }
|
29
|
+
ui.info "\n"
|
30
|
+
ui.info 'Server has been powered off'
|
31
|
+
else
|
32
|
+
ui.info 'Power off request has been sent'
|
33
|
+
ui.info "You can check power off operation status with 'knife clc operation show #{links['operation']['id']}'"
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
@@ -0,0 +1,38 @@
|
|
1
|
+
require 'chef/knife/clc_base'
|
2
|
+
|
3
|
+
class Chef
|
4
|
+
class Knife
|
5
|
+
class ClcServerPowerOn < Knife
|
6
|
+
include Knife::ClcBase
|
7
|
+
|
8
|
+
banner 'knife clc server power_on ID (options)'
|
9
|
+
|
10
|
+
option :clc_wait,
|
11
|
+
:long => '--wait',
|
12
|
+
:description => 'Wait for operation completion',
|
13
|
+
:boolean => true,
|
14
|
+
:default => false,
|
15
|
+
:on => :head
|
16
|
+
|
17
|
+
def parse_and_validate_parameters
|
18
|
+
unless name_args[0]
|
19
|
+
errors << 'Server ID is required'
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
def execute
|
24
|
+
ui.info 'Requesting server power on...'
|
25
|
+
links = connection.power_on_server(name_args[0])
|
26
|
+
|
27
|
+
if config[:clc_wait]
|
28
|
+
connection.wait_for(links['operation']['id']) { putc '.' }
|
29
|
+
ui.info "\n"
|
30
|
+
ui.info 'Server has been powered on'
|
31
|
+
else
|
32
|
+
ui.info 'Power on request has been sent'
|
33
|
+
ui.info "You can check power on operation status with 'knife clc operation show #{links['operation']['id']}'"
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
@@ -0,0 +1,38 @@
|
|
1
|
+
require 'chef/knife/clc_base'
|
2
|
+
|
3
|
+
class Chef
|
4
|
+
class Knife
|
5
|
+
class ClcServerReboot < Knife
|
6
|
+
include Knife::ClcBase
|
7
|
+
|
8
|
+
banner 'knife clc server reboot ID (options)'
|
9
|
+
|
10
|
+
option :clc_wait,
|
11
|
+
:long => '--wait',
|
12
|
+
:description => 'Wait for operation completion',
|
13
|
+
:boolean => true,
|
14
|
+
:default => false,
|
15
|
+
:on => :head
|
16
|
+
|
17
|
+
def parse_and_validate_parameters
|
18
|
+
unless name_args[0]
|
19
|
+
errors << 'Server ID is required'
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
def execute
|
24
|
+
ui.info 'Requesting server reboot...'
|
25
|
+
links = connection.reboot_server(name_args[0])
|
26
|
+
|
27
|
+
if config[:clc_wait]
|
28
|
+
connection.wait_for(links['operation']['id']) { putc '.' }
|
29
|
+
ui.info "\n"
|
30
|
+
ui.info 'Server has been rebooted'
|
31
|
+
else
|
32
|
+
ui.info 'Reboot request has been sent'
|
33
|
+
ui.info "You can check reboot operation status with 'knife clc operation show #{links['operation']['id']}'"
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
@@ -0,0 +1,188 @@
|
|
1
|
+
require 'chef/knife/clc_base'
|
2
|
+
|
3
|
+
class Chef
|
4
|
+
class Knife
|
5
|
+
class ClcServerShow < Knife
|
6
|
+
include Knife::ClcBase
|
7
|
+
|
8
|
+
banner 'knife clc server show ID (options)'
|
9
|
+
|
10
|
+
option :clc_uuid,
|
11
|
+
:long => '--uuid',
|
12
|
+
:description => 'Use primary argument as server UUID instead of just ID',
|
13
|
+
:boolean => true,
|
14
|
+
:default => false,
|
15
|
+
:on => :head
|
16
|
+
|
17
|
+
option :clc_creds,
|
18
|
+
:long => '--creds',
|
19
|
+
:description => 'Show server credentials',
|
20
|
+
:boolean => true,
|
21
|
+
:default => false,
|
22
|
+
:on => :head
|
23
|
+
|
24
|
+
option :clc_ports,
|
25
|
+
:long => '--ports',
|
26
|
+
:description => 'Show opened ports and restrictions',
|
27
|
+
:boolean => true,
|
28
|
+
:default => false,
|
29
|
+
:on => :head
|
30
|
+
|
31
|
+
def parse_and_validate_parameters
|
32
|
+
unless name_args[0]
|
33
|
+
errors << 'Server ID is required'
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
def execute
|
38
|
+
ui.info 'Requesting server info...'
|
39
|
+
|
40
|
+
context[:server] = get_server
|
41
|
+
context[:creds] = get_creds if config[:clc_creds]
|
42
|
+
context[:ip_addresses] = get_ip_addresses if config[:clc_ports]
|
43
|
+
|
44
|
+
render
|
45
|
+
end
|
46
|
+
|
47
|
+
def get_server
|
48
|
+
server = connection.show_server(name_args[0], config[:clc_uuid])
|
49
|
+
|
50
|
+
server['details'] ||= {}
|
51
|
+
server['details'].tap do |details|
|
52
|
+
details['ipAddresses'] ||= []
|
53
|
+
public_ips = server['details']['ipAddresses'].map { |addr| addr['public'] }.compact
|
54
|
+
private_ips = server['details']['ipAddresses'].map { |addr| addr['internal'] }.compact
|
55
|
+
details.merge!('publicIps' => public_ips, 'privateIps' => private_ips)
|
56
|
+
end
|
57
|
+
|
58
|
+
server
|
59
|
+
end
|
60
|
+
|
61
|
+
def get_creds
|
62
|
+
creds_link = context[:server]['links'].find { |link| link['rel'] == 'credentials' }
|
63
|
+
connection.follow(creds_link) if creds_link
|
64
|
+
end
|
65
|
+
|
66
|
+
def get_ip_addresses
|
67
|
+
context[:ip_addresses] = connection.list_ip_addresses(context[:server]['id'])
|
68
|
+
end
|
69
|
+
|
70
|
+
def render
|
71
|
+
render_properties
|
72
|
+
render_creds if config[:clc_creds]
|
73
|
+
render_addresses if config[:clc_ports]
|
74
|
+
end
|
75
|
+
|
76
|
+
def server_properties
|
77
|
+
%w(id name description groupId locationId osType status)
|
78
|
+
end
|
79
|
+
|
80
|
+
def server_detail_properties
|
81
|
+
%w(powerState cpu memoryMB storageGB publicIps privateIps)
|
82
|
+
end
|
83
|
+
|
84
|
+
def property_labels
|
85
|
+
{
|
86
|
+
'id' => 'ID',
|
87
|
+
'name' => 'Name',
|
88
|
+
'description' => 'Description',
|
89
|
+
'groupId' => 'Group',
|
90
|
+
'locationId' => 'Location',
|
91
|
+
'osType' => 'OS Type',
|
92
|
+
'cpu' => 'CPUs',
|
93
|
+
'memoryMB' => 'Memory',
|
94
|
+
'storageGB' => 'Storage',
|
95
|
+
'status' => 'Status',
|
96
|
+
'powerState' => 'Power State',
|
97
|
+
'publicIps' => 'Public IPs',
|
98
|
+
'privateIps' => 'Private IPs',
|
99
|
+
'userName' => 'Username',
|
100
|
+
'password' => 'Password'
|
101
|
+
}
|
102
|
+
end
|
103
|
+
|
104
|
+
def property_filters
|
105
|
+
{
|
106
|
+
'description' => ->(description) { description.empty? ? '-' : description },
|
107
|
+
'memoryMB' => ->(memory) { "#{memory} MB" },
|
108
|
+
'storageGB' => ->(storage) { "#{storage} GB" },
|
109
|
+
'publicIps' => ->(ips) { ips.empty? ? '-' : ips.join(', ') },
|
110
|
+
'privateIps' => ->(ips) { ips.empty? ? '-' : ips.join(', ') }
|
111
|
+
}
|
112
|
+
end
|
113
|
+
|
114
|
+
def render_properties
|
115
|
+
server = context[:server]
|
116
|
+
|
117
|
+
render_fields(:fields => server_properties, :container => server)
|
118
|
+
render_fields(:fields => server_detail_properties, :container => server['details'])
|
119
|
+
end
|
120
|
+
|
121
|
+
def render_addresses
|
122
|
+
if context[:ip_addresses].empty?
|
123
|
+
ui.info 'No additional networking info available'
|
124
|
+
else
|
125
|
+
ui.info Hirb::Helpers::AutoTable.render(context[:ip_addresses],
|
126
|
+
:headers => ip_headers,
|
127
|
+
:fields => ip_fields,
|
128
|
+
:filters => ip_filters,
|
129
|
+
:resize => false,
|
130
|
+
:description => false)
|
131
|
+
end
|
132
|
+
end
|
133
|
+
|
134
|
+
def ip_fields
|
135
|
+
%w(id internalIPAddress ports sourceRestrictions)
|
136
|
+
end
|
137
|
+
|
138
|
+
def ip_headers
|
139
|
+
{
|
140
|
+
'id' => 'Public IP',
|
141
|
+
'internalIPAddress' => 'Internal IP',
|
142
|
+
'ports' => 'Ports',
|
143
|
+
'sourceRestrictions' => 'Sources'
|
144
|
+
}
|
145
|
+
end
|
146
|
+
|
147
|
+
def ip_filters
|
148
|
+
{
|
149
|
+
'sourceRestrictions' => ->(sources) { sources.empty? ? '-' : sources.map { |source| source['cidr'] }.join(', ') },
|
150
|
+
'ports' => ->(ports) { ports.map { |permission| format_permission(permission) }.join(', ') }
|
151
|
+
}
|
152
|
+
end
|
153
|
+
|
154
|
+
def format_permission(permission)
|
155
|
+
protocol = permission['protocol']
|
156
|
+
|
157
|
+
if %w(tcp udp).include? protocol.downcase
|
158
|
+
ports = permission.values_at('port', 'portTo').compact
|
159
|
+
[protocol, ports.join('-')].join(':')
|
160
|
+
else
|
161
|
+
protocol
|
162
|
+
end
|
163
|
+
end
|
164
|
+
|
165
|
+
def render_creds
|
166
|
+
render_fields(fields: %w(userName password), container: context[:creds] || {})
|
167
|
+
end
|
168
|
+
|
169
|
+
|
170
|
+
def render_fields(fields: [], labels: property_labels, filters: property_filters, container: {})
|
171
|
+
fields.each do |field|
|
172
|
+
value = container[field]
|
173
|
+
filter = filters[field]
|
174
|
+
|
175
|
+
formatted_value = if value
|
176
|
+
filter ? filter.call(value) : value
|
177
|
+
else
|
178
|
+
'-'
|
179
|
+
end
|
180
|
+
|
181
|
+
label = labels[field] || field
|
182
|
+
|
183
|
+
ui.info "#{ui.color(label + ':', :bold)} #{formatted_value}"
|
184
|
+
end
|
185
|
+
end
|
186
|
+
end
|
187
|
+
end
|
188
|
+
end
|
@@ -0,0 +1,91 @@
|
|
1
|
+
require 'chef/knife/clc_base'
|
2
|
+
|
3
|
+
class Chef
|
4
|
+
class Knife
|
5
|
+
class ClcTemplateList < Knife
|
6
|
+
include Knife::ClcBase
|
7
|
+
|
8
|
+
banner 'knife clc template list (options)'
|
9
|
+
|
10
|
+
option :clc_datacenter,
|
11
|
+
:long => '--datacenter ID',
|
12
|
+
:short => '-D ID',
|
13
|
+
:description => 'Datacenter ID to show templates from',
|
14
|
+
:on => :head
|
15
|
+
|
16
|
+
option :clc_all,
|
17
|
+
:long => '--all',
|
18
|
+
:boolean => true,
|
19
|
+
:default => false,
|
20
|
+
:description => 'The attribute to return a list of all templates from all datacenters',
|
21
|
+
:on => :head
|
22
|
+
|
23
|
+
def execute
|
24
|
+
context[:templates] = cloud_templates
|
25
|
+
render
|
26
|
+
end
|
27
|
+
|
28
|
+
def cloud_templates
|
29
|
+
if config[:clc_datacenter]
|
30
|
+
connection.list_templates(config[:clc_datacenter])
|
31
|
+
elsif config[:clc_all]
|
32
|
+
datacenters = connection.list_datacenters
|
33
|
+
|
34
|
+
datacenters.map do |dc|
|
35
|
+
connection.list_templates(dc['id'])
|
36
|
+
end.flatten
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
def parse_and_validate_parameters
|
41
|
+
if config[:clc_datacenter].nil? && !config[:clc_all]
|
42
|
+
errors << 'Datacenter ID is required'
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
def filters
|
47
|
+
{
|
48
|
+
'storageSizeGB' => ->(size) { (size.zero? ? '-' : "#{size} GB").rjust(7) },
|
49
|
+
'apiOnly' => ->(api_flag) { (api_flag ? '+' : '-').center(9) },
|
50
|
+
'capabilities' => ->(capabilities) { capabilities.empty? ? '-' : capabilities.join(', ') }
|
51
|
+
}
|
52
|
+
end
|
53
|
+
|
54
|
+
def width_limits
|
55
|
+
{
|
56
|
+
'description' => 0.2,
|
57
|
+
'storageSizeGB' => 7,
|
58
|
+
'capabilities' => 15,
|
59
|
+
'apiOnly' => 9
|
60
|
+
}
|
61
|
+
end
|
62
|
+
|
63
|
+
def fields
|
64
|
+
# TODO AS: Displaying shortened list of fields for now
|
65
|
+
# %w(name osType description storageSizeGB capabilities apiOnly)
|
66
|
+
%w(name storageSizeGB capabilities)
|
67
|
+
end
|
68
|
+
|
69
|
+
def headers
|
70
|
+
{
|
71
|
+
'name' => 'Name',
|
72
|
+
'osType' => 'OS Type',
|
73
|
+
'description' => 'Description',
|
74
|
+
'storageSizeGB' => 'Storage',
|
75
|
+
'capabilities' => 'Capabilities',
|
76
|
+
'apiOnly' => 'API Only'
|
77
|
+
}
|
78
|
+
end
|
79
|
+
|
80
|
+
def render
|
81
|
+
ui.info Hirb::Helpers::AutoTable.render(context[:templates],
|
82
|
+
:headers => headers,
|
83
|
+
:fields => fields,
|
84
|
+
:filters => filters,
|
85
|
+
:max_fields => width_limits,
|
86
|
+
:resize => false,
|
87
|
+
:description => false)
|
88
|
+
end
|
89
|
+
end
|
90
|
+
end
|
91
|
+
end
|