vps 0.1.2 → 0.3.1

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
- SHA1:
3
- metadata.gz: 591e2f6174b369e271f23bc60b9d9492045259f3
4
- data.tar.gz: 5b325e542fbacd8a0cf33df939c58db68c17995b
2
+ SHA256:
3
+ metadata.gz: c05fa45234177718e60d54da1b3fdf0405b832360a03e939271feb39237355d5
4
+ data.tar.gz: c3349feae30878a1c26477b4a290fa926ba2a2ed03cc17ae04075f9b4c90cbe5
5
5
  SHA512:
6
- metadata.gz: 07edf2782cd06c64ad79478dfc51c168552822530083f3170dd702fc46aec3f61600390abb8846cfe1ce7de021f48e5f27a39f1530cfd2cca75ef859c42ce67e
7
- data.tar.gz: 7b59c311ae6fda27227c2128c4dbf26338b6a2e8f4740e49b05cb321b24eb28f2d78d45eaf53e58c28b8d3360abeaf02a5d3cfc2c64572af81ed8bb3cd136f0d
6
+ metadata.gz: 71e6d995c7dbacd2b144782e051eae9c87cb809a01d0c181a896ad607a9fe3f35c6cc0ab80174ecfa7a4956852633ec833b3044d41abf9e99bc943fa76f46f7f
7
+ data.tar.gz: 58d5327bd2fbcbd2b42db20e6544fbbed5a27cbabdf1bdc38200ee48c90c651ade0d64aa4503fe0bc3734de94b19e76e3f64c83540f3347e310a57aa37177463
@@ -1,5 +1,29 @@
1
1
  ## VPS CHANGELOG
2
2
 
3
+ ### Version 0.3.1 (October 3, 2020)
4
+
5
+ * Support skipping certain image builds when deploying
6
+ * Add more X-Forwarded headers to fix the origin error
7
+
8
+ ### Version 0.2.3 (January 2, 2020)
9
+
10
+ * Support upstreams without domains
11
+
12
+ ### Version 0.2.2 (January 2, 2020)
13
+
14
+ * Automatically add container names for upstreams and services
15
+ * Add opportunity to add lines to the generated Dockerfile
16
+
17
+ ### Version 0.2.1 (January 2, 2020)
18
+
19
+ * Support NodeJS based applications
20
+ * Clean up default upstream specs
21
+ * Set container name when adding upstream
22
+
23
+ ### Version 0.2.0 (December 31, 2019)
24
+
25
+ * Provide ability to add both custom HTTP and HTTPS Nginx configs [BREAKING]
26
+
3
27
  ### Version 0.1.2 (September 29, 2019)
4
28
 
5
29
  * Run postload tasks at the end of deployment
