kontena-plugin-upcloud 0.3.0 → 0.3.1.rc1
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 +4 -4
- data/lib/kontena/machine/upcloud/client.rb +92 -0
- data/lib/kontena/machine/upcloud/master_provisioner.rb +12 -19
- data/lib/kontena/machine/upcloud/node_destroyer.rb +9 -13
- data/lib/kontena/machine/upcloud/node_provisioner.rb +9 -17
- data/lib/kontena/machine/upcloud/node_restarter.rb +5 -8
- data/lib/kontena/machine/upcloud.rb +1 -1
- data/lib/kontena/plugin/upcloud/master/create_command.rb +6 -30
- data/lib/kontena/plugin/upcloud/nodes/create_command.rb +8 -31
- data/lib/kontena/plugin/upcloud/nodes/restart_command.rb +6 -3
- data/lib/kontena/plugin/upcloud/nodes/terminate_command.rb +4 -3
- data/lib/kontena/plugin/upcloud/prompts.rb +99 -0
- data/lib/kontena/plugin/upcloud.rb +1 -17
- metadata +6 -5
- data/lib/kontena/machine/upcloud/upcloud_common.rb +0 -72
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: aa71abdd5e6d879f8868bfb1e14f669a5879d197
|
4
|
+
data.tar.gz: 35cd56ca6f880a201813cfc4ed2724c01a84cbd8
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 5c82aabaaa2c8b6f97d0ad708590e67178aede22b22955d8e1aa7c4320951b7c3b1ea730dafc7a019bb7176aed4f46905439685a4837be72bc8551d2d60fa8a3
|
7
|
+
data.tar.gz: 0791e9666f8b9fad40fb3b6558046b1c4cbd0004cc0fc5e9772f841db61aa33c5b22356a1d6e7e13d6c770a4ab897459ba2834c10d190fe202c93e06feea3082
|
@@ -0,0 +1,92 @@
|
|
1
|
+
require 'excon'
|
2
|
+
require 'json'
|
3
|
+
|
4
|
+
module Kontena
|
5
|
+
module Machine
|
6
|
+
module Upcloud
|
7
|
+
class Client
|
8
|
+
|
9
|
+
API_URL = 'https://api.upcloud.com'.freeze
|
10
|
+
ACCEPT = 'Accept'.freeze
|
11
|
+
CTYPE = 'Content-Type'.freeze
|
12
|
+
APP_JSON = 'application/json'.freeze
|
13
|
+
CTYPE_HEAD = { CTYPE => APP_JSON }
|
14
|
+
|
15
|
+
attr_reader :http_client
|
16
|
+
|
17
|
+
def initialize(username, password)
|
18
|
+
@http_client = Excon.new(
|
19
|
+
API_URL,
|
20
|
+
omit_default_port: true,
|
21
|
+
user: username,
|
22
|
+
password: password,
|
23
|
+
)
|
24
|
+
end
|
25
|
+
|
26
|
+
def get(path)
|
27
|
+
request(method: :get, path: path)
|
28
|
+
end
|
29
|
+
|
30
|
+
def post(path, body)
|
31
|
+
request(method: :post, path: path, body: body, headers: CTYPE_HEAD)
|
32
|
+
end
|
33
|
+
|
34
|
+
def delete(path)
|
35
|
+
request(method: :delete, path: path)
|
36
|
+
end
|
37
|
+
|
38
|
+
def find_template(name)
|
39
|
+
get('storage/template')[:storages][:storage].find{|s| s[:title].downcase.start_with?(name.downcase)}
|
40
|
+
end
|
41
|
+
|
42
|
+
def find_plan(name)
|
43
|
+
list_plans.find{|s| s[:name].downcase.eql?(name.downcase)}
|
44
|
+
end
|
45
|
+
|
46
|
+
def list_plans
|
47
|
+
get('plan')[:plans][:plan]
|
48
|
+
end
|
49
|
+
|
50
|
+
def list_zones
|
51
|
+
get('zone')[:zones][:zone]
|
52
|
+
end
|
53
|
+
|
54
|
+
def zone_exist?(name)
|
55
|
+
list_zones.any? { |zone| zone[:id] == name }
|
56
|
+
end
|
57
|
+
|
58
|
+
def get_server(id)
|
59
|
+
get("server/#{id}").fetch(:server, nil)
|
60
|
+
end
|
61
|
+
|
62
|
+
def api_access?
|
63
|
+
response = get('account')
|
64
|
+
response.kind_of?(Hash) && response.has_key?(:account)
|
65
|
+
rescue
|
66
|
+
false
|
67
|
+
end
|
68
|
+
|
69
|
+
private
|
70
|
+
|
71
|
+
def request(opts)
|
72
|
+
response = http_client.request(
|
73
|
+
opts.merge(
|
74
|
+
path: "/1.2/#{opts[:path]}",
|
75
|
+
headers: (opts[:headers] || {}).merge(ACCEPT => APP_JSON),
|
76
|
+
)
|
77
|
+
)
|
78
|
+
|
79
|
+
if (200..299).cover?(response.status)
|
80
|
+
if response.body && response.body.start_with?('{'.freeze)
|
81
|
+
JSON.parse(response.body, symbolize_names: true)
|
82
|
+
else
|
83
|
+
{ success: true }
|
84
|
+
end
|
85
|
+
else
|
86
|
+
raise "Request to Upcloud failed: #{response.status} #{response.body}"
|
87
|
+
end
|
88
|
+
end
|
89
|
+
end
|
90
|
+
end
|
91
|
+
end
|
92
|
+
end
|
@@ -9,23 +9,17 @@ module Kontena
|
|
9
9
|
class MasterProvisioner
|
10
10
|
include RandomName
|
11
11
|
include Machine::CertHelper
|
12
|
-
include UpcloudCommon
|
13
12
|
include Kontena::Cli::Common
|
14
13
|
|
15
|
-
attr_reader :http_client, :
|
14
|
+
attr_reader :http_client, :uc_client
|
16
15
|
|
17
16
|
# @param [String] token Upcloud token
|
18
17
|
def initialize(upcloud_username, upcloud_password)
|
19
|
-
@
|
20
|
-
@password = upcloud_password
|
18
|
+
@uc_client = Kontena::Machine::Upcloud::Client.new(upcloud_username, upcloud_password)
|
21
19
|
end
|
22
20
|
|
23
21
|
def run!(opts)
|
24
|
-
|
25
|
-
ssh_key = File.read(File.expand_path(opts[:ssh_key])).strip
|
26
|
-
end
|
27
|
-
|
28
|
-
abort('Invalid ssh key') unless ssh_key && ssh_key.start_with?('ssh-')
|
22
|
+
abort('Invalid ssh key') unless opts[:ssh_key].to_s.start_with?('ssh-')
|
29
23
|
|
30
24
|
if opts[:ssl_cert]
|
31
25
|
abort('Invalid ssl cert') unless File.exists?(File.expand_path(opts[:ssl_cert]))
|
@@ -36,11 +30,9 @@ module Kontena
|
|
36
30
|
end
|
37
31
|
end
|
38
32
|
|
39
|
-
|
40
|
-
|
41
|
-
abort('
|
42
|
-
abort('Server plan not found on Upcloud') unless plan = find_plan(opts[:plan])
|
43
|
-
abort('Zone not found on Upcloud') unless zone_exist?(opts[:zone])
|
33
|
+
abort('CoreOS template not found on Upcloud') unless coreos_template = uc_client.find_template('CoreOS Stable')
|
34
|
+
abort('Server plan not found on Upcloud') unless plan = uc_client.find_plan(opts[:plan])
|
35
|
+
abort('Zone not found on Upcloud') unless uc_client.zone_exist?(opts[:zone])
|
44
36
|
|
45
37
|
if opts[:name]
|
46
38
|
server_name = opts[:name]
|
@@ -61,7 +53,7 @@ module Kontena
|
|
61
53
|
device_data = {
|
62
54
|
server: {
|
63
55
|
zone: opts[:zone],
|
64
|
-
title:
|
56
|
+
title: hostname,
|
65
57
|
hostname: hostname,
|
66
58
|
plan: plan[:name],
|
67
59
|
vnc: 'off',
|
@@ -83,21 +75,21 @@ module Kontena
|
|
83
75
|
create_password: 'no',
|
84
76
|
username: 'root',
|
85
77
|
ssh_keys: {
|
86
|
-
ssh_key: [ssh_key]
|
78
|
+
ssh_key: [opts[:ssh_key]]
|
87
79
|
}
|
88
80
|
}
|
89
81
|
}
|
90
82
|
}.to_json
|
91
83
|
|
92
84
|
spinner "Creating an Upcloud server #{hostname.colorize(:cyan)} " do
|
93
|
-
response = post('server',
|
85
|
+
response = uc_client.post('server', device_data)
|
94
86
|
if response.has_key?(:error)
|
95
87
|
abort("\nUpcloud server creation failed (#{response[:error].fetch(:error_message, '')})")
|
96
88
|
end
|
97
89
|
device_data = response[:server]
|
98
90
|
|
99
91
|
until device_data && device_data.fetch(:state, nil).to_s == 'maintenance'
|
100
|
-
device_data = get("server/#{device[:uuid]}").fetch(:server, {}) rescue nil
|
92
|
+
device_data = uc_client.get("server/#{device[:uuid]}").fetch(:server, {}) rescue nil
|
101
93
|
sleep 5
|
102
94
|
end
|
103
95
|
end
|
@@ -128,7 +120,8 @@ module Kontena
|
|
128
120
|
public_ip: device_public_ip[:address],
|
129
121
|
provider: 'upcloud',
|
130
122
|
version: master_version,
|
131
|
-
code: opts[:initial_admin_code]
|
123
|
+
code: opts[:initial_admin_code],
|
124
|
+
ssl_certificate: (respond_to?(:certificate_public_key) && !opts[:ssl_cert]) ? certificate_public_key(ssl_cert) : nil
|
132
125
|
}
|
133
126
|
end
|
134
127
|
|
@@ -3,24 +3,20 @@ module Kontena
|
|
3
3
|
module Upcloud
|
4
4
|
class NodeDestroyer
|
5
5
|
include RandomName
|
6
|
-
include UpcloudCommon
|
7
6
|
include Kontena::Cli::ShellSpinner
|
8
7
|
|
9
|
-
attr_reader :api_client, :
|
8
|
+
attr_reader :api_client, :uc_client
|
10
9
|
|
11
10
|
# @param [Kontena::Client] api_client Kontena api client
|
12
11
|
# @param [String] token Upcloud token
|
13
12
|
def initialize(api_client, upcloud_username, upcloud_password)
|
14
13
|
@api_client = api_client
|
15
|
-
@
|
16
|
-
@password = upcloud_password
|
14
|
+
@uc_client = Kontena::Machine::Upcloud::Client.new(upcloud_username, upcloud_password)
|
17
15
|
end
|
18
16
|
|
19
17
|
def run!(grid, name)
|
20
18
|
|
21
|
-
|
22
|
-
|
23
|
-
servers = get('server')
|
19
|
+
servers = uc_client.get('server')
|
24
20
|
unless servers && servers.has_key?(:servers)
|
25
21
|
abort('Upcloud API error')
|
26
22
|
end
|
@@ -29,7 +25,7 @@ module Kontena
|
|
29
25
|
|
30
26
|
abort "Cannot find node #{name.colorize(:cyan)} in UpCloud" unless server
|
31
27
|
|
32
|
-
server_data = get("server/#{server[:uuid]}")
|
28
|
+
server_data = uc_client.get("server/#{server[:uuid]}")
|
33
29
|
|
34
30
|
storage_devices = server_data.fetch(:server, {}).fetch(:storage_devices, {}).fetch(:storage_device, [])
|
35
31
|
storage_uuids = storage_devices.map{|s| s[:storage]}
|
@@ -39,8 +35,8 @@ module Kontena
|
|
39
35
|
if server
|
40
36
|
unless server[:state].eql?('stopped')
|
41
37
|
spinner "Shutting down UpCloud node #{name.colorize(:cyan)} " do
|
42
|
-
device_data = post(
|
43
|
-
"server/#{server[:uuid]}/stop",
|
38
|
+
device_data = uc_client.post(
|
39
|
+
"server/#{server[:uuid]}/stop", {
|
44
40
|
stop_server: {
|
45
41
|
stop_type: 'soft',
|
46
42
|
timeout: 120
|
@@ -49,20 +45,20 @@ module Kontena
|
|
49
45
|
)
|
50
46
|
|
51
47
|
until device_data && device_data.fetch(:state, nil).to_s.eql?('stopped')
|
52
|
-
device_data = get("server/#{server[:uuid]}").fetch(:server, {}) rescue nil
|
48
|
+
device_data = uc_client.get("server/#{server[:uuid]}").fetch(:server, {}) rescue nil
|
53
49
|
sleep 5
|
54
50
|
end
|
55
51
|
end
|
56
52
|
end
|
57
53
|
|
58
54
|
spinner "Terminating UpCloud node #{name.colorize(:cyan)} " do
|
59
|
-
response = delete("server/#{server[:uuid]}")
|
55
|
+
response = uc_client.delete("server/#{server[:uuid]}")
|
60
56
|
abort "Cannot delete node #{name.colorize(:cyan)} in Upcloud" unless response[:success]
|
61
57
|
end
|
62
58
|
|
63
59
|
storage_uuids.each do |uuid|
|
64
60
|
spinner "Deleting UpCloud storage device '#{uuid.colorize(:cyan)}' " do
|
65
|
-
response = delete("storage/#{uuid}")
|
61
|
+
response = uc_client.delete("storage/#{uuid}")
|
66
62
|
unless response[:success]
|
67
63
|
puts "#{"WARNING".colorize(:red)}: Couldn't delete UpCloud storage '#{uuid.colorize(:cyan)}', check manually."
|
68
64
|
end
|
@@ -7,26 +7,20 @@ module Kontena
|
|
7
7
|
module Upcloud
|
8
8
|
class NodeProvisioner
|
9
9
|
include RandomName
|
10
|
-
include UpcloudCommon
|
11
10
|
include Kontena::Cli::ShellSpinner
|
12
11
|
|
13
|
-
attr_reader :api_client, :
|
12
|
+
attr_reader :api_client, :uc_client
|
14
13
|
|
15
14
|
# @param [Kontena::Client] api_client Kontena api client
|
16
15
|
# @param [String] upcloud_username Upcloud username
|
17
16
|
# @param [String] upcloud_password Upcloud password
|
18
17
|
def initialize(api_client, upcloud_username, upcloud_password)
|
19
18
|
@api_client = api_client
|
20
|
-
@
|
21
|
-
@password = upcloud_password
|
19
|
+
@uc_client = Kontena::Machine::Upcloud::Client.new(upcloud_username, upcloud_password)
|
22
20
|
end
|
23
21
|
|
24
22
|
def run!(opts)
|
25
|
-
|
26
|
-
ssh_key = File.read(File.expand_path(opts[:ssh_key])).strip
|
27
|
-
end
|
28
|
-
|
29
|
-
abort('Invalid ssh key') unless ssh_key && ssh_key.start_with?('ssh-')
|
23
|
+
abort('Invalid ssh key') unless opts[:ssh_key].to_s.start_with?('ssh-')
|
30
24
|
|
31
25
|
count = opts[:count].to_i
|
32
26
|
userdata_vars = {
|
@@ -35,11 +29,9 @@ module Kontena
|
|
35
29
|
grid_token: opts[:grid_token],
|
36
30
|
}
|
37
31
|
|
38
|
-
|
39
|
-
|
40
|
-
abort('
|
41
|
-
abort('Server plan not found on Upcloud') unless plan = find_plan(opts[:plan])
|
42
|
-
abort('Zone not found on Upcloud') unless zone_exist?(opts[:zone])
|
32
|
+
abort('CoreOS template not found on Upcloud') unless coreos_template = uc_client.find_template('CoreOS Stable')
|
33
|
+
abort('Server plan not found on Upcloud') unless plan = uc_client.find_plan(opts[:plan])
|
34
|
+
abort('Zone not found on Upcloud') unless uc_client.zone_exist?(opts[:zone])
|
43
35
|
|
44
36
|
count.times do |i|
|
45
37
|
if opts[:name]
|
@@ -72,14 +64,14 @@ module Kontena
|
|
72
64
|
create_password: 'no',
|
73
65
|
username: 'root',
|
74
66
|
ssh_keys: {
|
75
|
-
ssh_key: [ssh_key]
|
67
|
+
ssh_key: [opts[:ssh_key]]
|
76
68
|
}
|
77
69
|
}
|
78
70
|
}
|
79
71
|
}.to_json
|
80
72
|
|
81
73
|
spinner "Creating UpCloud node #{hostname.colorize(:cyan)} " do
|
82
|
-
response = post('server',
|
74
|
+
response = uc_client.post('server', device_data)
|
83
75
|
|
84
76
|
if response.has_key?(:error)
|
85
77
|
abort("\nUpCloud server creation failed (#{response[:error].fetch(:error_message, '')})")
|
@@ -87,7 +79,7 @@ module Kontena
|
|
87
79
|
device_data = response[:server]
|
88
80
|
|
89
81
|
until device_data && device_data.fetch(:state, nil).to_s == 'maintenance'
|
90
|
-
device_data = get("server/#{device[:uuid]}").fetch(:server, {}) rescue nil
|
82
|
+
device_data = uc_client.get("server/#{device[:uuid]}").fetch(:server, {}) rescue nil
|
91
83
|
sleep 5
|
92
84
|
end
|
93
85
|
end
|
@@ -3,22 +3,19 @@ module Kontena
|
|
3
3
|
module Upcloud
|
4
4
|
class NodeRestarter
|
5
5
|
include RandomName
|
6
|
-
include UpcloudCommon
|
7
6
|
include Kontena::Cli::ShellSpinner
|
8
7
|
|
9
|
-
attr_reader :
|
8
|
+
attr_reader :uc_client
|
10
9
|
|
11
10
|
# @param [String] upcloud_username Upcloud username
|
12
11
|
# @param [String] upcloud_password Upcloud password
|
13
12
|
def initialize(upcloud_username, upcloud_password)
|
14
|
-
@
|
15
|
-
@password = upcloud_password
|
13
|
+
@uc_client = Kontena::Machine::Upcloud::Client.new(upcloud_username, upcloud_password)
|
16
14
|
end
|
17
15
|
|
18
16
|
def run!(name)
|
19
|
-
abort_unless_api_access
|
20
17
|
|
21
|
-
servers = get('server')
|
18
|
+
servers = uc_client.get('server')
|
22
19
|
unless servers && servers.has_key?(:servers)
|
23
20
|
abort('Upcloud API error')
|
24
21
|
end
|
@@ -27,8 +24,8 @@ module Kontena
|
|
27
24
|
|
28
25
|
if server
|
29
26
|
spinner "Restarting UpCloud node #{name.colorize(:cyan)} " do
|
30
|
-
result = post(
|
31
|
-
"server/#{server[:uuid]}/restart",
|
27
|
+
result = uc_client.post(
|
28
|
+
"server/#{server[:uuid]}/restart", {
|
32
29
|
restart_server: {
|
33
30
|
stop_type: 'soft',
|
34
31
|
timeout: 600,
|
@@ -1,6 +1,6 @@
|
|
1
1
|
require 'kontena/machine/random_name'
|
2
2
|
require 'kontena/machine/cert_helper'
|
3
|
-
require_relative 'upcloud/
|
3
|
+
require_relative 'upcloud/client'
|
4
4
|
require_relative 'upcloud/node_provisioner'
|
5
5
|
require_relative 'upcloud/node_destroyer'
|
6
6
|
require_relative 'upcloud/node_restarter'
|
@@ -1,24 +1,24 @@
|
|
1
1
|
require 'securerandom'
|
2
|
+
require 'kontena/plugin/upcloud/prompts'
|
2
3
|
|
3
4
|
module Kontena::Plugin::Upcloud::Master
|
4
5
|
class CreateCommand < Kontena::Command
|
5
6
|
include Kontena::Cli::Common
|
6
7
|
|
7
8
|
option "--name", "[NAME]", "Set Kontena Master name"
|
8
|
-
|
9
|
-
|
10
|
-
|
9
|
+
|
10
|
+
include Kontena::Plugin::Upcloud::Prompts::Create
|
11
|
+
|
11
12
|
option "--ssl-cert", "SSL CERT", "SSL certificate file (optional)"
|
12
|
-
option "--plan", "PLAN", "Server plan", required: true
|
13
|
-
option "--zone", "ZONE", "Zone", required: true
|
14
13
|
option "--vault-secret", "VAULT_SECRET", "Secret key for Vault (optional)"
|
15
14
|
option "--vault-iv", "VAULT_IV", "Initialization vector for Vault (optional)"
|
16
15
|
option "--mongodb-uri", "URI", "External MongoDB uri (optional)"
|
17
|
-
option "--version", "VERSION", "Define installed Kontena version", default: 'latest'
|
18
16
|
|
19
17
|
def execute
|
20
18
|
require_relative '../../../machine/upcloud'
|
21
19
|
|
20
|
+
abort_unless_api_access
|
21
|
+
|
22
22
|
provisioner.run!(
|
23
23
|
name: self.name,
|
24
24
|
ssh_key: ssh_key,
|
@@ -36,29 +36,5 @@ module Kontena::Plugin::Upcloud::Master
|
|
36
36
|
def provisioner
|
37
37
|
Kontena::Machine::Upcloud::MasterProvisioner.new(username, password)
|
38
38
|
end
|
39
|
-
|
40
|
-
def default_username
|
41
|
-
prompt.ask('UpCloud username:', echo: true)
|
42
|
-
end
|
43
|
-
|
44
|
-
def default_password
|
45
|
-
prompt.ask('UpCloud password:', echo: false)
|
46
|
-
end
|
47
|
-
|
48
|
-
def default_plan
|
49
|
-
prompt.select("Choose plan:") do |menu|
|
50
|
-
Kontena::Plugin::Upcloud::PLANS.each do |plan, name|
|
51
|
-
menu.choice name, plan
|
52
|
-
end
|
53
|
-
end
|
54
|
-
end
|
55
|
-
|
56
|
-
def default_zone
|
57
|
-
prompt.select("Choose availability zone:") do |menu|
|
58
|
-
Kontena::Plugin::Upcloud::ZONES.each do |zone, name|
|
59
|
-
menu.choice name, zone
|
60
|
-
end
|
61
|
-
end
|
62
|
-
end
|
63
39
|
end
|
64
40
|
end
|
@@ -1,21 +1,23 @@
|
|
1
|
+
require 'kontena/plugin/upcloud/prompts'
|
2
|
+
|
1
3
|
module Kontena::Plugin::Upcloud::Nodes
|
2
4
|
class CreateCommand < Kontena::Command
|
3
5
|
include Kontena::Cli::Common
|
4
6
|
include Kontena::Cli::GridOptions
|
5
7
|
|
6
8
|
parameter "[NAME]", "Node name"
|
7
|
-
|
8
|
-
|
9
|
-
|
9
|
+
|
10
|
+
include Kontena::Plugin::Upcloud::Prompts::Create
|
11
|
+
|
10
12
|
option "--count", "COUNT", "How many nodes should be created"
|
11
|
-
option "--zone", "ZONE", "Zone", required: true
|
12
|
-
option "--plan", "PLAN", "Server size", required: true
|
13
|
-
option "--version", "VERSION", "Define installed Kontena version", default: 'latest'
|
14
13
|
|
15
14
|
requires_current_master_token
|
16
15
|
|
17
16
|
def execute
|
18
17
|
require_relative '../../../machine/upcloud'
|
18
|
+
|
19
|
+
abort_unless_api_access
|
20
|
+
|
19
21
|
grid = fetch_grid
|
20
22
|
provisioner = Kontena::Machine::Upcloud::NodeProvisioner.new(client, username, password)
|
21
23
|
provisioner.run!(
|
@@ -37,33 +39,8 @@ module Kontena::Plugin::Upcloud::Nodes
|
|
37
39
|
client.get("grids/#{current_grid}")
|
38
40
|
end
|
39
41
|
|
40
|
-
|
41
|
-
def default_username
|
42
|
-
prompt.ask('UpCloud username:', echo: true)
|
43
|
-
end
|
44
|
-
|
45
|
-
def default_password
|
46
|
-
prompt.ask('UpCloud password:', echo: false)
|
47
|
-
end
|
48
|
-
|
49
42
|
def default_count
|
50
43
|
prompt.ask('How many servers:', default: 1)
|
51
44
|
end
|
52
|
-
|
53
|
-
def default_plan
|
54
|
-
prompt.select("Choose plan:") do |menu|
|
55
|
-
Kontena::Plugin::Upcloud::PLANS.each do |plan, name|
|
56
|
-
menu.choice name, plan
|
57
|
-
end
|
58
|
-
end
|
59
|
-
end
|
60
|
-
|
61
|
-
def default_zone
|
62
|
-
prompt.select("Choose availability zone:") do |menu|
|
63
|
-
Kontena::Plugin::Upcloud::ZONES.each do |zone, name|
|
64
|
-
menu.choice name, zone
|
65
|
-
end
|
66
|
-
end
|
67
|
-
end
|
68
45
|
end
|
69
46
|
end
|
@@ -1,16 +1,19 @@
|
|
1
|
+
require 'kontena/plugin/upcloud/prompts'
|
2
|
+
|
1
3
|
module Kontena::Plugin::Upcloud::Nodes
|
2
4
|
class RestartCommand < Kontena::Command
|
3
5
|
include Kontena::Cli::Common
|
4
6
|
include Kontena::Cli::GridOptions
|
5
7
|
|
6
|
-
|
7
|
-
|
8
|
-
option "--password", "PASS", "Upcloud password", required: true, environment_variable: 'UPCLOUD_PASSWORD'
|
8
|
+
include Kontena::Plugin::Upcloud::Prompts::NodeName
|
9
|
+
include Kontena::Plugin::Upcloud::Prompts::Common
|
9
10
|
|
10
11
|
def execute
|
11
12
|
require_api_url
|
12
13
|
require_current_grid
|
13
14
|
|
15
|
+
abort_unless_api_access
|
16
|
+
|
14
17
|
require 'kontena/machine/upcloud'
|
15
18
|
|
16
19
|
restarter = Kontena::Machine::Upcloud::NodeRestarter.new(username, password)
|
@@ -1,17 +1,18 @@
|
|
1
|
+
require 'kontena/plugin/upcloud/prompts'
|
1
2
|
module Kontena::Plugin::Upcloud::Nodes
|
2
3
|
class TerminateCommand < Kontena::Command
|
3
4
|
include Kontena::Cli::Common
|
4
5
|
include Kontena::Cli::GridOptions
|
5
6
|
|
6
|
-
|
7
|
-
|
8
|
-
option "--password", "PASS", "Upcloud password", required: true, environment_variable: 'UPCLOUD_PASSWORD'
|
7
|
+
include Kontena::Plugin::Upcloud::Prompts::NodeName
|
8
|
+
include Kontena::Plugin::Upcloud::Prompts::Common
|
9
9
|
|
10
10
|
option '--force', :flag, "Force terminate", attribute_name: :forced
|
11
11
|
|
12
12
|
requires_current_master_token
|
13
13
|
|
14
14
|
def execute
|
15
|
+
abort_unless_api_access
|
15
16
|
require_relative '../../../machine/upcloud'
|
16
17
|
confirm_command(name) unless forced?
|
17
18
|
grid = client.get("grids/#{current_grid}")
|
@@ -0,0 +1,99 @@
|
|
1
|
+
require 'kontena/machine/upcloud/client'
|
2
|
+
|
3
|
+
module Kontena
|
4
|
+
module Plugin
|
5
|
+
module Upcloud
|
6
|
+
module Prompts
|
7
|
+
module Common
|
8
|
+
def self.included(base)
|
9
|
+
base.prepend Defaults
|
10
|
+
base.option "--username", "USER", "Upcloud username", required: true, environment_variable: 'UPCLOUD_USERNAME'
|
11
|
+
base.option "--password", "PASS", "Upcloud password", required: true, environment_variable: 'UPCLOUD_PASSWORD'
|
12
|
+
end
|
13
|
+
|
14
|
+
def upcloud_client
|
15
|
+
@upcloud_client ||= Kontena::Machine::Upcloud::Client.new(username, password)
|
16
|
+
end
|
17
|
+
|
18
|
+
def abort_unless_api_access
|
19
|
+
unless upcloud_client.api_access?
|
20
|
+
exit_with_error('Upcloud API authentication failed. Check that API access is enabled for the user.')
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
module Defaults
|
25
|
+
def default_username
|
26
|
+
prompt.ask('UpCloud username:', echo: true)
|
27
|
+
end
|
28
|
+
|
29
|
+
def default_password
|
30
|
+
pass = prompt.ask('UpCloud password:', echo: false)
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
module NodeName
|
36
|
+
def self.included(base)
|
37
|
+
base.prepend Defaults
|
38
|
+
base.parameter "[NAME]", "Node name"
|
39
|
+
end
|
40
|
+
|
41
|
+
module Defaults
|
42
|
+
def default_name
|
43
|
+
nodes = client.get("grids/#{current_grid}/nodes")
|
44
|
+
nodes = nodes['nodes'].select{ |n|
|
45
|
+
n['labels'] && n['labels'].include?('provider=upcloud'.freeze)
|
46
|
+
}
|
47
|
+
raise "Did not find any nodes with label provider=upcloud" if nodes.empty?
|
48
|
+
prompt.select("Select node:") do |menu|
|
49
|
+
nodes.sort_by{|n| n['node_number'] }.reverse.each do |node|
|
50
|
+
initial = node['initial_member'] ? '(initial) ' : ''
|
51
|
+
menu.choice "#{node['name']} #{initial}", node['name']
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
module Create
|
59
|
+
def self.included(base)
|
60
|
+
base.include Common
|
61
|
+
base.prepend Defaults
|
62
|
+
base.option "--ssh-key", "SSH_KEY", "Path to ssh public key", attribute_name: :ssh_key_path
|
63
|
+
base.option "--version", "VERSION", "Define installed Kontena version", default: 'latest'
|
64
|
+
base.option "--zone", "ZONE", "Zone", required: true
|
65
|
+
base.option "--plan", "PLAN", "Server size", required: true
|
66
|
+
end
|
67
|
+
|
68
|
+
def ssh_key
|
69
|
+
return File.read(ssh_key_path) unless ssh_key_path.nil?
|
70
|
+
default = File.read(Defaults::DEFAULT_SSH_KEY_PATH).strip rescue nil
|
71
|
+
prompt.ask('SSH public key: (enter an ssh key in OpenSSH format "ssh-xxx xxxxx key_name")', default: default) do |q|
|
72
|
+
q.validate /^ssh-rsa \S+ \S+$/
|
73
|
+
end
|
74
|
+
end
|
75
|
+
|
76
|
+
module Defaults
|
77
|
+
DEFAULT_SSH_KEY_PATH = File.join(Dir.home, '.ssh', 'id_rsa.pub')
|
78
|
+
|
79
|
+
def default_plan
|
80
|
+
prompt.select("Choose plan:") do |menu|
|
81
|
+
upcloud_client.list_plans.each do |plan|
|
82
|
+
menu.choice "#{plan[:name]} (#{plan[:memory_amount]}MB #{plan[:storage_size]}GB #{plan[:storage_tier]})", plan[:name]
|
83
|
+
end
|
84
|
+
end
|
85
|
+
end
|
86
|
+
|
87
|
+
def default_zone
|
88
|
+
prompt.select("Choose availability zone:") do |menu|
|
89
|
+
upcloud_client.list_zones.each do |zone|
|
90
|
+
menu.choice zone[:description], zone[:id]
|
91
|
+
end
|
92
|
+
end
|
93
|
+
end
|
94
|
+
end
|
95
|
+
end
|
96
|
+
end
|
97
|
+
end
|
98
|
+
end
|
99
|
+
end
|
@@ -1,23 +1,7 @@
|
|
1
1
|
module Kontena
|
2
2
|
module Plugin
|
3
3
|
module Upcloud
|
4
|
-
VERSION = "0.3.
|
5
|
-
|
6
|
-
ZONES = {
|
7
|
-
'nl-ams1' => 'Amsterdam #1',
|
8
|
-
'us-chi1' => 'Chicago #1',
|
9
|
-
'de-fra1' => 'Frankfurt #1',
|
10
|
-
'fi-hel1' => 'Helsinki #1',
|
11
|
-
'uk-lon1' => 'London #1',
|
12
|
-
'sg-sin1' => 'Singapore #1'
|
13
|
-
}.freeze
|
14
|
-
|
15
|
-
PLANS = {
|
16
|
-
'1xCPU-1GB' => '1024MB / 1 CPU, 30GB MaxIOPS disk, 2048GB transfer',
|
17
|
-
'2xCPU-2GB' => '2048MB / 2 CPU, 50GB MaxIOPS disk, 3072GB transfer',
|
18
|
-
'4xCPU-4GB' => '4096MB / 4 CPU, 100GB MaxIOPS disk, 4096GB transfer',
|
19
|
-
'6xCPU-8GB' => '8192MB / 6 CPU, 200GB MaxIOPS disk, 8192GB transfer'
|
20
|
-
}.freeze
|
4
|
+
VERSION = "0.3.1.rc1"
|
21
5
|
end
|
22
6
|
end
|
23
7
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: kontena-plugin-upcloud
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.3.
|
4
|
+
version: 0.3.1.rc1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Kontena, Inc.
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2017-07
|
11
|
+
date: 2017-08-07 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: kontena-cli
|
@@ -67,13 +67,13 @@ files:
|
|
67
67
|
- README.md
|
68
68
|
- kontena-plugin-upcloud.gemspec
|
69
69
|
- lib/kontena/machine/upcloud.rb
|
70
|
+
- lib/kontena/machine/upcloud/client.rb
|
70
71
|
- lib/kontena/machine/upcloud/cloudinit.yml
|
71
72
|
- lib/kontena/machine/upcloud/cloudinit_master.yml
|
72
73
|
- lib/kontena/machine/upcloud/master_provisioner.rb
|
73
74
|
- lib/kontena/machine/upcloud/node_destroyer.rb
|
74
75
|
- lib/kontena/machine/upcloud/node_provisioner.rb
|
75
76
|
- lib/kontena/machine/upcloud/node_restarter.rb
|
76
|
-
- lib/kontena/machine/upcloud/upcloud_common.rb
|
77
77
|
- lib/kontena/plugin/upcloud.rb
|
78
78
|
- lib/kontena/plugin/upcloud/master/create_command.rb
|
79
79
|
- lib/kontena/plugin/upcloud/master_command.rb
|
@@ -81,6 +81,7 @@ files:
|
|
81
81
|
- lib/kontena/plugin/upcloud/nodes/create_command.rb
|
82
82
|
- lib/kontena/plugin/upcloud/nodes/restart_command.rb
|
83
83
|
- lib/kontena/plugin/upcloud/nodes/terminate_command.rb
|
84
|
+
- lib/kontena/plugin/upcloud/prompts.rb
|
84
85
|
- lib/kontena/plugin/upcloud_command.rb
|
85
86
|
- lib/kontena_cli_plugin.rb
|
86
87
|
homepage: https://github.com/kontena/kontena-plugin-upcloud
|
@@ -98,9 +99,9 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
98
99
|
version: '0'
|
99
100
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
100
101
|
requirements:
|
101
|
-
- - "
|
102
|
+
- - ">"
|
102
103
|
- !ruby/object:Gem::Version
|
103
|
-
version:
|
104
|
+
version: 1.3.1
|
104
105
|
requirements: []
|
105
106
|
rubyforge_project:
|
106
107
|
rubygems_version: 2.4.5
|
@@ -1,72 +0,0 @@
|
|
1
|
-
require 'excon'
|
2
|
-
require 'json'
|
3
|
-
|
4
|
-
module Kontena
|
5
|
-
module Machine
|
6
|
-
module Upcloud
|
7
|
-
module UpcloudCommon
|
8
|
-
|
9
|
-
attr_reader :username
|
10
|
-
attr_reader :password
|
11
|
-
|
12
|
-
def upcloud_client
|
13
|
-
@upcloud_client ||= Excon.new(
|
14
|
-
'https://api.upcloud.com',
|
15
|
-
omit_default_port: true,
|
16
|
-
user: username,
|
17
|
-
password: password,
|
18
|
-
headers: { "Accept-Encoding" => 'application/json' }
|
19
|
-
)
|
20
|
-
end
|
21
|
-
|
22
|
-
def find_template(name)
|
23
|
-
get('storage/template')[:storages][:storage].find{|s| s[:title].downcase.start_with?(name.downcase)}
|
24
|
-
end
|
25
|
-
|
26
|
-
def find_plan(name)
|
27
|
-
get('plan')[:plans][:plan].find{|s| s[:name].downcase.eql?(name.downcase)}
|
28
|
-
end
|
29
|
-
|
30
|
-
def zone_exist?(name)
|
31
|
-
get('zone')[:zones][:zone].map{|p| p[:id]}.include?(name)
|
32
|
-
end
|
33
|
-
|
34
|
-
def get_server(id)
|
35
|
-
get("server/#{id}").fetch(:server, nil)
|
36
|
-
end
|
37
|
-
|
38
|
-
def api_access?
|
39
|
-
response = get('account')
|
40
|
-
response.kind_of?(Hash) && response.has_key?(:account)
|
41
|
-
rescue
|
42
|
-
false
|
43
|
-
end
|
44
|
-
|
45
|
-
def abort_unless_api_access
|
46
|
-
unless api_access?
|
47
|
-
abort('Upcloud API authentication failed. Check that API access is enabled for the user.')
|
48
|
-
end
|
49
|
-
end
|
50
|
-
|
51
|
-
[:get, :post, :delete].each do |http_method|
|
52
|
-
define_method http_method do |path, options={}|
|
53
|
-
response = upcloud_client.send(
|
54
|
-
http_method,
|
55
|
-
{
|
56
|
-
path: File.join('/1.2', path),
|
57
|
-
headers: { 'Content-Type' => 'application/json' }
|
58
|
-
}.merge(options)
|
59
|
-
)
|
60
|
-
if response.body && response.body.start_with?('{')
|
61
|
-
JSON.parse(response.body, symbolize_names: true)
|
62
|
-
elsif response.status.to_s.start_with?('2')
|
63
|
-
{success: true}
|
64
|
-
else
|
65
|
-
{error: response.status}
|
66
|
-
end
|
67
|
-
end
|
68
|
-
end
|
69
|
-
end
|
70
|
-
end
|
71
|
-
end
|
72
|
-
end
|