provisioning 0.0.1.alpha.1
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/bin/provision +5 -0
- data/lib/provisioning/cli.rb +105 -0
- data/lib/provisioning/console.rb +22 -0
- data/lib/provisioning/digitalocean.rb +100 -0
- data/lib/provisioning/dokku.rb +58 -0
- data/lib/provisioning.rb +7 -0
- metadata +130 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 24a8c455a3b419d172d520a0bf765ee3ad408b0b
|
4
|
+
data.tar.gz: 0f976f7ae8452797c1502bbcfbf4448f9878aaa4
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 7f94d389eb42dbe86eb9cc9a47f6850a2821fdaf6817e399e32b25082289b2fdd8f74f5a032c4aad2ca8841594fd6625b74a65b5ad0164ff897f000303d502f5
|
7
|
+
data.tar.gz: 1894e90832225ab2f513a747c9c1b45972602ea30e7eb9a6f76f1037dce1566fa5fd43fdfc54147255c57b310ab4e7675d2157f4c03bc056f9d97e8b0144caa1
|
data/bin/provision
ADDED
@@ -0,0 +1,105 @@
|
|
1
|
+
require "git"
|
2
|
+
require "json"
|
3
|
+
require "net/ssh"
|
4
|
+
require "rainbow"
|
5
|
+
|
6
|
+
require "provisioning"
|
7
|
+
|
8
|
+
module Provisioning
|
9
|
+
module CLI
|
10
|
+
def self.get_ssh_key(fingerprint)
|
11
|
+
Console.info("Getting SSH key from authentication agent")
|
12
|
+
agent = Net::SSH::Authentication::Agent.connect
|
13
|
+
agent.identities.find do |identity|
|
14
|
+
identity.fingerprint == fingerprint
|
15
|
+
end || Console.error("could not get key from the authentication agent, run `ssh-add`")
|
16
|
+
end
|
17
|
+
|
18
|
+
def self.start(args, env)
|
19
|
+
config_file = args.shift || "provisioning.json"
|
20
|
+
|
21
|
+
begin
|
22
|
+
config = JSON.parse(File.open(config_file).read)
|
23
|
+
rescue Errno::ENOENT, JSON::ParserError
|
24
|
+
Console.error("could not read json provisioning file '#{config_file}'")
|
25
|
+
end
|
26
|
+
|
27
|
+
ssh_key_fingerprint = config["ssh"]["key"]["fingerprint"]
|
28
|
+
|
29
|
+
ssh_key = get_ssh_key(ssh_key_fingerprint)
|
30
|
+
puts
|
31
|
+
|
32
|
+
app_name = config["app"]["name"]
|
33
|
+
domain = config["domain"]
|
34
|
+
platform = config["providers"]["platform"]
|
35
|
+
server_hostname = [platform, domain].join(".")
|
36
|
+
server_address = nil
|
37
|
+
|
38
|
+
if config["providers"]["hosting"] == "digitalocean"
|
39
|
+
digitalocean = DigitalOcean.new(config["digitalocean"])
|
40
|
+
|
41
|
+
digitalocean.upload_ssh_key(ssh_key)
|
42
|
+
puts
|
43
|
+
|
44
|
+
droplet = digitalocean.create_droplet(
|
45
|
+
name: server_hostname,
|
46
|
+
ssh_key_fingerprint: ssh_key_fingerprint
|
47
|
+
)
|
48
|
+
server_address = droplet.networks.v4.first.ip_address
|
49
|
+
puts
|
50
|
+
end
|
51
|
+
|
52
|
+
if config["providers"]["dns"] == "digitalocean"
|
53
|
+
digitalocean = DigitalOcean.new(config["digitalocean"])
|
54
|
+
|
55
|
+
digitalocean.create_domain(domain, server_address)
|
56
|
+
Console.success("Configue '#{domain}' with the following DNS servers:")
|
57
|
+
digitalocean.get_domain_name_servers(domain).each do |server|
|
58
|
+
Console.success(" - #{server}")
|
59
|
+
end
|
60
|
+
puts
|
61
|
+
|
62
|
+
digitalocean.create_domain_record(
|
63
|
+
domain: domain,
|
64
|
+
type: "A",
|
65
|
+
name: platform,
|
66
|
+
data: server_address
|
67
|
+
)
|
68
|
+
digitalocean.create_domain_record(
|
69
|
+
domain: domain,
|
70
|
+
type: "CNAME",
|
71
|
+
name: app_name,
|
72
|
+
data: "#{server_hostname}."
|
73
|
+
)
|
74
|
+
config["app"]["domains"].each do |app_domain|
|
75
|
+
Console.success("Configue '#{app_domain}' to point to '#{server_hostname}'")
|
76
|
+
end
|
77
|
+
puts
|
78
|
+
end
|
79
|
+
|
80
|
+
if config["providers"]["platform"] == "dokku"
|
81
|
+
dokku = Dokku.new(config["dokku"])
|
82
|
+
dokku.setup(address: server_address, domain: domain)
|
83
|
+
Console.success("Run `gem install dokku-cli` to get dokku client on your machine")
|
84
|
+
puts
|
85
|
+
|
86
|
+
dokku.create_app(config["app"])
|
87
|
+
puts
|
88
|
+
|
89
|
+
Console.info("Adding dokku to git remotes")
|
90
|
+
begin
|
91
|
+
git = Git.open(".")
|
92
|
+
rescue ArgumentError
|
93
|
+
Console.warning("not a git repository, skipping")
|
94
|
+
else
|
95
|
+
if git.remotes.map(&:name).include?("dokku")
|
96
|
+
Console.warning("remote already exists, skipping")
|
97
|
+
else
|
98
|
+
git.add_remote("dokku", "dokku@#{server_hostname}:#{app_name}")
|
99
|
+
end
|
100
|
+
Console.success("Run `git push dokku master` to deploy your code")
|
101
|
+
end
|
102
|
+
end
|
103
|
+
end
|
104
|
+
end
|
105
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
require "rainbow"
|
2
|
+
|
3
|
+
module Provisioning
|
4
|
+
module Console
|
5
|
+
def self.info(text)
|
6
|
+
puts text
|
7
|
+
end
|
8
|
+
|
9
|
+
def self.success(text)
|
10
|
+
puts Rainbow("#{text}").green
|
11
|
+
end
|
12
|
+
|
13
|
+
def self.warning(text)
|
14
|
+
puts Rainbow("Warning: #{text}").yellow
|
15
|
+
end
|
16
|
+
|
17
|
+
def self.error(text)
|
18
|
+
puts Rainbow("Error: #{text}").red
|
19
|
+
exit 1
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
@@ -0,0 +1,100 @@
|
|
1
|
+
require "droplet_kit"
|
2
|
+
|
3
|
+
require "provisioning"
|
4
|
+
|
5
|
+
module Provisioning
|
6
|
+
class DigitalOcean
|
7
|
+
def initialize(config)
|
8
|
+
@config = config
|
9
|
+
@client = DropletKit::Client.new(access_token: @config["token"])
|
10
|
+
end
|
11
|
+
|
12
|
+
def upload_ssh_key(ssh_key)
|
13
|
+
Console.info("Uploading SSH key to DigitalOcean")
|
14
|
+
|
15
|
+
disable_verbose
|
16
|
+
if @client.ssh_keys.all.map(&:fingerprint).include?(ssh_key.fingerprint)
|
17
|
+
Console.warning("SSH key already uploaded to DigitalOcean, skipping")
|
18
|
+
else
|
19
|
+
key = DropletKit::SSHKey.new(
|
20
|
+
name: "provisioning key",
|
21
|
+
public_key: ssh_key.to_s
|
22
|
+
)
|
23
|
+
@client.ssh_keys.create(key)
|
24
|
+
end
|
25
|
+
restore_verbose
|
26
|
+
end
|
27
|
+
|
28
|
+
def create_droplet(name:, ssh_key_fingerprint:)
|
29
|
+
Console.info("Creating droplet '#{name}'")
|
30
|
+
|
31
|
+
disable_verbose
|
32
|
+
@client.droplets.all.each do |droplet|
|
33
|
+
if droplet.name == name
|
34
|
+
Console.warning("droplet already exists, skipping")
|
35
|
+
return droplet
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
droplet = DropletKit::Droplet.new(
|
40
|
+
name: name,
|
41
|
+
region: @config["droplet"]["region"],
|
42
|
+
image: @config["droplet"]["image"],
|
43
|
+
size: @config["droplet"]["size"],
|
44
|
+
ssh_keys: [ssh_key_fingerprint]
|
45
|
+
)
|
46
|
+
@client.droplets.create(droplet)
|
47
|
+
droplet
|
48
|
+
ensure
|
49
|
+
restore_verbose
|
50
|
+
end
|
51
|
+
|
52
|
+
def create_domain(name, address)
|
53
|
+
Console.info("Creating domain '#{name}'")
|
54
|
+
|
55
|
+
disable_verbose
|
56
|
+
if @client.domains.all.map(&:name).include?(name)
|
57
|
+
Console.warning("domain already exists, skipping")
|
58
|
+
else
|
59
|
+
domain = DropletKit::Domain.new(name: name, ip_address: address)
|
60
|
+
@client.domains.create(domain)
|
61
|
+
end
|
62
|
+
ensure
|
63
|
+
restore_verbose
|
64
|
+
end
|
65
|
+
|
66
|
+
def create_domain_record(domain:, type:, name:, data:)
|
67
|
+
Console.info("Creating domain record #{type} '#{name}.#{domain}' to '#{data}'")
|
68
|
+
|
69
|
+
disable_verbose
|
70
|
+
if @client.domain_records.all(for_domain: domain).map(&:name).include?(name)
|
71
|
+
Console.warning("record already exists, skipping")
|
72
|
+
else
|
73
|
+
record = DropletKit::DomainRecord.new(type: type, name: name, data: data)
|
74
|
+
@client.domain_records.create(record, for_domain: domain)
|
75
|
+
end
|
76
|
+
ensure
|
77
|
+
restore_verbose
|
78
|
+
end
|
79
|
+
|
80
|
+
def get_domain_name_servers(domain)
|
81
|
+
disable_verbose
|
82
|
+
@client.domain_records.all(for_domain: domain).
|
83
|
+
select { |r| r.type == "NS" }.
|
84
|
+
map(&:data)
|
85
|
+
ensure
|
86
|
+
restore_verbose
|
87
|
+
end
|
88
|
+
|
89
|
+
private
|
90
|
+
|
91
|
+
def disable_verbose
|
92
|
+
$OLD_VERBOSE = $VERBOSE
|
93
|
+
$VERBOSE = nil
|
94
|
+
end
|
95
|
+
|
96
|
+
def restore_verbose
|
97
|
+
$VERBOSE = $OLD_VERBOSE
|
98
|
+
end
|
99
|
+
end
|
100
|
+
end
|
@@ -0,0 +1,58 @@
|
|
1
|
+
require "net/ssh"
|
2
|
+
|
3
|
+
require "provisioning"
|
4
|
+
|
5
|
+
module Provisioning
|
6
|
+
class Dokku
|
7
|
+
def initialize(config)
|
8
|
+
@config = config
|
9
|
+
@servers = []
|
10
|
+
end
|
11
|
+
|
12
|
+
def setup(address:, domain:)
|
13
|
+
@servers << address
|
14
|
+
version = @config["version"]
|
15
|
+
Console.info("Installing dokku #{version} on '#{address}'")
|
16
|
+
Net::SSH.start(address, "root") do |ssh|
|
17
|
+
if ssh.exec!("which dokku").present?
|
18
|
+
Console.warning("dokku already installed, skipping")
|
19
|
+
else
|
20
|
+
puts ssh.exec!("wget https://raw.githubusercontent.com/dokku/dokku/#{version}/bootstrap.sh")
|
21
|
+
puts ssh.exec!("DOKKU_TAG=#{version} bash bootstrap.sh")
|
22
|
+
puts ssh.exec!("service dokku-installer stop")
|
23
|
+
puts ssh.exec!("systemctl disable dokku-installer")
|
24
|
+
puts ssh.exec!("cat .ssh/authorized_keys | sshcommand acl-add dokku admin")
|
25
|
+
puts ssh.exec!("echo -n #{domain} > /home/dokku/VHOST")
|
26
|
+
puts ssh.exec!("echo -n #{domain} > /home/dokku/HOSTNAME")
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
def create_app(config)
|
32
|
+
name = config["name"]
|
33
|
+
@servers.each do |address|
|
34
|
+
Console.info("Creating dokku app '#{name}' on '#{address}'")
|
35
|
+
Net::SSH.start(address, "root") do |ssh|
|
36
|
+
existing_apps = ssh.exec!("dokku apps").to_s.lines.map(&:chomp)
|
37
|
+
if existing_apps.include?(name)
|
38
|
+
Console.warning("app already exists, skipping")
|
39
|
+
else
|
40
|
+
puts ssh.exec!("dokku apps:create #{name}")
|
41
|
+
|
42
|
+
config["services"].each do |service|
|
43
|
+
case service
|
44
|
+
when "mongo", "postgres", "redis"
|
45
|
+
puts ssh.exec!("dokku plugin:install https://github.com/dokku/dokku-#{service}.git #{service}")
|
46
|
+
puts ssh.exec!("dokku #{service}:create #{name}-#{service}")
|
47
|
+
puts ssh.exec!("dokku #{service}:link #{name}-#{service} #{name}")
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
domains = config["domains"].join(" ")
|
52
|
+
puts ssh.exec!("dokku domains:add #{name} #{domains}")
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
data/lib/provisioning.rb
ADDED
metadata
ADDED
@@ -0,0 +1,130 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: provisioning
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.1.alpha.1
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Vincent Ollivier
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2017-09-23 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: git
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - "~>"
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '1.3'
|
20
|
+
- - ">="
|
21
|
+
- !ruby/object:Gem::Version
|
22
|
+
version: 1.3.0
|
23
|
+
type: :runtime
|
24
|
+
prerelease: false
|
25
|
+
version_requirements: !ruby/object:Gem::Requirement
|
26
|
+
requirements:
|
27
|
+
- - "~>"
|
28
|
+
- !ruby/object:Gem::Version
|
29
|
+
version: '1.3'
|
30
|
+
- - ">="
|
31
|
+
- !ruby/object:Gem::Version
|
32
|
+
version: 1.3.0
|
33
|
+
- !ruby/object:Gem::Dependency
|
34
|
+
name: rainbow
|
35
|
+
requirement: !ruby/object:Gem::Requirement
|
36
|
+
requirements:
|
37
|
+
- - "~>"
|
38
|
+
- !ruby/object:Gem::Version
|
39
|
+
version: '2.2'
|
40
|
+
- - ">="
|
41
|
+
- !ruby/object:Gem::Version
|
42
|
+
version: 2.2.0
|
43
|
+
type: :runtime
|
44
|
+
prerelease: false
|
45
|
+
version_requirements: !ruby/object:Gem::Requirement
|
46
|
+
requirements:
|
47
|
+
- - "~>"
|
48
|
+
- !ruby/object:Gem::Version
|
49
|
+
version: '2.2'
|
50
|
+
- - ">="
|
51
|
+
- !ruby/object:Gem::Version
|
52
|
+
version: 2.2.0
|
53
|
+
- !ruby/object:Gem::Dependency
|
54
|
+
name: droplet_kit
|
55
|
+
requirement: !ruby/object:Gem::Requirement
|
56
|
+
requirements:
|
57
|
+
- - "~>"
|
58
|
+
- !ruby/object:Gem::Version
|
59
|
+
version: '2.1'
|
60
|
+
- - ">="
|
61
|
+
- !ruby/object:Gem::Version
|
62
|
+
version: 2.1.0
|
63
|
+
type: :runtime
|
64
|
+
prerelease: false
|
65
|
+
version_requirements: !ruby/object:Gem::Requirement
|
66
|
+
requirements:
|
67
|
+
- - "~>"
|
68
|
+
- !ruby/object:Gem::Version
|
69
|
+
version: '2.1'
|
70
|
+
- - ">="
|
71
|
+
- !ruby/object:Gem::Version
|
72
|
+
version: 2.1.0
|
73
|
+
- !ruby/object:Gem::Dependency
|
74
|
+
name: net-ssh
|
75
|
+
requirement: !ruby/object:Gem::Requirement
|
76
|
+
requirements:
|
77
|
+
- - "~>"
|
78
|
+
- !ruby/object:Gem::Version
|
79
|
+
version: '4.1'
|
80
|
+
- - ">="
|
81
|
+
- !ruby/object:Gem::Version
|
82
|
+
version: 4.1.0
|
83
|
+
type: :runtime
|
84
|
+
prerelease: false
|
85
|
+
version_requirements: !ruby/object:Gem::Requirement
|
86
|
+
requirements:
|
87
|
+
- - "~>"
|
88
|
+
- !ruby/object:Gem::Version
|
89
|
+
version: '4.1'
|
90
|
+
- - ">="
|
91
|
+
- !ruby/object:Gem::Version
|
92
|
+
version: 4.1.0
|
93
|
+
description: PaaS Provisioning
|
94
|
+
email: v@vinc.cc
|
95
|
+
executables:
|
96
|
+
- provision
|
97
|
+
extensions: []
|
98
|
+
extra_rdoc_files: []
|
99
|
+
files:
|
100
|
+
- bin/provision
|
101
|
+
- lib/provisioning.rb
|
102
|
+
- lib/provisioning/cli.rb
|
103
|
+
- lib/provisioning/console.rb
|
104
|
+
- lib/provisioning/digitalocean.rb
|
105
|
+
- lib/provisioning/dokku.rb
|
106
|
+
homepage: https://github.com/vinc/provisioning.rb
|
107
|
+
licenses:
|
108
|
+
- MIT
|
109
|
+
metadata: {}
|
110
|
+
post_install_message:
|
111
|
+
rdoc_options: []
|
112
|
+
require_paths:
|
113
|
+
- lib
|
114
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
115
|
+
requirements:
|
116
|
+
- - ">="
|
117
|
+
- !ruby/object:Gem::Version
|
118
|
+
version: '0'
|
119
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
120
|
+
requirements:
|
121
|
+
- - ">"
|
122
|
+
- !ruby/object:Gem::Version
|
123
|
+
version: 1.3.1
|
124
|
+
requirements: []
|
125
|
+
rubyforge_project:
|
126
|
+
rubygems_version: 2.6.8
|
127
|
+
signing_key:
|
128
|
+
specification_version: 4
|
129
|
+
summary: PaaS Provisioning
|
130
|
+
test_files: []
|