chef-provisioning-upcloud 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 6696f303371737ddc6cf49450260ac618ab132da
4
+ data.tar.gz: 2eea17ad6ff8a0010e8a25aeadcc9e77217f320c
5
+ SHA512:
6
+ metadata.gz: db6caf7c6052385178278c4fde338b544315fdc4409a3b3702253b83f1d68592459abd7d8b8baa9ed2b558b29f8081b1efbcabf4cfd2f8384b6eb0de6386d6be
7
+ data.tar.gz: f5f38fb1116cbafe5dff96b33ab8916cdaaf6d527e05761db0e3cd71519d01958f23bd95894704ff20c14014ae519f5f53b5514a3c38181dcd494495f3e1a89e
data/CHANGELOG.md ADDED
@@ -0,0 +1,4 @@
1
+ ## 0.2.0 (2016-01-11)
2
+
3
+ - Rewrite whole logic to Interactors.
4
+ - Fix formatting.
data/README.md ADDED
@@ -0,0 +1,73 @@
1
+ # chef-provisioning-upcloud
2
+
3
+ **Pull requests are encouraged and greatly appreciated!**
4
+
5
+ ## Warning - there will be dragons
6
+
7
+ - Use at your own risk.
8
+ - It's POC, created just for fun and maybe to learn something.
9
+
10
+ ## What doesn't work
11
+
12
+ - `action :destroy` won't delete disks.
13
+
14
+ ## Quick start
15
+
16
+ ### knife.rb
17
+
18
+ ```ruby
19
+ current_dir = File.dirname(__FILE__)
20
+ cookbook_copyright "Szymon Szypulski"
21
+ cookbook_email "szymon.szypulski@gmail.com"
22
+ log_level :info
23
+ log_location STDOUT
24
+ node_name "szymon"
25
+ client_key "#{ENV["HOME"]}/.chef_priv/szymon.pem"
26
+ validation_client_name "organization-validator"
27
+ validation_key "#{ENV["HOME"]}/.chef_priv/organization-validator.pem"
28
+ chef_server_url "https://api.opscode.com/organizations/organization"
29
+ cookbook_path ["./cookbooks"]
30
+ profiles(
31
+ "default" => {},
32
+ "openday" => {
33
+ driver: "upcloud:openday",
34
+ machine_options: {
35
+ bootstrap_options: {
36
+ # https://api.upcloud.com/1.2/storage/template
37
+ template: "01000000-0000-4000-8000-000030040200", # Ubuntu 14.04
38
+ # https://api.upcloud.com/1.2/zone
39
+ zone: "uk-lon1",
40
+ # https://api.upcloud.com/1.2/plan
41
+ plan: "1xCPU-1GB"
42
+ }
43
+ }
44
+ }
45
+ )
46
+ drivers(
47
+ "upcloud:openday" => {
48
+ driver_options: {
49
+ compute_options: {
50
+ auth_token: "<base64 from upcloud user+":"+password>"
51
+ }
52
+ }
53
+ }
54
+ )
55
+ ```
56
+
57
+ ### provision.rb
58
+
59
+ ```ruby
60
+ require "chef/provisioning/upcloud_driver/driver"
61
+
62
+ with_chef_server Chef::Config[:chef_server_url],
63
+ client_name: Chef::Config[:node_name],
64
+ signing_key_filename: Chef::Config[:client_key]
65
+
66
+ machine "web1.tld.com"
67
+ ```
68
+
69
+ ### Execution
70
+
71
+ ```
72
+ CHEF_PROFILE=openday chef-client -c knife.rb provision.rb
73
+ ```
data/Rakefile ADDED
@@ -0,0 +1,2 @@
1
+ require 'bundler'
2
+ require 'bundler/gem_tasks'
@@ -0,0 +1,6 @@
1
+ require "chef/provisioning/upcloud_driver/driver"
2
+
3
+ Chef::Provisioning.register_driver_class(
4
+ "upcloud",
5
+ Chef::Provisioning::UpcloudDriver::Driver
6
+ )
@@ -0,0 +1 @@
1
+ class Base; end
@@ -0,0 +1,15 @@
1
+ class Base::DestroyMachine
2
+ include Interactor
3
+
4
+ # @param client
5
+ # @param action_handler
6
+ # @param machine_spec
7
+ def call
8
+ machine_id = context.machine_spec.reference["server_id"]
9
+ context.action_handler.perform_action "Destroy machine #{machine_id}\n" do
10
+ # delete all disks too
11
+ context.client.delete("server/#{machine_id}")
12
+ context.machine_spec.reference = nil
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,23 @@
1
+ class Base::GetMachine
2
+ include Interactor
3
+
4
+ # @param client
5
+ # @param action_handler (optional)
6
+ # @param machine_spec
7
+ def call
8
+ machine_id = context.machine_spec.reference["server_id"]
9
+ response = context.client.get("server/#{machine_id}")
10
+ case response.status_code
11
+ when 404
12
+ context.action_handler.perform_action "Machine #{machine_id} does not exist.\n" do
13
+ context.machine_spec.reference = nil
14
+ end if context.action_handler
15
+ context.machine = nil
16
+ when 200
17
+ puts "Machine #{machine_id} exist.\n"
18
+ context.machine = JSON.parse(response.body)["server"]
19
+ else
20
+ fail "Unexpected response"
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,12 @@
1
+ class Base::InitializeClient
2
+ include Interactor
3
+
4
+ # @param auth_token
5
+ def call
6
+ client = Hurley::Client.new "https://api.upcloud.com/1.2/"
7
+ client.header["Authorization"] = "Basic #{context.auth_token}"
8
+ client.header["Content-Type"] = "application/json"
9
+
10
+ context.client = client
11
+ end
12
+ end
@@ -0,0 +1,24 @@
1
+ class Base::ReadyMachine
2
+ include Interactor
3
+
4
+ # @param client
5
+ # @param action_handler
6
+ # @param machine_spec
7
+ def call
8
+ client = context.client
9
+ machine_id = context.machine_spec.reference["server_id"]
10
+
11
+ machine = GetMachine.call(*context).machine
12
+ return if machine["state"] == "started"
13
+ context.action_handler.perform_action "Powering up, wait for machine #{machine_id}\n" do
14
+ client.post("server/#{machine_id}/start")
15
+ while machine["state"] != "started"
16
+ Timeout.timeout(60) do
17
+ sleep 5
18
+ client.post("server/#{machine_id}/start")
19
+ machine = GetMachine.call(*context).machine
20
+ end
21
+ end
22
+ end
23
+ end
24
+ end
@@ -0,0 +1,52 @@
1
+ require "chef/provisioning/upcloud_driver/version"
2
+
3
+ class Base::RequestMachine
4
+ include Interactor
5
+
6
+ # @param client
7
+ # @param action_handler
8
+ # @param machine_spec
9
+ # @param driver_url
10
+ def call
11
+ machine_options = context.machine_options
12
+ machine_spec = context.machine_spec
13
+
14
+ context.action_handler.perform_action "Creating server #{machine_spec.name} with options #{machine_options}\n" do
15
+ response = context.client.post("server", request_body(machine_options, machine_spec).to_json, "application/json")
16
+ if response.success?
17
+ server = JSON.parse(response.body)["server"]
18
+
19
+ machine_spec.reference = {
20
+ "driver_url" => context.driver_url,
21
+ "driver_version" => ::Chef::Provisioning::UpcloudDriver::VERSION,
22
+ "server_id" => server["uuid"],
23
+ "bootstrap_password" => server["password"]
24
+ }
25
+ else
26
+ fail "Unexpected response: #{response.body}"
27
+ end
28
+ end
29
+ end
30
+
31
+ private
32
+
33
+ def request_body(machine_options, machine_spec)
34
+ {
35
+ server: {
36
+ zone: machine_options[:bootstrap_options][:zone],
37
+ title: machine_spec.name,
38
+ hostname: machine_spec.name,
39
+ plan: machine_options[:bootstrap_options][:plan],
40
+ storage_devices: {
41
+ storage_device: [{
42
+ action: "clone",
43
+ storage: machine_options[:bootstrap_options][:template],
44
+ title: "#{machine_spec.name} from a template",
45
+ size: 30,
46
+ tier: "maxiops"
47
+ }]
48
+ }
49
+ }
50
+ }
51
+ end
52
+ end
@@ -0,0 +1,21 @@
1
+ class Base::StopMachine
2
+ include Interactor
3
+
4
+ # @param client
5
+ # @param action_handler
6
+ # @param machine_spec
7
+ def call
8
+ machine_id = context.machine_spec.reference["server_id"]
9
+ context.action_handler.perform_action "Power off machine #{machine_id}\n" do
10
+ context.client.post("server/#{machine_id}/stop")
11
+ end
12
+
13
+ machine = GetMachine.call(*context).machine
14
+ while machine["state"] != "stopped"
15
+ Timeout.timeout(60) do
16
+ sleep 20
17
+ machine = GetMachine.call(*context).machine
18
+ end
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,10 @@
1
+ require "chef/provisioning/interactors/base"
2
+ require "chef/provisioning/interactors/base/destroy_machine"
3
+ require "chef/provisioning/interactors/base/initialize_client"
4
+ require "chef/provisioning/interactors/base/stop_machine"
5
+
6
+ class DestroyMachine
7
+ include Interactor::Organizer
8
+
9
+ organize Base::InitializeClient, Base::StopMachine, Base::DestroyMachine
10
+ end
@@ -0,0 +1,9 @@
1
+ require "chef/provisioning/interactors/base"
2
+ require "chef/provisioning/interactors/base/get_machine"
3
+ require "chef/provisioning/interactors/base/initialize_client"
4
+
5
+ class GetMachine
6
+ include Interactor::Organizer
7
+
8
+ organize Base::InitializeClient, Base::GetMachine
9
+ end
@@ -0,0 +1,9 @@
1
+ require "chef/provisioning/interactors/base"
2
+ require "chef/provisioning/interactors/base/initialize_client"
3
+ require "chef/provisioning/interactors/base/ready_machine"
4
+
5
+ class ReadyMachine
6
+ include Interactor::Organizer
7
+
8
+ organize Base::InitializeClient, Base::ReadyMachine
9
+ end
@@ -0,0 +1,9 @@
1
+ require "chef/provisioning/interactors/base"
2
+ require "chef/provisioning/interactors/base/request_machine"
3
+ require "chef/provisioning/interactors/base/initialize_client"
4
+
5
+ class RequestMachine
6
+ include Interactor::Organizer
7
+
8
+ organize Base::InitializeClient, Base::RequestMachine
9
+ end
@@ -0,0 +1,9 @@
1
+ require "chef/provisioning/interactors/base"
2
+ require "chef/provisioning/interactors/base/stop_machine"
3
+ require "chef/provisioning/interactors/base/initialize_client"
4
+
5
+ class StopMachine
6
+ include Interactor::Organizer
7
+
8
+ organize Base::InitializeClient, Base::StopMachine
9
+ end
@@ -0,0 +1,3 @@
1
+ require "chef/provisioning"
2
+ require "chef/provisioning/upcloud_driver/driver"
3
+ require "chef/provisioning/upcloud_driver/resources"
@@ -0,0 +1,96 @@
1
+ require "chef/provisioning/driver"
2
+ require "chef/provisioning/upcloud_driver/version"
3
+
4
+ require "chef/provisioning/transport/ssh"
5
+ require "chef/provisioning/convergence_strategy/install_cached"
6
+ require "chef/provisioning/machine/unix_machine"
7
+
8
+ require "hurley"
9
+ require "interactor"
10
+
11
+ require "chef/provisioning/interactors/destroy_machine"
12
+ require "chef/provisioning/interactors/get_machine"
13
+ require "chef/provisioning/interactors/ready_machine"
14
+ require "chef/provisioning/interactors/request_machine"
15
+ require "chef/provisioning/interactors/stop_machine"
16
+
17
+ class Chef
18
+ module Provisioning
19
+ module UpcloudDriver
20
+ class Driver < Chef::Provisioning::Driver
21
+ include Chef::Mixin::ShellOut
22
+
23
+ def self.from_url(driver_url, config)
24
+ Driver.new(driver_url, config)
25
+ end
26
+
27
+ def initialize(driver_url, config)
28
+ super
29
+
30
+ begin
31
+ @auth_token = config[:driver_options][:compute_options][:auth_token]
32
+ rescue NoMethodError
33
+ msg = "Auth token is missing"
34
+ Chef::Log.fatal msg
35
+ raise msg
36
+ end
37
+ end
38
+
39
+ def self.canonicalize_url(driver_url, config)
40
+ [driver_url, config]
41
+ end
42
+
43
+ def allocate_machine(action_handler, machine_spec, machine_options)
44
+ if machine_spec.reference
45
+ GetMachine.call(action_handler: action_handler, auth_token: @auth_token, machine_spec: machine_spec)
46
+ end
47
+ return if machine_spec.reference
48
+ RequestMachine.call(
49
+ action_handler: action_handler, auth_token: @auth_token, driver_url: driver_url,
50
+ machine_options: machine_options, machine_spec: machine_spec
51
+ )
52
+ end
53
+
54
+ def stop_machine(action_handler, machine_spec, _machine_options)
55
+ return unless machine_spec.reference
56
+ StopMachine.call(action_handler: action_handler, auth_token: @auth_token, machine_spec: machine_spec)
57
+ end
58
+
59
+ def destroy_machine(action_handler, machine_spec, _machine_options)
60
+ return unless machine_spec.reference
61
+ DestroyMachine.call(action_handler: action_handler, auth_token: @auth_token, machine_spec: machine_spec)
62
+ end
63
+
64
+ def ready_machine(action_handler, machine_spec, machine_options)
65
+ ReadyMachine.call(auth_token: @auth_token, action_handler: action_handler, machine_spec: machine_spec)
66
+
67
+ machine_for(machine_spec, machine_options)
68
+ end
69
+
70
+ def machine_for(machine_spec, machine_options)
71
+ machine = GetMachine.call(auth_token: @auth_token, machine_spec: machine_spec).machine
72
+ ip_address = machine["ip_addresses"]["ip_address"].find do |address|
73
+ address["family"] == "IPv4" && address["access"] == "public"
74
+ end["address"]
75
+
76
+ ssh_options = {
77
+ auth_methods: ["password"],
78
+ password: machine_spec.reference["bootstrap_password"]
79
+ }
80
+
81
+ transport = Chef::Provisioning::Transport::SSH.new(
82
+ ip_address, "root", ssh_options, {}, config
83
+ )
84
+
85
+ convergence_strategy =
86
+ Chef::Provisioning::ConvergenceStrategy::InstallCached.new(machine_options[:convergence_options], {})
87
+ Chef::Provisioning::Machine::UnixMachine.new(machine_spec, transport, convergence_strategy)
88
+ end
89
+
90
+ def connect_to_machine(machine_spec, machine_options)
91
+ machine_for(machine_spec, machine_options)
92
+ end
93
+ end
94
+ end
95
+ end
96
+ end
@@ -0,0 +1,7 @@
1
+ class Chef
2
+ module Provisioning
3
+ module UpcloudDriver
4
+ VERSION = '0.2.0'
5
+ end
6
+ end
7
+ end
metadata ADDED
@@ -0,0 +1,146 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: chef-provisioning-upcloud
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.2.0
5
+ platform: ruby
6
+ authors:
7
+ - Szymon Szypulski
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2016-01-11 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: chef
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '12.5'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '12.5'
27
+ - !ruby/object:Gem::Dependency
28
+ name: chef-provisioning
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: 1.5.0
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: 1.5.0
41
+ - !ruby/object:Gem::Dependency
42
+ name: hurley
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - ">="
46
+ - !ruby/object:Gem::Version
47
+ version: '0'
48
+ type: :runtime
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - ">="
53
+ - !ruby/object:Gem::Version
54
+ version: '0'
55
+ - !ruby/object:Gem::Dependency
56
+ name: interactor
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - "~>"
60
+ - !ruby/object:Gem::Version
61
+ version: '3.0'
62
+ type: :runtime
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - "~>"
67
+ - !ruby/object:Gem::Version
68
+ version: '3.0'
69
+ - !ruby/object:Gem::Dependency
70
+ name: rake
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - ">="
74
+ - !ruby/object:Gem::Version
75
+ version: '0'
76
+ type: :development
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - ">="
81
+ - !ruby/object:Gem::Version
82
+ version: '0'
83
+ - !ruby/object:Gem::Dependency
84
+ name: pry
85
+ requirement: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - ">="
88
+ - !ruby/object:Gem::Version
89
+ version: '0'
90
+ type: :development
91
+ prerelease: false
92
+ version_requirements: !ruby/object:Gem::Requirement
93
+ requirements:
94
+ - - ">="
95
+ - !ruby/object:Gem::Version
96
+ version: '0'
97
+ description: Provisioner for creating upcloud containers in Chef Provisioning.
98
+ email: szymon.szypulski@gmail.com
99
+ executables: []
100
+ extensions: []
101
+ extra_rdoc_files: []
102
+ files:
103
+ - CHANGELOG.md
104
+ - README.md
105
+ - Rakefile
106
+ - lib/chef/provisioning/driver_init/upcloud.rb
107
+ - lib/chef/provisioning/interactors/base.rb
108
+ - lib/chef/provisioning/interactors/base/destroy_machine.rb
109
+ - lib/chef/provisioning/interactors/base/get_machine.rb
110
+ - lib/chef/provisioning/interactors/base/initialize_client.rb
111
+ - lib/chef/provisioning/interactors/base/ready_machine.rb
112
+ - lib/chef/provisioning/interactors/base/request_machine.rb
113
+ - lib/chef/provisioning/interactors/base/stop_machine.rb
114
+ - lib/chef/provisioning/interactors/destroy_machine.rb
115
+ - lib/chef/provisioning/interactors/get_machine.rb
116
+ - lib/chef/provisioning/interactors/ready_machine.rb
117
+ - lib/chef/provisioning/interactors/request_machine.rb
118
+ - lib/chef/provisioning/interactors/stop_machine.rb
119
+ - lib/chef/provisioning/upcloud_driver.rb
120
+ - lib/chef/provisioning/upcloud_driver/driver.rb
121
+ - lib/chef/provisioning/upcloud_driver/version.rb
122
+ homepage: https://github.com/szymonpk/chef-provisioning-upcloud
123
+ licenses:
124
+ - MIT
125
+ metadata: {}
126
+ post_install_message:
127
+ rdoc_options: []
128
+ require_paths:
129
+ - lib
130
+ required_ruby_version: !ruby/object:Gem::Requirement
131
+ requirements:
132
+ - - ">="
133
+ - !ruby/object:Gem::Version
134
+ version: '0'
135
+ required_rubygems_version: !ruby/object:Gem::Requirement
136
+ requirements:
137
+ - - ">="
138
+ - !ruby/object:Gem::Version
139
+ version: '0'
140
+ requirements: []
141
+ rubyforge_project:
142
+ rubygems_version: 2.4.3
143
+ signing_key:
144
+ specification_version: 4
145
+ summary: Provisioner for creating upcloud containers in Chef Provisioning.
146
+ test_files: []