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 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,5 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require "provisioning"
4
+
5
+ Provisioning::CLI.start(ARGV, ENV)
@@ -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
@@ -0,0 +1,7 @@
1
+ require "provisioning/cli"
2
+ require "provisioning/console"
3
+ require "provisioning/digitalocean"
4
+ require "provisioning/dokku"
5
+
6
+ module Provisioning
7
+ end
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: []