knife-glesys 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +17 -0
- data/Gemfile +5 -0
- data/LICENSE.txt +22 -0
- data/README.md +116 -0
- data/Rakefile +1 -0
- data/knife-glesys.gemspec +21 -0
- data/lib/chef/knife/glesys_base.rb +68 -0
- data/lib/chef/knife/glesys_server_create.rb +271 -0
- data/lib/chef/knife/glesys_server_delete.rb +110 -0
- data/lib/chef/knife/glesys_server_info.rb +45 -0
- data/lib/chef/knife/glesys_server_list.rb +38 -0
- data/lib/chef/knife/glesys_template_list.rb +39 -0
- data/lib/knife-glesys/version.rb +6 -0
- metadata +91 -0
data/.gitignore
ADDED
data/Gemfile
ADDED
data/LICENSE.txt
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
Copyright (c) 2013 Simon Gate
|
2
|
+
|
3
|
+
MIT License
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
6
|
+
a copy of this software and associated documentation files (the
|
7
|
+
"Software"), to deal in the Software without restriction, including
|
8
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
9
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
10
|
+
permit persons to whom the Software is furnished to do so, subject to
|
11
|
+
the following conditions:
|
12
|
+
|
13
|
+
The above copyright notice and this permission notice shall be
|
14
|
+
included in all copies or substantial portions of the Software.
|
15
|
+
|
16
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
17
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
18
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
19
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
20
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
21
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
22
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,116 @@
|
|
1
|
+
# Knife Glesys
|
2
|
+
|
3
|
+
knife-glesys is a Knife addon that will make it easier manage your VPS at [Glesys](http://www.glesys.se). You can create,
|
4
|
+
delete, list and show info about your servers.
|
5
|
+
To be able to use this addon you need to create a Glesys API key with permission to `IP` and `SERVER`. You do this in their control panel.
|
6
|
+
|
7
|
+
## Installation
|
8
|
+
|
9
|
+
To use the addon install it as a normal gem, from your command line run:
|
10
|
+
|
11
|
+
```bash
|
12
|
+
$ gem install knife-glesys
|
13
|
+
```
|
14
|
+
|
15
|
+
## Configuration
|
16
|
+
|
17
|
+
To configure the addon you can either add your Glesys username and your API key to knife.rb in your chef directory.
|
18
|
+
|
19
|
+
```ruby
|
20
|
+
knife[:glesys_username] = "YOUR USERNAME"
|
21
|
+
knife[:glesys_api_key] = "YOUR API KEY"
|
22
|
+
```
|
23
|
+
|
24
|
+
Or you can pass your username and your API key to the knife glesys command.
|
25
|
+
|
26
|
+
```bash
|
27
|
+
$ knife glesys server list --glesys-api-key "YOUR API KEY" --glesys-username "YOUR USERNAME"
|
28
|
+
```
|
29
|
+
|
30
|
+
## Usage
|
31
|
+
|
32
|
+
### Create a new server
|
33
|
+
|
34
|
+
When creating a new instance you there are some options you need to supply for it to work, `template` (server image),
|
35
|
+
`platform`, `data-center`, `root-password` and a `hostname`. It is recommended that you also specify the number of
|
36
|
+
cpu cores, the amount of memory and disksize. Or else these will default to 1 cpu core, 512 mb memory and 10 gb disk.
|
37
|
+
If you want to view the options you can just run the command without any options.
|
38
|
+
|
39
|
+
```bash
|
40
|
+
$ knife glesys server create (options)
|
41
|
+
```
|
42
|
+
|
43
|
+
To create a OpenVZ Debian server in Stockholm you run this command (This will also provision the host with the `db` role):
|
44
|
+
|
45
|
+
```bash
|
46
|
+
$ knife glesys server create --template "Debian 6.0 64-bit" --platform "OpenVZ" --data-center "Stockholm" \
|
47
|
+
--cpu-cores 1 --memory-size 128 --transfer 50 -N database --run-list 'role[:db]' \
|
48
|
+
--hostname "data.example.com" --root-password 'passw0rd' --description "Redis database server"
|
49
|
+
```
|
50
|
+
|
51
|
+
### List available templates
|
52
|
+
|
53
|
+
Glesys offers many different templates (or images) to use when you spin up a new VPS. To get a list of all available and on which platform you run:
|
54
|
+
|
55
|
+
```bash
|
56
|
+
$ knife glesys templates list
|
57
|
+
```
|
58
|
+
|
59
|
+
### List your servers
|
60
|
+
|
61
|
+
To list your servers that you have connected to your account. This will give you a list with
|
62
|
+
|
63
|
+
```bash
|
64
|
+
$ knife glesys server list
|
65
|
+
```
|
66
|
+
|
67
|
+
### More information about a server
|
68
|
+
|
69
|
+
To get detailed information about a server like how much memory that is used and how much the server costs you can issue the info command.
|
70
|
+
|
71
|
+
```bash
|
72
|
+
$ knife glesys server info vz31337
|
73
|
+
```
|
74
|
+
|
75
|
+
### Delete a server
|
76
|
+
|
77
|
+
Every server has a uniqe id at Glesys. Just pass this id to the delete command to erase the server.
|
78
|
+
|
79
|
+
```bash
|
80
|
+
$ knife glesys server delete vz31337
|
81
|
+
```
|
82
|
+
|
83
|
+
And to at the same time delete the Chef node pass the `--purge` option to the delete command.
|
84
|
+
|
85
|
+
## TODO
|
86
|
+
|
87
|
+
There are a few things that still needs to be fixed (in no special order).
|
88
|
+
|
89
|
+
* Manage Glesys IPs
|
90
|
+
* Graph server stats in console
|
91
|
+
|
92
|
+
## Known issues
|
93
|
+
|
94
|
+
* Needs HEAD version of [fog](https://github.com/fog/fog) to work
|
95
|
+
|
96
|
+
## Contributing
|
97
|
+
|
98
|
+
I like contributions, so if you find any errors please add a issue or even better, send a pull request.
|
99
|
+
|
100
|
+
1. Fork it
|
101
|
+
2. Create your feature branch (`git checkout -b my-new-feature`)
|
102
|
+
3. Commit your changes (`git commit -am 'Add some feature'`)
|
103
|
+
4. Push to the branch (`git push origin my-new-feature`)
|
104
|
+
5. Create new Pull Request
|
105
|
+
|
106
|
+
## Copyright
|
107
|
+
|
108
|
+
(The MIT License)
|
109
|
+
|
110
|
+
Copyright (c) 2013 smgt (Simon Gate)
|
111
|
+
|
112
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
113
|
+
|
114
|
+
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
115
|
+
|
116
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/Rakefile
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
require "bundler/gem_tasks"
|
@@ -0,0 +1,21 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
lib = File.expand_path('../lib', __FILE__)
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
+
require 'knife-glesys/version'
|
5
|
+
|
6
|
+
Gem::Specification.new do |gem|
|
7
|
+
gem.name = "knife-glesys"
|
8
|
+
gem.version = Knife::Glesys::VERSION
|
9
|
+
gem.authors = ["Simon Gate"]
|
10
|
+
gem.email = ["simon@smgt.me"]
|
11
|
+
gem.description = %q{Glesys support for Chef's Knife Command}
|
12
|
+
gem.summary = gem.description
|
13
|
+
gem.homepage = "https://github.com/smgt/knife-glesys"
|
14
|
+
|
15
|
+
gem.files = `git ls-files`.split($/)
|
16
|
+
gem.executables = gem.files.grep(%r{^bin/}).map{ |f| File.basename(f) }
|
17
|
+
gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
|
18
|
+
gem.require_paths = ["lib"]
|
19
|
+
gem.add_dependency "fog", "~> 1.9"
|
20
|
+
gem.add_dependency "chef", ">= 0.10.10"
|
21
|
+
end
|
@@ -0,0 +1,68 @@
|
|
1
|
+
require "chef/knife"
|
2
|
+
|
3
|
+
class Chef
|
4
|
+
class Knife
|
5
|
+
module GlesysBase
|
6
|
+
|
7
|
+
def self.included(includer)
|
8
|
+
includer.class_eval do
|
9
|
+
|
10
|
+
deps do
|
11
|
+
require 'fog'
|
12
|
+
require 'readline'
|
13
|
+
require 'chef/json_compat'
|
14
|
+
end
|
15
|
+
|
16
|
+
option :glesys_api_key,
|
17
|
+
:short => "-A KEY",
|
18
|
+
:long => "--glesys-api-key KEY",
|
19
|
+
:description => "Your Glesys API key",
|
20
|
+
:proc => Proc.new { |key| Chef::Config[:knife][:glesys_api_key] = key }
|
21
|
+
|
22
|
+
option :glesys_username,
|
23
|
+
:short => "-U USERNAME",
|
24
|
+
:long => "--glesys-username USERNAME",
|
25
|
+
:description => "Your Glesysusername",
|
26
|
+
:proc => Proc.new { |key| Chef::Config[:knife][:glesys_username] = key }
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
def connection
|
31
|
+
@connection ||= begin
|
32
|
+
connection = Fog::Compute.new(
|
33
|
+
:provider => 'Glesys',
|
34
|
+
:glesys_api_key => Chef::Config[:knife][:glesys_api_key],
|
35
|
+
:glesys_username => Chef::Config[:knife][:glesys_username],
|
36
|
+
)
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
def msg_pair(label, value, color=:cyan)
|
41
|
+
if value && !value.to_s.empty?
|
42
|
+
puts "#{ui.color(label, color)}: #{value}"
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
def locate_config_value(key)
|
47
|
+
key = key.to_sym
|
48
|
+
config[key] || Chef::Config[:knife][key]
|
49
|
+
end
|
50
|
+
|
51
|
+
def color_state(state)
|
52
|
+
|
53
|
+
return ui.color("unknown", :cyan) if state.nil?
|
54
|
+
|
55
|
+
case state.to_s.downcase
|
56
|
+
when 'shutting-down','terminated','stopping','stopped' then ui.color(state, :red)
|
57
|
+
when 'pending', 'locked' then ui.color(state, :yellow)
|
58
|
+
else ui.color(state, :green)
|
59
|
+
end
|
60
|
+
|
61
|
+
end
|
62
|
+
|
63
|
+
def validate!
|
64
|
+
end
|
65
|
+
|
66
|
+
end
|
67
|
+
end
|
68
|
+
end
|
@@ -0,0 +1,271 @@
|
|
1
|
+
require "chef/knife/glesys_base"
|
2
|
+
|
3
|
+
class Chef
|
4
|
+
class Knife
|
5
|
+
class GlesysServerCreate < Knife
|
6
|
+
|
7
|
+
include Knife::GlesysBase
|
8
|
+
|
9
|
+
banner "knife glesys server create (options)"
|
10
|
+
|
11
|
+
attr_reader :server
|
12
|
+
|
13
|
+
deps do
|
14
|
+
require 'fog'
|
15
|
+
require 'readline'
|
16
|
+
require 'chef/json_compat'
|
17
|
+
require 'chef/knife/bootstrap'
|
18
|
+
Chef::Knife::Bootstrap.load_deps
|
19
|
+
end
|
20
|
+
|
21
|
+
option :image,
|
22
|
+
:short => "-i IMAGE",
|
23
|
+
:long => "--image IMAGE",
|
24
|
+
:description => "The image to use on the server (Debian 6.0 64-bit, Ubuntu, etc)",
|
25
|
+
:proc => Proc.new { |f| Chef::Config[:knife][:image] = f },
|
26
|
+
:required => true
|
27
|
+
|
28
|
+
option :platform,
|
29
|
+
:short => "-p PLATFORM",
|
30
|
+
:long => "--platform PLATFORM",
|
31
|
+
:description => "The platform to launch the server on (Xen or OpenVZ)",
|
32
|
+
:proc => Proc.new { |f| Chef::Config[:knife][:platform] = f },
|
33
|
+
:required => true
|
34
|
+
|
35
|
+
option :datacenter,
|
36
|
+
:long => "--data-center DATACENTER",
|
37
|
+
:description => "The data center to launch the server in (Falkenberg, New York, Amsterdam or Stockholm)",
|
38
|
+
:proc => Proc.new { |f| Chef::Config[:knife][:datacenter] = f },
|
39
|
+
:required => true
|
40
|
+
|
41
|
+
option :rootpassword,
|
42
|
+
:short => "-P PASSWORD",
|
43
|
+
:long => "--root-password PASSWORD",
|
44
|
+
:description => "Root password to set on the new server",
|
45
|
+
:required => true
|
46
|
+
|
47
|
+
option :hostname,
|
48
|
+
:short => "-h HOSTNAME",
|
49
|
+
:long => "--hostname HOSTNAME",
|
50
|
+
:hostname => "Server hostname",
|
51
|
+
:required => true
|
52
|
+
|
53
|
+
option :cpucores,
|
54
|
+
:long => "--cpu-cores CPUCORES",
|
55
|
+
:description => "The number cpu cores (1-8)",
|
56
|
+
:proc => Proc.new { |f| Chef::Config[:knife][:cpucores] = f }
|
57
|
+
|
58
|
+
option :memorysize,
|
59
|
+
:long => "--memory-size MEMORY",
|
60
|
+
:description => "The amount of memory (128mb - 16384mb)",
|
61
|
+
:proc => Proc.new { |f| Chef::Config[:knife][:memorysize] = f }
|
62
|
+
|
63
|
+
option :disksize,
|
64
|
+
:long => "--disk-size DISK",
|
65
|
+
:description => "The amount of disk (5gb-100gb)",
|
66
|
+
:proc => Proc.new { |f| Chef::Config[:knife][:disksize] = f }
|
67
|
+
|
68
|
+
option :transfer,
|
69
|
+
:long => "--transfer TRANSFER",
|
70
|
+
:description => "Transfer (50gb - 10000gb)",
|
71
|
+
:proc => Proc.new { |f| Chef::Config[:knife][:transfer] = f }
|
72
|
+
|
73
|
+
option :chef_node_name,
|
74
|
+
:short => "-N NAME",
|
75
|
+
:long => "--node-name NAME",
|
76
|
+
:description => "Chef node name",
|
77
|
+
:proc => Proc.new { |f| Chef::Config[:knife][:chef_node_name] = f }
|
78
|
+
|
79
|
+
option :description,
|
80
|
+
:short => "-D DESCRIPTION",
|
81
|
+
:long => "--description DESCRIPTION",
|
82
|
+
:description => "Server description"
|
83
|
+
|
84
|
+
option :ipv4,
|
85
|
+
:long => "--ipv4 IP",
|
86
|
+
:hostname => "IPV4 to assign the server"
|
87
|
+
|
88
|
+
option :ipv6,
|
89
|
+
:long => "--ipv6 IP",
|
90
|
+
:hostname => "IPV6 to assign the server"
|
91
|
+
|
92
|
+
option :run_list,
|
93
|
+
:short => "-r RUN_LIST",
|
94
|
+
:long => "--run-list RUN_LIST",
|
95
|
+
:description => "Comma separated list of roles/recipes to apply",
|
96
|
+
:proc => lambda { |o| o.split(/[\s,]+/) }
|
97
|
+
|
98
|
+
option :ssh_gateway,
|
99
|
+
:short => "-w GATEWAY",
|
100
|
+
:long => "--ssh-gateway GATEWAY",
|
101
|
+
:description => "The SSH gateway server",
|
102
|
+
:proc => Proc.new { |key| Chef::Config[:knife][:ssh_gateway] = key }
|
103
|
+
|
104
|
+
option :ssh_port,
|
105
|
+
:short => "-o PORT",
|
106
|
+
:long => "--ssh-port PORT",
|
107
|
+
:default => "22",
|
108
|
+
:description => "SSH Port",
|
109
|
+
:proc => Proc.new { |key| Chef::Config[:knife][:ssh_port] = key }
|
110
|
+
|
111
|
+
option :json_attributes,
|
112
|
+
:short => "-j JSON",
|
113
|
+
:long => "--json-attributes JSON",
|
114
|
+
:description => "A JSON string to be added to the first run of chef-client",
|
115
|
+
:proc => lambda { |o| JSON.parse(o) }
|
116
|
+
|
117
|
+
def tcp_test_ssh(hostname, ssh_port)
|
118
|
+
tcp_socket = TCPSocket.new(hostname, ssh_port)
|
119
|
+
readable = IO.select([tcp_socket], nil, nil, 5)
|
120
|
+
if readable
|
121
|
+
Chef::Log.debug("sshd accepting connections on #{hostname}, banner is #{tcp_socket.gets}")
|
122
|
+
yield
|
123
|
+
true
|
124
|
+
else
|
125
|
+
false
|
126
|
+
end
|
127
|
+
rescue SocketError, Errno::ECONNREFUSED, Errno::EHOSTUNREACH, Errno::ENETUNREACH, IOError
|
128
|
+
sleep 2
|
129
|
+
false
|
130
|
+
rescue Errno::EPERM, Errno::ETIMEDOUT
|
131
|
+
false
|
132
|
+
ensure
|
133
|
+
tcp_socket && tcp_socket.close
|
134
|
+
end
|
135
|
+
|
136
|
+
def run
|
137
|
+
validate!
|
138
|
+
|
139
|
+
default_server = create_server_def
|
140
|
+
@server = connection.servers.create default_server
|
141
|
+
|
142
|
+
# Show information about the new server
|
143
|
+
msg_pair("Server ID", @server.serverid)
|
144
|
+
msg_pair("State", ui.color(color_state(@server.state),:bold))
|
145
|
+
msg_pair("Hostname", @server.hostname)
|
146
|
+
msg_pair("Description", @server.description)
|
147
|
+
puts "\n"
|
148
|
+
msg_pair("IPv4", @server.iplist.select{|i| i["version"] == 4}.collect{|i| i["ipaddress"]}.join(", "))
|
149
|
+
msg_pair("IPv6", @server.iplist.select{|i| i["version"] == 6}.collect{|i| i["ipaddress"]}.join(", "))
|
150
|
+
puts "\n"
|
151
|
+
msg_pair("CPU Cores", @server.cpucores)
|
152
|
+
msg_pair("Memory", "#{@server.memorysize} MB")
|
153
|
+
msg_pair("Disk", "#{@server.disksize} GB")
|
154
|
+
puts "\n"
|
155
|
+
msg_pair("Image", @server.templatename)
|
156
|
+
msg_pair("Platform", @server.platform)
|
157
|
+
msg_pair("Datacenter", @server.datacenter)
|
158
|
+
|
159
|
+
# Waiting for server to boot
|
160
|
+
print "\nBooting"
|
161
|
+
@server.wait_for{ print "."; ready? }
|
162
|
+
|
163
|
+
# Waiting for sshd to start
|
164
|
+
wait_for_sshd(@server.public_ip_address)
|
165
|
+
|
166
|
+
# Bootstrap the node
|
167
|
+
bootstrap_for_node(@server,@server.public_ip_address).run
|
168
|
+
|
169
|
+
msg_pair("Server ID", @server.serverid)
|
170
|
+
msg_pair("State", ui.color(color_state(@server.state),:bold))
|
171
|
+
msg_pair("Hostname", @server.hostname)
|
172
|
+
msg_pair("Description", @server.description)
|
173
|
+
puts "\n"
|
174
|
+
msg_pair("IPv4", @server.iplist.select{|i| i["version"] == 4}.collect{|i| i["ipaddress"]}.join(", "))
|
175
|
+
msg_pair("IPv6", @server.iplist.select{|i| i["version"] == 6}.collect{|i| i["ipaddress"]}.join(", "))
|
176
|
+
puts "\n"
|
177
|
+
msg_pair("CPU Cores", @server.cpucores)
|
178
|
+
msg_pair("Memory", "#{@server.memorysize} MB")
|
179
|
+
msg_pair("Disk", "#{@server.disksize} GB")
|
180
|
+
puts "\n"
|
181
|
+
msg_pair("Image", @server.templatename)
|
182
|
+
msg_pair("Platform", @server.platform)
|
183
|
+
msg_pair("Datacenter", @server.datacenter)
|
184
|
+
puts "\n"
|
185
|
+
msg_pair("Environment", config[:environment] || '_default')
|
186
|
+
msg_pair("Run List", (config[:run_list] || []).join(', '))
|
187
|
+
msg_pair("JSON Attributes", config[:json_attributes]) unless !config[:json_attributes] || config[:json_attributes].empty?
|
188
|
+
end
|
189
|
+
|
190
|
+
def create_server_def
|
191
|
+
default_server = {
|
192
|
+
templatename: locate_config_value(:image),
|
193
|
+
datacenter: locate_config_value(:datacenter),
|
194
|
+
platform: locate_config_value(:platform),
|
195
|
+
memorysize: locate_config_value(:memorysize),
|
196
|
+
disksize: locate_config_value(:disksize),
|
197
|
+
cpucores: locate_config_value(:cpucores),
|
198
|
+
transfer: locate_config_value(:transfer),
|
199
|
+
description: config[:description],
|
200
|
+
hostname: config[:hostname],
|
201
|
+
rootpassword: config[ :rootpassword ]
|
202
|
+
}
|
203
|
+
|
204
|
+
default_server
|
205
|
+
end
|
206
|
+
|
207
|
+
def bootstrap_for_node(server,ssh_host)
|
208
|
+
bootstrap = Chef::Knife::Bootstrap.new
|
209
|
+
bootstrap.name_args = [ssh_host]
|
210
|
+
bootstrap.config[:run_list] = locate_config_value(:run_list) || []
|
211
|
+
bootstrap.config[:ssh_user] = "root"
|
212
|
+
bootstrap.config[:ssh_port] = config[:ssh_port]
|
213
|
+
bootstrap.config[:ssh_password] = server.rootpassword
|
214
|
+
bootstrap.config[:ssh_gateway] = config[:ssh_gateway]
|
215
|
+
bootstrap.config[:use_sudo] = false
|
216
|
+
# bootstrap.config[:identity_file] = config[:identity_file]
|
217
|
+
bootstrap.config[:chef_node_name] = locate_config_value(:chef_node_name) || server.serverid
|
218
|
+
bootstrap.config[:prerelease] = config[:prerelease]
|
219
|
+
bootstrap.config[:bootstrap_version] = locate_config_value(:bootstrap_version)
|
220
|
+
bootstrap.config[:first_boot_attributes] = locate_config_value(:json_attributes) || {}
|
221
|
+
bootstrap.config[:distro] = locate_config_value(:distro) || "chef-full"
|
222
|
+
bootstrap.config[:template_file] = locate_config_value(:template_file)
|
223
|
+
bootstrap.config[:environment] = config[:environment]
|
224
|
+
|
225
|
+
# knife-bootstrap
|
226
|
+
Chef::Config[:knife][:hints] ||= {}
|
227
|
+
Chef::Config[:knife][:hints]["glesys"] ||= {}
|
228
|
+
bootstrap
|
229
|
+
end
|
230
|
+
|
231
|
+
def wait_for_sshd(hostname)
|
232
|
+
config[:ssh_gateway] ? wait_for_tunnelled_sshd(hostname) : wait_for_direct_sshd(hostname, config[:ssh_port])
|
233
|
+
end
|
234
|
+
|
235
|
+
def wait_for_tunnelled_sshd(hostname)
|
236
|
+
print("\nWaiting for sshd tunnel.")
|
237
|
+
print(".") until tunnel_test_ssh(ssh_connect_host) {
|
238
|
+
sleep @initial_sleep_delay ||= (vpc_mode? ? 40 : 10)
|
239
|
+
puts("done")
|
240
|
+
}
|
241
|
+
end
|
242
|
+
|
243
|
+
def tunnel_test_ssh(hostname, &block)
|
244
|
+
gw_host, gw_user = config[:ssh_gateway].split('@').reverse
|
245
|
+
gw_host, gw_port = gw_host.split(':')
|
246
|
+
gateway = Net::SSH::Gateway.new(gw_host, gw_user, :port => gw_port || 22)
|
247
|
+
status = false
|
248
|
+
gateway.open(hostname, config[:ssh_port]) do |local_tunnel_port|
|
249
|
+
status = tcp_test_ssh('localhost', local_tunnel_port, &block)
|
250
|
+
end
|
251
|
+
status
|
252
|
+
rescue SocketError, Errno::ECONNREFUSED, Errno::EHOSTUNREACH, Errno::ENETUNREACH, IOError
|
253
|
+
sleep 2
|
254
|
+
false
|
255
|
+
rescue Errno::EPERM, Errno::ETIMEDOUT
|
256
|
+
false
|
257
|
+
end
|
258
|
+
|
259
|
+
def wait_for_direct_sshd(hostname, ssh_port)
|
260
|
+
print "\nWaiting for ssh."
|
261
|
+
print(".") until tcp_test_ssh(ssh_connect_host, ssh_port) {
|
262
|
+
puts "done"
|
263
|
+
}
|
264
|
+
end
|
265
|
+
|
266
|
+
def ssh_connect_host
|
267
|
+
@server.public_ip_address
|
268
|
+
end
|
269
|
+
end
|
270
|
+
end
|
271
|
+
end
|
@@ -0,0 +1,110 @@
|
|
1
|
+
require "chef/knife/glesys_base"
|
2
|
+
|
3
|
+
# These two are needed for the '--purge' deletion case
|
4
|
+
require 'chef/node'
|
5
|
+
require 'chef/api_client'
|
6
|
+
|
7
|
+
class Chef
|
8
|
+
class Knife
|
9
|
+
class GlesysServerDelete < Knife
|
10
|
+
|
11
|
+
include Knife::GlesysBase
|
12
|
+
|
13
|
+
banner "knife glesys server delete SERVER [SERVER] (options)"
|
14
|
+
|
15
|
+
deps do
|
16
|
+
require 'fog'
|
17
|
+
require 'readline'
|
18
|
+
Chef::Knife::Bootstrap.load_deps
|
19
|
+
end
|
20
|
+
|
21
|
+
option :purge,
|
22
|
+
:short => "-P",
|
23
|
+
:long => "--purge",
|
24
|
+
:boolean => true,
|
25
|
+
:default => false,
|
26
|
+
:description => "Destroy corresponding node and client on the Chef Server, in addition to destroying the Glesys server itself. Assumes node and client have the same name as the server (if not, add the '--node-name' option)."
|
27
|
+
|
28
|
+
option :keepip,
|
29
|
+
:short => "-i",
|
30
|
+
:long => "--keep-ip",
|
31
|
+
:boolean => true,
|
32
|
+
:default => false,
|
33
|
+
:description => "Don't release the IP"
|
34
|
+
|
35
|
+
option :chef_node_name,
|
36
|
+
:short => "-N NAME",
|
37
|
+
:long => "--node-name NAME",
|
38
|
+
:description => "The name of the node and client to delete, if it differs from the server name. Only has meaning when used with the '--purge' option."
|
39
|
+
|
40
|
+
# Extracted from Chef::Knife.delete_object, because it has a
|
41
|
+
# confirmation step built in... By specifying the '--purge'
|
42
|
+
# flag (and also explicitly confirming the server destruction!)
|
43
|
+
# the user is already making their intent known. It is not
|
44
|
+
# necessary to make them confirm two more times.
|
45
|
+
def destroy_item(klass, name, type_name)
|
46
|
+
begin
|
47
|
+
object = klass.load(name)
|
48
|
+
object.destroy
|
49
|
+
ui.warn("Deleted #{type_name} #{name}")
|
50
|
+
rescue Net::HTTPServerException
|
51
|
+
ui.warn("Could not find a #{type_name} named #{name} to delete!")
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
def run
|
56
|
+
@name_args.each do |server_id|
|
57
|
+
server = connection.servers.get(server_id)
|
58
|
+
puts "\n"
|
59
|
+
msg_pair("Server ID", server.serverid)
|
60
|
+
state = case server.state.to_s.downcase
|
61
|
+
when 'shutting-down','terminated','stopping','stopped' then ui.color(server.state, :red)
|
62
|
+
when 'pending' then ui.color(server.state, :yellow)
|
63
|
+
else ui.color(server.state, :green)
|
64
|
+
end
|
65
|
+
msg_pair("State", ui.color(state,:bold))
|
66
|
+
msg_pair("Hostname", server.hostname)
|
67
|
+
msg_pair("Description", server.description) if server.respond_to? :description # When fog supports description
|
68
|
+
puts "\n"
|
69
|
+
msg_pair("IPv4", server.iplist.select{|i| i["version"] == 4}.collect{|i| i["ipaddress"]}.join(", "))
|
70
|
+
msg_pair("IPv6", server.iplist.select{|i| i["version"] == 6}.collect{|i| i["ipaddress"]}.join(", "))
|
71
|
+
puts "\n"
|
72
|
+
msg_pair("CPU Cores", server.cpucores)
|
73
|
+
msg_pair("Memory", "#{server.memorysize} MB")
|
74
|
+
msg_pair("Disk", "#{server.disksize} GB")
|
75
|
+
puts "\n"
|
76
|
+
msg_pair("Template", server.templatename)
|
77
|
+
msg_pair("Platform", server.platform)
|
78
|
+
msg_pair("Datacenter", server.datacenter)
|
79
|
+
puts "\n"
|
80
|
+
msg_pair("Transfer", "#{server.transfer['usage']} of #{server.transfer['max']} #{server.transfer['unit']}")
|
81
|
+
msg_pair("Cost", "#{server.cost['amount']} #{server.cost['currency']} per #{server.cost['timeperiod']}")
|
82
|
+
|
83
|
+
puts "\n"
|
84
|
+
|
85
|
+
ui.confirm("Do you wan't to delete this server?")
|
86
|
+
|
87
|
+
if config[:keepip]
|
88
|
+
server.keepip = config[:keepip]
|
89
|
+
end
|
90
|
+
|
91
|
+
server.destroy
|
92
|
+
|
93
|
+
ui.warn("Deleted server #{server_id}")
|
94
|
+
|
95
|
+
if config[:purge]
|
96
|
+
thing_to_delete = config[:chef_node_name] || server_id
|
97
|
+
destroy_item(Chef::Node, thing_to_delete, "node")
|
98
|
+
destroy_item(Chef::ApiClient, thing_to_delete, "client")
|
99
|
+
else
|
100
|
+
ui.warn("Corresponding node and client for the #{server_id} server were not deleted and remain registered with the Chef Server")
|
101
|
+
end
|
102
|
+
end
|
103
|
+
|
104
|
+
rescue NoMethodError
|
105
|
+
ui.error("Could not locate server '#{server_id}'.")
|
106
|
+
end
|
107
|
+
|
108
|
+
end
|
109
|
+
end
|
110
|
+
end
|
@@ -0,0 +1,45 @@
|
|
1
|
+
require "chef/knife/glesys_base"
|
2
|
+
|
3
|
+
class Chef
|
4
|
+
class Knife
|
5
|
+
class GlesysServerInfo < Knife
|
6
|
+
|
7
|
+
include Knife::GlesysBase
|
8
|
+
|
9
|
+
banner "knife glesys server info SERVER"
|
10
|
+
|
11
|
+
deps do
|
12
|
+
require 'fog'
|
13
|
+
require 'readline'
|
14
|
+
Chef::Knife::Bootstrap.load_deps
|
15
|
+
end
|
16
|
+
|
17
|
+
def run
|
18
|
+
server = connection.servers.get(@name_args.first)
|
19
|
+
msg_pair("Server ID", server.serverid)
|
20
|
+
msg_pair("State", ui.color(color_state(server.state),:bold))
|
21
|
+
msg_pair("Hostname", server.hostname)
|
22
|
+
msg_pair("Description", server.description) if server.respond_to? :description # When fog supports description
|
23
|
+
puts "\n"
|
24
|
+
msg_pair("IPv4", server.iplist.select{|i| i["version"] == 4}.collect{|i| i["ipaddress"]}.join(", "))
|
25
|
+
msg_pair("IPv6", server.iplist.select{|i| i["version"] == 6}.collect{|i| i["ipaddress"]}.join(", "))
|
26
|
+
puts "\n"
|
27
|
+
msg_pair("CPU Cores", server.cpucores)
|
28
|
+
msg_pair("Memory", "#{server.memorysize} MB")
|
29
|
+
msg_pair("Disk", "#{server.disksize} GB")
|
30
|
+
puts "\n"
|
31
|
+
msg_pair("Image", server.templatename)
|
32
|
+
msg_pair("Platform", server.platform)
|
33
|
+
msg_pair("Datacenter", server.datacenter)
|
34
|
+
puts "\n"
|
35
|
+
msg(ui.color("Current Usage:",:bold))
|
36
|
+
msg_pair("Transfer", "#{ui.color(server.usage['transfer']['usage'].to_s, :yellow)} of #{server.usage['transfer']['max']} #{server.usage['transfer']['unit']}")
|
37
|
+
msg_pair("Memory", "#{ui.color(server.usage['memory']['usage'].to_s, :yellow)} of #{server.usage['memory']['max']} #{server.usage['memory']['unit']}")
|
38
|
+
msg_pair("CPU", "#{ui.color(server.usage['cpu']['usage'].to_s, :yellow)} of #{server.usage['cpu']['max']} #{server.usage['cpu']['unit']}")
|
39
|
+
msg_pair("Disk", "#{ui.color(server.usage['disk']['usage'].to_s, :yellow)} of #{server.usage['disk']['max']} #{server.usage['disk']['unit']}")
|
40
|
+
msg_pair("Cost", "#{ui.color(server.cost['amount'].to_s, :yellow)} #{server.cost['currency']} per #{server.cost['timeperiod']}")
|
41
|
+
end
|
42
|
+
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
@@ -0,0 +1,38 @@
|
|
1
|
+
require "chef/knife/glesys_base"
|
2
|
+
|
3
|
+
class Chef
|
4
|
+
class Knife
|
5
|
+
class GlesysServerList < Knife
|
6
|
+
|
7
|
+
include Knife::GlesysBase
|
8
|
+
|
9
|
+
banner "knife glesys server list"
|
10
|
+
|
11
|
+
deps do
|
12
|
+
require 'fog'
|
13
|
+
require 'readline'
|
14
|
+
Chef::Knife::Bootstrap.load_deps
|
15
|
+
end
|
16
|
+
|
17
|
+
def run
|
18
|
+
|
19
|
+
server_list = [
|
20
|
+
ui.color('ID', :bold),
|
21
|
+
ui.color("Hostname", :bold),
|
22
|
+
ui.color("Platform", :bold),
|
23
|
+
ui.color("Datacenter", :bold),
|
24
|
+
].flatten.compact
|
25
|
+
|
26
|
+
connection.servers.all.each do |server|
|
27
|
+
server_list << server.serverid.to_s
|
28
|
+
server_list << server.hostname
|
29
|
+
server_list << server.platform
|
30
|
+
server_list << server.datacenter
|
31
|
+
end
|
32
|
+
|
33
|
+
puts ui.list(server_list, :columns_across, 4)
|
34
|
+
end
|
35
|
+
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
@@ -0,0 +1,39 @@
|
|
1
|
+
require "chef/knife/glesys_base"
|
2
|
+
|
3
|
+
class Chef
|
4
|
+
class Knife
|
5
|
+
class GlesysTemplateList < Knife
|
6
|
+
include Knife::GlesysBase
|
7
|
+
|
8
|
+
banner "knife glesys template list (options)"
|
9
|
+
|
10
|
+
deps do
|
11
|
+
require 'fog'
|
12
|
+
require 'readline'
|
13
|
+
Chef::Knife::Bootstrap.load_deps
|
14
|
+
end
|
15
|
+
|
16
|
+
def run
|
17
|
+
|
18
|
+
template_list = [
|
19
|
+
ui.color('Platform', :bold),
|
20
|
+
ui.color('Name', :bold),
|
21
|
+
ui.color('Operating System', :bold),
|
22
|
+
ui.color('Min Memory Size', :bold),
|
23
|
+
ui.color('Min Disk Size', :bold),
|
24
|
+
|
25
|
+
]
|
26
|
+
|
27
|
+
connection.templates.sort_by(&:platform).each do |template|
|
28
|
+
template_list << template.platform
|
29
|
+
template_list << template.name
|
30
|
+
template_list << template.operating_system
|
31
|
+
template_list << "#{template.minimum_memory_size} mb"
|
32
|
+
template_list << "#{template.minimum_disk_size} gb"
|
33
|
+
end
|
34
|
+
|
35
|
+
puts ui.list(template_list, :columns_across, 5)
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
metadata
ADDED
@@ -0,0 +1,91 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: knife-glesys
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.0
|
5
|
+
prerelease:
|
6
|
+
platform: ruby
|
7
|
+
authors:
|
8
|
+
- Simon Gate
|
9
|
+
autorequire:
|
10
|
+
bindir: bin
|
11
|
+
cert_chain: []
|
12
|
+
date: 2013-02-27 00:00:00.000000000 Z
|
13
|
+
dependencies:
|
14
|
+
- !ruby/object:Gem::Dependency
|
15
|
+
name: fog
|
16
|
+
requirement: !ruby/object:Gem::Requirement
|
17
|
+
none: false
|
18
|
+
requirements:
|
19
|
+
- - ~>
|
20
|
+
- !ruby/object:Gem::Version
|
21
|
+
version: '1.9'
|
22
|
+
type: :runtime
|
23
|
+
prerelease: false
|
24
|
+
version_requirements: !ruby/object:Gem::Requirement
|
25
|
+
none: false
|
26
|
+
requirements:
|
27
|
+
- - ~>
|
28
|
+
- !ruby/object:Gem::Version
|
29
|
+
version: '1.9'
|
30
|
+
- !ruby/object:Gem::Dependency
|
31
|
+
name: chef
|
32
|
+
requirement: !ruby/object:Gem::Requirement
|
33
|
+
none: false
|
34
|
+
requirements:
|
35
|
+
- - ! '>='
|
36
|
+
- !ruby/object:Gem::Version
|
37
|
+
version: 0.10.10
|
38
|
+
type: :runtime
|
39
|
+
prerelease: false
|
40
|
+
version_requirements: !ruby/object:Gem::Requirement
|
41
|
+
none: false
|
42
|
+
requirements:
|
43
|
+
- - ! '>='
|
44
|
+
- !ruby/object:Gem::Version
|
45
|
+
version: 0.10.10
|
46
|
+
description: Glesys support for Chef's Knife Command
|
47
|
+
email:
|
48
|
+
- simon@smgt.me
|
49
|
+
executables: []
|
50
|
+
extensions: []
|
51
|
+
extra_rdoc_files: []
|
52
|
+
files:
|
53
|
+
- .gitignore
|
54
|
+
- Gemfile
|
55
|
+
- LICENSE.txt
|
56
|
+
- README.md
|
57
|
+
- Rakefile
|
58
|
+
- knife-glesys.gemspec
|
59
|
+
- lib/chef/knife/glesys_base.rb
|
60
|
+
- lib/chef/knife/glesys_server_create.rb
|
61
|
+
- lib/chef/knife/glesys_server_delete.rb
|
62
|
+
- lib/chef/knife/glesys_server_info.rb
|
63
|
+
- lib/chef/knife/glesys_server_list.rb
|
64
|
+
- lib/chef/knife/glesys_template_list.rb
|
65
|
+
- lib/knife-glesys/version.rb
|
66
|
+
homepage: https://github.com/smgt/knife-glesys
|
67
|
+
licenses: []
|
68
|
+
post_install_message:
|
69
|
+
rdoc_options: []
|
70
|
+
require_paths:
|
71
|
+
- lib
|
72
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
73
|
+
none: false
|
74
|
+
requirements:
|
75
|
+
- - ! '>='
|
76
|
+
- !ruby/object:Gem::Version
|
77
|
+
version: '0'
|
78
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
79
|
+
none: false
|
80
|
+
requirements:
|
81
|
+
- - ! '>='
|
82
|
+
- !ruby/object:Gem::Version
|
83
|
+
version: '0'
|
84
|
+
requirements: []
|
85
|
+
rubyforge_project:
|
86
|
+
rubygems_version: 1.8.23
|
87
|
+
signing_key:
|
88
|
+
specification_version: 3
|
89
|
+
summary: Glesys support for Chef's Knife Command
|
90
|
+
test_files: []
|
91
|
+
has_rdoc:
|