data/README.md CHANGED
@@ -96,7 +96,7 @@ For support, remarks and requests, please mail me at [pm_engel@icloud.com](mailt
96
96
 
97
97
  ## License
98
98
 
99
- Copyright (c) 2019 Paul Engel, released under the MIT license
99
+ Copyright (c) 2020 Paul Engel, released under the MIT license
100
100
 
101
101
  http://github.com/archan937 – http://twitter.com/archan937 – pm_engel@icloud.com
102
102
 
data/VERSION CHANGED
@@ -1 +1 @@
1
- 0.1.2
1
+ 0.3.1
data/lib/vps.rb CHANGED
@@ -1,3 +1,4 @@
1
+ require "tmpdir"
1
2
  require "vps/version"
2
3
 
3
4
  module VPS
@@ -29,7 +29,9 @@ module VPS
29
29
 
30
30
  Playbook.all.each do |playbook|
31
31
  desc playbook.usage, playbook.description
32
- method_options playbook.options if playbook.options
32
+ playbook.options.each do |(name, options)|
33
+ method_option name, options
34
+ end
33
35
  define_method playbook.command do |*args|
34
36
  start = Time.now
35
37
  playbook.run!(args, options)
@@ -11,7 +11,7 @@ module VPS
11
11
 
12
12
  if (upstream = config[:upstreams].detect{|upstream| upstream[:name] == name})
13
13
  upstream[:email] = email if email
14
- upstream[:domains].push(domain).uniq!
14
+ (upstream[:domains] ||= []).push(domain).uniq!
15
15
  VPS.write_config(host, config)
16
16
  end
17
17
  end
@@ -61,8 +61,11 @@ module VPS
61
61
  end
62
62
 
63
63
  def options
64
- options = playbook["options"] || {}
65
- options[%w(-d --dry-run)] = :boolean
64
+ options = (playbook["options"] || {}).inject({}) do |hash, (key, value)|
65
+ hash[key.to_sym] = value.symbolize_keys
66
+ hash
67
+ end
68
+ options[:d] = {:type => :boolean, :aliases => "dry-run"}
66
69
  options
67
70
  end
68
71
 
@@ -86,6 +89,13 @@ module VPS
86
89
  def run!(args, options)
87
90
  hash = Hash[arguments.zip(args)]
88
91
  state = State.new(hash.merge(options))
92
+
93
+ self.options.each do |(name, opts)|
94
+ if opts[:aliases]
95
+ state[opts[:aliases].underscore] = state[name]
96
+ end
97
+ end
98
+
89
99
  run(state)
90
100
  end
91
101
 
@@ -5,9 +5,6 @@ module VPS
5
5
 
6
6
  class AuthenticationFailedError < VPS::CLI::Error; end
7
7
  class SSHMock
8
- def initialize
9
- puts "🏄‍♀️ ~> ".gray + "Mocking SSH connection with Ubuntu 18.04.2 LTS server".cyan
10
- end
11
8
  def exec!(command)
12
9
  case command
13
10
  when "cat /etc/lsb-release"
@@ -32,7 +29,11 @@ module VPS
32
29
  end
33
30
 
34
31
  def dry_run?
35
- !!fetch(:d)
32
+ !!fetch(:d) || skip?
33
+ end
34
+
35
+ def skip?
36
+ !!fetch(:_skip_)
36
37
  end
37
38
 
38
39
  def scope(constants = {})
@@ -57,7 +58,7 @@ module VPS
57
58
  (hash || {}).fetch(key)
58
59
  end.tap do |value|
59
60
  if to_domain && value
60
- if (domain = value[:domains].first)
61
+ if (domain = (value[:domains] || ["-"]).first)
61
62
  return domain.gsub(/https?:\/\//, "")
62
63
  end
63
64
  end
@@ -109,7 +110,9 @@ module VPS
109
110
  command = "sudo -u #{user} -H sh -c #{command.inspect}"
110
111
  end
111
112
  puts "🏄‍♀️ ~> ".gray + command.yellow
112
- unless dry_run?
113
+ if dry_run?
114
+ puts " skipped".gray if skip?
115
+ else
113
116
  start = Time.now
114
117
  result = []
115
118
 
@@ -132,18 +135,16 @@ module VPS
132
135
  end
133
136
 
134
137
  def home_directory
135
- @home_directory ||= ssh.exec!("pwd").strip
138
+ ssh.exec!("pwd").strip
136
139
  end
137
140
 
138
141
  def server_version
139
- @server_version ||= begin
140
- release = ssh.exec!("cat /etc/lsb-release")
142
+ release = ssh.exec!("cat /etc/lsb-release")
141
143
 
142
- distribution = release.match(/DISTRIB_ID=(.*)/)[1].underscore
143
- release = release.match(/DISTRIB_RELEASE=(.*)/)[1]
144
+ distribution = release.match(/DISTRIB_ID=(.*)/)[1].underscore
145
+ release = release.match(/DISTRIB_RELEASE=(.*)/)[1]
144
146
 
145
- [distribution, release].join("-")
146
- end
147
+ [distribution, release].join("-")
147
148
  end
148
149
 
149
150
  private
@@ -153,12 +154,10 @@ module VPS
153
154
  end
154
155
 
155
156
  def ssh
156
- @ssh ||= begin
157
- if dry_run?
158
- SSHMock.new
159
- else
160
- Net::SSH.start(fetch(:host), fetch(:user))
161
- end
157
+ if dry_run?
158
+ SSHMock.new
159
+ else
160
+ Net::SSH.start(fetch(:host), fetch(:user))
162
161
  end
163
162
  rescue StandardError => e
164
163
  raise AuthenticationFailedError, e.message
@@ -86,7 +86,22 @@ module VPS
86
86
  end
87
87
 
88
88
  def when(state, options)
89
- if state[options[:boolean]]
89
+ pass = false
90
+
91
+ if options.key?("boolean")
92
+ pass = !!state[options[:boolean]]
93
+ else
94
+ value = options.key?("value") ? state[options[:value]] : options[:string]
95
+ if options.key?("include")
96
+ pass = state[options[:include]].include?(value)
97
+ elsif options.key?("exclude")
98
+ pass = !state[options[:exclude]].include?(value)
99
+ end
100
+ end
101
+
102
+ scope = pass ? {} : {_skip_: true}
103
+
104
+ state.scope(scope) do
90
105
  puts_description(state, options)
91
106
  run_tasks(state, {:tasks => options[:run]})
92
107
  end
@@ -153,7 +168,9 @@ module VPS
153
168
  output = [options[:command]].flatten.inject(nil) do |_, command|
154
169
  command = state.resolve(command)
155
170
  puts "☕ ~> ".gray + command.yellow
156
- unless state.dry_run?
171
+ if state.dry_run?
172
+ puts " skipped".gray if state.skip?
173
+ else
157
174
  start = Time.now
158
175
  result = []
159
176
 
@@ -10,13 +10,9 @@ module VPS
10
10
 
11
11
  unless config[:upstreams].any?{|upstream| upstream[:name] == name}
12
12
  spec = derive_upstream(path)
13
- spec[:nginx] ||= nil
14
13
  config[:upstreams].push(spec.merge({
15
14
  :name => name || File.basename(path),
16
- :path => path,
17
- :domains => [],
18
- :email => nil,
19
- :compose => nil
15
+ :path => path
20
16
  }))
21
17
  VPS.write_config(host, config)
22
18
  end
@@ -84,6 +80,20 @@ module VPS
84
80
  }
85
81
  end
86
82
  end
83
+ elsif Dir["#{path}/package.json"].any?
84
+ tmpfile = "#{Dir.tmpdir}/vps-debug.log"
85
+ pid = spawn("cd #{path} && npm start", :out => tmpfile, :err => "/dev/null")
86
+ Process.detach(pid)
87
+ sleep 5
88
+ `ps aux | grep -e "no[d]e #{path}"`.strip.split("\n").collect do |line|
89
+ `kill -9 #{line.split(" ")[1]}`
90
+ end
91
+ port = File.read(tmpfile).match(/on port (\d+)/).captures.first.to_i
92
+ {
93
+ type: "node",
94
+ node_version: `$SHELL -l -c 'cd #{path} && node -v'`.match(/[\d\.?]+/).to_s,
95
+ port: port
96
+ }
87
97
  end
88
98
  end
89
99
 
@@ -1,7 +1,7 @@
1
1
  module VPS
2
2
  MAJOR = 0
3
- MINOR = 1
4
- TINY = 2
3
+ MINOR = 3
4
+ TINY = 1
5
5
 
6
6
  VERSION = [MAJOR, MINOR, TINY].join(".")
7
7
  end
@@ -6,6 +6,11 @@ usage:
6
6
  arguments:
7
7
  - host
8
8
  - tool
9
+ options:
10
+ s:
11
+ type: array
12
+ aliases: skip-build
13
+ default: []
9
14
  tasks:
10
15
  - task: ensure
11
16
  argument: user
@@ -13,23 +13,34 @@ tasks:
13
13
  - task: generate_file
14
14
  template: docker/upstream/Dockerfile.{{ upstream.type }}.erb
15
15
  target: "{{ config_path }}/{{ upstream.name }}/Dockerfile"
16
- - description: Building '{{ upstream.name }}' image
17
- task: execute
18
- command: docker build --no-cache -f {{ config_path }}/{{ upstream.name }}/Dockerfile -t {{ upstream.name }} {{ upstream.path }}
16
+ - task: when
17
+ value: upstream.name
18
+ exclude: skip_build
19
+ run:
20
+ - task: execute
21
+ command: docker build --no-cache -f {{ config_path }}/{{ upstream.name }}/Dockerfile -t {{ upstream.name }} {{ upstream.path }}
19
22
  - description: Saving docker images as .gzip file
20
23
  task: loop
21
24
  through: << upstreams >>
22
25
  as: upstream
23
26
  run:
24
- - task: execute
25
- command: docker save {{ upstream.name }} | gzip > /tmp/{{ upstream.name }}.gzip
27
+ - task: when
28
+ value: upstream.name
29
+ exclude: skip_build
30
+ run:
31
+ - task: execute
32
+ command: docker save {{ upstream.name }} | gzip > /tmp/{{ upstream.name }}.gzip
26
33
  - description: Uploading images
27
34
  task: loop
28
35
  through: << upstreams >>
29
36
  as: upstream
30
37
  run:
31
- - task: upload
32
- file: /tmp/{{ upstream.name }}.gzip
38
+ - task: when
39
+ value: upstream.name
40
+ exclude: skip_build
41
+ run:
42
+ - task: upload
43
+ file: /tmp/{{ upstream.name }}.gzip
33
44
  - description: Stopping current containers
34
45
  task: remote_execute
35
46
  command: cd {{ release_path }} && docker-compose stop
@@ -38,15 +49,23 @@ tasks:
38
49
  through: << upstreams >>
39
50
  as: upstream
40
51
  run:
41
- - task: remote_execute
42
- command: docker container rm $(docker container ls -f ancestor={{ upstream.name }} -aq)
52
+ - task: when
53
+ value: upstream.name
54
+ exclude: skip_build
55
+ run:
56
+ - task: remote_execute
57
+ command: docker container rm $(docker container ls -f ancestor={{ upstream.name }} -aq)
43
58
  - description: Removing current images
44
59
  task: loop
45
60
  through: << upstreams >>
46
61
  as: upstream
47
62
  run:
48
- - task: remote_execute
49
- command: docker image rm {{ upstream.name }}
63
+ - task: when
64
+ value: upstream.name
65
+ exclude: skip_build
66
+ run:
67
+ - task: remote_execute
68
+ command: docker image rm {{ upstream.name }}
50
69
  - task: run_tasks
51
70
  tasks: << preload >>
52
71
  - description: Unzipping and loading docker images
@@ -54,8 +73,12 @@ tasks:
54
73
  through: << upstreams >>
55
74
  as: upstream
56
75
  run:
57
- - task: remote_execute
58
- command: gunzip < /tmp/{{ upstream.name }}.gzip | docker load
76
+ - task: when
77
+ value: upstream.name
78
+ exclude: skip_build
79
+ run:
80
+ - task: remote_execute
81
+ command: gunzip < /tmp/{{ upstream.name }}.gzip | docker load
59
82
  - task: generate_file
60
83
  template: docker/docker-compose.yml.erb
61
84
  target: "{{ docker_compose_file }}"
@@ -88,7 +111,7 @@ tasks:
88
111
  - cd {{ release_path }} && if [ ! -d "data/certbot/conf/live/{{ domain:upstream }}" ]; then yes Y | sudo ./init-letsencrypt/{{ upstream.name }}.sh; fi
89
112
  - description: Starting containers
90
113
  task: remote_execute
91
- command: cd {{ release_path }} && docker-compose up {{ up }} -d
114
+ command: cd {{ release_path }} && docker-compose up -d
92
115
  - description: Checking running docker images
93
116
  task: remote_execute
94
117
  command: docker ps
@@ -3,7 +3,7 @@
3
3
  upstream <%= upstream[:name] %> {
4
4
  server <%= upstream[:name] %>:<%= upstream[:port] %>;
5
5
  }
6
- <%- upstream[:domains].partition{|domain| domain.include?("http://")}.reject(&:empty?).each do |domains| %>
6
+ <%- (upstream[:domains] || []).partition{|domain| domain.include?("http://")}.reject(&:empty?).each do |domains| %>
7
7
  <%-
8
8
  https = domains.first.include?("https://")
9
9
  domains = domains.collect{|domain| domain.gsub(/https?:\/\//, "")}.join(" ")
@@ -18,6 +18,10 @@ server {
18
18
  server_name <%= domains %>;
19
19
  server_tokens off;
20
20
 
21
+ <%- end %>
22
+ <%- if nginx[:http] %>
23
+ <%= nginx[:http].gsub("PROXY_PASS", proxy_pass).indent(2) %>
24
+
21
25
  <%- end %>
22
26
  <%- if https %>
23
27
  location /.well-known/acme-challenge/ {
@@ -47,8 +51,8 @@ server {
47
51
  try_files $uri @app;
48
52
 
49
53
  <%- end %>
50
- <%- if nginx[:config] %>
51
- <%= nginx[:config].gsub("PROXY_PASS", proxy_pass).indent(2) %>
54
+ <%- if nginx[:https] %>
55
+ <%= nginx[:https].gsub("PROXY_PASS", proxy_pass).indent(2) %>
52
56
 
53
57
  <%- end %>
54
58
  location <%= nginx[:try_files] ? "@app" : "/" %> {
@@ -56,6 +60,10 @@ server {
56
60
  proxy_set_header Host $http_host;
57
61
  proxy_set_header X-Real-IP $remote_addr;
58
62
  proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
63
+ proxy_set_header X-Forwarded-Proto $scheme;
64
+ proxy_set_header X-Forwarded-Ssl on;
65
+ proxy_set_header X-Forwarded-Port $server_port;
66
+ proxy_set_header X-Forwarded-Host $host;
59
67
  <%- if nginx[:proxy_redirect] %>
60
68
  proxy_redirect <%= nginx[:proxy_redirect] %>;
61
69
  <%- end %>
@@ -34,12 +34,13 @@ services:
34
34
  <%- services.to_h.each do |name, spec| %>
35
35
 
36
36
  <%= name %>:
37
- <%= OpenStruct.to_hash(spec).to_yaml.sub(/^.*?\n/, "").indent(4) %>
37
+ <%= OpenStruct.to_hash(spec).to_yaml.sub(/^.*?\n/, "").sub("\n", "\ncontainer_name: #{name}\n").indent(4) %>
38
38
  <%- end %>
39
39
  <%- upstreams.each do |upstream| %>
40
40
 
41
41
  <%= upstream.name %>:
42
42
  image: <%= upstream.name %>
43
+ container_name: <%= upstream.name %>
43
44
  restart: always
44
45
  <%- unless upstream[:compose].inspect.match(/\bports\b/) %>
45
46
  ports:
@@ -0,0 +1,15 @@
1
+ FROM node:<%= upstream.node_version %>-alpine
2
+
3
+ RUN apk update \
4
+ && apk --no-cache --update add \
5
+ build-base nodejs tzdata
6
+
7
+ WORKDIR /opt/app
8
+ COPY . .
9
+
10
+ ENV NODE_ENV=production
11
+ <%- if upstream.dockerfile %>
12
+ <%= upstream.dockerfile.strip %>
13
+ <%- end %>
14
+ RUN npm install
15
+ CMD ["npm", "start"]
@@ -9,5 +9,8 @@ WORKDIR /opt/app
9
9
  COPY . .
10
10
 
11
11
  ENV MIX_ENV=prod
12
+ <%- if upstream.dockerfile %>
13
+ <%= upstream.dockerfile.strip %>
14
+ <%- end %>
12
15
  RUN mix do deps.get --only prod, deps.compile
13
16
  CMD ["sh", "-c", "mix phx.server"]
@@ -9,5 +9,8 @@ WORKDIR /opt/app
9
9
  COPY . .
10
10
 
11
11
  ENV MIX_ENV=prod
12
+ <%- if upstream.dockerfile %>
13
+ <%= upstream.dockerfile.strip %>
14
+ <%- end %>
12
15
  RUN mix do deps.get --only prod, deps.compile
13
16
  CMD ["sh", "-c", "mix run --no-halt"]
@@ -11,6 +11,9 @@ WORKDIR /opt/app
11
11
  COPY . .
12
12
 
13
13
  ENV RACK_ENV=production
14
+ <%- if upstream.dockerfile %>
15
+ <%= upstream.dockerfile.strip %>
16
+ <%- end %>
14
17
  RUN gem install bundler -v <%= upstream.bundler_version %>
15
18
  RUN bundle install --without development test
16
19
  CMD ["bundle", "exec", "rackup", "config.ru", "-o", "0.0.0.0"]
@@ -10,8 +10,12 @@ RUN apk update \
10
10
  WORKDIR /opt/app
11
11
  COPY . .
12
12
 
13
- ENV RAILS_ENV=production
14
13
  EXPOSE <%= upstream.port %>
14
+
15
+ ENV RAILS_ENV=production
16
+ <%- if upstream.dockerfile %>
17
+ <%= upstream.dockerfile.strip %>
18
+ <%- end %>
15
19
  RUN gem install bundler -v <%= upstream.bundler_version %>
16
20
  RUN bundle install --without development test
17
21
  CMD ["rm", "-f", "tmp/pids/server.pid"]
@@ -1,6 +1,6 @@
1
1
  #!/bin/bash
2
2
 
3
- <%- if (domains = upstream[:domains].collect{|domain| domain.dup.gsub!("https://", "")}.compact).any? %>
3
+ <%- if (domains = (upstream[:domains] || []).collect{|domain| domain.dup.gsub!("https://", "")}.compact).any? %>
4
4
  domains=(<%= domains.join(" ") %>)
5
5
  email="<%= upstream[:email] || "noreply@#{domains.first}" %>" # Adding a valid address is strongly recommended
6
6
  data_path="./data/certbot"
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: vps
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.2
4
+ version: 0.3.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Paul Engel
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2019-12-29 00:00:00.000000000 Z
11
+ date: 2020-10-03 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: thor
@@ -174,6 +174,7 @@ files:
174
174
  - script/console
175
175
  - templates/docker/data/nginx/app.conf.erb
176
176
  - templates/docker/docker-compose.yml.erb
177
+ - templates/docker/upstream/Dockerfile.node.erb
177
178
  - templates/docker/upstream/Dockerfile.phoenix.erb
178
179
  - templates/docker/upstream/Dockerfile.plug.erb
179
180
  - templates/docker/upstream/Dockerfile.rack.erb
@@ -203,7 +204,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
203
204
  version: '0'
204
205
  requirements: []
205
206
  rubyforge_project:
206
- rubygems_version: 2.4.5.4
207
+ rubygems_version: 2.7.6
207
208
  signing_key:
208
209
  specification_version: 4
209
210
  summary: Zero-config deployments of Plug, Phoenix, Rack and Rails apps on a clean