pvcglue 0.9.3 → 0.9.4

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 02dc01c9dfc836f04aac2b7e7d099dd0cad4dc11
4
- data.tar.gz: 3b2ee3d8c9bb49fee054d5c4ddb889b90fd69ebf
3
+ metadata.gz: e8640111473b3ed136163c0bb0fb2a7af3aca750
4
+ data.tar.gz: c509475f64ca8e936b661d238840be07b1ba435c
5
5
  SHA512:
6
- metadata.gz: 362b79a99c872b3aba193122ca001ee57f7942d742b53ea4fec293961cec5e8362362556fd7b63b802f889a325e5caf7a622715d20356df75fb227f258ec50fe
7
- data.tar.gz: 9145f5653e913be83eb8b2165bc5479fafa8c84a905637c0e81b6fc378c00e0948e7806c8f161367f1d572863795f1e46a7c4e9a6c15b0691c97ab222966b1a2
6
+ metadata.gz: 6880a84309e9d85cb6cd8e4965620f35672e91e55a7ce614e79b97dbba5041070ce6b53bc19f7f9e6a7842d4af0e6bd7d76e119a07e8b90906bdc0e2be3c8955
7
+ data.tar.gz: 47f8cded36079c27e0db96acca25db1ebfaecb273a95bff1ee42c0e8ba5c61e79b7bef22cee4685c94dd538008059d7604d45ffda41298c6a20c4ec36d5eb404
data/bin/pvc CHANGED
@@ -31,7 +31,11 @@ def capistrano_style_environment
31
31
  end
32
32
  else
33
33
  Pvcglue::CLI.start
34
+ Pvcglue.docs.done
34
35
  end
36
+ else
37
+ Pvcglue::CLI.start
38
+ Pvcglue.docs.done
35
39
  end
36
40
  end
37
41
 
@@ -5,6 +5,7 @@ require 'pvcglue/manager'
5
5
  require 'pvcglue/cloud'
6
6
  require 'pvcglue/packages'
7
7
  Dir[File.dirname(__FILE__) + '/pvcglue/packages/*.rb'].each { |file| require file }
8
+ Dir[File.dirname(__FILE__) + '/pvcglue/cloud_providers/*.rb'].each { |file| require file }
8
9
  require 'pvcglue/bootstrap'
9
10
  require 'pvcglue/nodes'
10
11
  require 'pvcglue/stack'
@@ -17,21 +18,45 @@ require 'pvcglue/toml_pvc_dumper'
17
18
  require 'pvcglue/local'
18
19
  require 'pvcglue/monit'
19
20
  require 'pvcglue/pvcify'
21
+ require 'pvcglue/docs'
20
22
  require 'tilt'
21
23
  require 'awesome_print'
22
24
  require 'hashie'
23
25
  require 'pvcglue/custom_hashie'
24
26
  require 'pvcglue/minion'
27
+ require 'pvcglue/cloud_providers'
25
28
  require 'droplet_kit'
26
- require 'pvcglue/digital_ocean'
29
+ # require 'pvcglue/digital_ocean'
27
30
  require 'logger'
28
31
  require 'pvcglue/connection'
29
32
  require 'paint'
30
- require 'pry'
33
+ # require 'pry'
34
+ require 'net/http'
35
+ require 'byebug'
36
+
37
+
38
+ # require 'thor'
39
+ # require 'tilt'
40
+ # require 'awesome_print'
41
+ # require 'hashie'
42
+ # require 'pvcglue/custom_hashie'
43
+ # require 'logger'
44
+ # Dir[File.dirname(__FILE__) + '/pvcglue/*.rb'].each { |file| require file unless File.basename(file) == 'cli.rb' }
45
+ # require 'pvcglue/cli'
46
+ # Dir[File.dirname(__FILE__) + '/pvcglue/packages/*.rb'].each { |file| require file }
47
+ # Dir[File.dirname(__FILE__) + '/pvcglue/cloud_providers/*.rb'].each { |file| require file }
48
+ # require 'droplet_kit'
49
+ # require 'paint'
50
+ # require 'pry'
51
+ # require 'net/http'
52
+ # require 'byebug'
31
53
 
32
54
  # puts File.join(File.dirname(__FILE__), 'pvcglue', 'packages', '*.rb')
33
55
  # pvc manager bootstrap --cloud_manager_override=local_cloud.pvcglue.toml --save_before_upload=save --verbose
34
56
 
57
+
58
+ # TODO: Set up a maintenance mode page and command to allow the message to be changed without a redeploy, like if Amazon S3 goes down...
59
+ #
35
60
  module Pvcglue
36
61
  # def self.reset!
37
62
  # ap Pvcglue.instance_variables
@@ -101,19 +126,19 @@ module Pvcglue
101
126
  # background = 'black'
102
127
  background = nil
103
128
  case severity[0..0]
104
- when 'E'
105
- foreground = 'red'
106
- when 'W'
107
- # foreground = 'black'
108
- # background = 'yellow'
109
- foreground = 'yellow'
110
- when 'I'
111
- foreground = 'purple'
112
- when 'D'
113
- foreground = 'cyan'
114
- else
115
- foreground = 'black'
116
- background = 'red'
129
+ when 'E'
130
+ foreground = 'red'
131
+ when 'W'
132
+ # foreground = 'black'
133
+ # background = 'yellow'
134
+ foreground = 'yellow'
135
+ when 'I'
136
+ foreground = 'purple'
137
+ when 'D'
138
+ foreground = 'cyan'
139
+ else
140
+ foreground = 'black'
141
+ background = 'red'
117
142
  end
118
143
  # case severity[0..0]
119
144
  # when 'E'
@@ -135,6 +160,10 @@ module Pvcglue
135
160
  mattr_accessor :logger_package_description
136
161
  mattr_accessor :logger_current_minion
137
162
 
163
+ mattr_accessor :docs do
164
+ Pvcglue::Docs.new(!!ARGV.detect { |arg| arg.downcase == '--docs' })
165
+ end
166
+
138
167
  def self.verbose?
139
168
  return if @filtering_verbose
140
169
  if Pvcglue.command_line_options[:verbose]
@@ -160,12 +189,15 @@ module Pvcglue
160
189
  end
161
190
 
162
191
  def self.template_file_name(template)
192
+ override = File.join(Pvcglue.configuration.template_override_dir, template)
193
+ return override if File.exists?(override)
163
194
  File.join(Pvcglue::gem_dir, 'lib', 'pvcglue', 'templates', template)
164
195
  end
165
196
 
166
197
  def self.render_template(template, file_name = nil)
167
198
  # puts '-'*80
168
199
  # puts "---> render_template(template=#{template}, file_name=#{file_name}"
200
+ # Pvcglue.logger.debug { "render_template(template=#{template}, file_name=#{file_name}" }
169
201
  data = Tilt.new(Pvcglue.template_file_name(template)).render
170
202
  if file_name
171
203
  File.write(file_name, data)
@@ -183,6 +215,14 @@ module Pvcglue
183
215
  true
184
216
  end
185
217
 
218
+ def self.system_get_stdout(cmd)
219
+ Pvcglue.logger.debug { cmd }
220
+ result = `#{cmd}`
221
+ Pvcglue.verbose? { result }
222
+ Pvcglue.logger.debug { "exit_code=#{$?.to_i}" }
223
+ result
224
+ end
225
+
186
226
  class Version
187
227
  def self.version
188
228
  VERSION
@@ -1,5 +1,4 @@
1
1
  require 'thor'
2
- require 'orca'
3
2
  require 'pvcglue'
4
3
 
5
4
  module Pvcglue
@@ -12,9 +11,10 @@ module Pvcglue
12
11
  class_option :force_cert
13
12
  class_option :provision_only
14
13
  class_option :quiet
15
- class_option :info
14
+ # class_option :info
16
15
  class_option :debug
17
16
  class_option :verbose
17
+ class_option :docs
18
18
 
19
19
  def initialize(args = [], local_options = {}, config = {})
20
20
  super
@@ -28,6 +28,7 @@ module Pvcglue
28
28
  desc "version", "show the version of PVC..."
29
29
 
30
30
  def version
31
+ byebug
31
32
  puts Pvcglue::Version.version
32
33
  end
33
34
 
@@ -261,6 +262,17 @@ module Pvcglue
261
262
  Pvcglue::Local.update_local_config_from_cache
262
263
  end
263
264
 
265
+ desc "render template", "debug use"
266
+ method_option :stage, :required => true, :aliases => "-s"
267
+
268
+ def render(template_file_name, machine_name = nil)
269
+ minion = machine_name.nil? ? nil : Pvcglue.cloud.find_minion_by_name(machine_name)
270
+ template = Tilt.new(Pvcglue.template_file_name(template_file_name))
271
+ data = template.render(self, minion: minion)
272
+ puts data
273
+ puts "---> Rendered '#{template_file_name}' from #{Pvcglue.template_file_name(template_file_name)}"
274
+ end
275
+
264
276
 
265
277
  end
266
278
 
@@ -15,7 +15,6 @@ module Pvcglue
15
15
  # attr_accessor :stage_secrets
16
16
 
17
17
 
18
-
19
18
  def data
20
19
  ::Pvcglue::Manager.initialize_cloud_data unless @data
21
20
  @data
@@ -335,9 +334,35 @@ module Pvcglue
335
334
  project[:gems] || {}
336
335
  end
337
336
 
337
+ def gem_file_data
338
+ @gem_file_data ||= begin
339
+ File.read(Pvcglue.configuration.gemfile_file_name)
340
+ end
341
+ end
342
+
343
+ def gem_installed?(gem)
344
+ value = gems[gem]
345
+ return value unless value == 'auto'
346
+ yield
347
+ end
348
+
338
349
  def whenever_gem_installed?
339
- data = File.read(Pvcglue.configuration.gemfile_file_name)
340
- data =~ /^\s*gem\s+['"]whenever['"]/
350
+ gem_installed?(:whenever) do
351
+ gem_file_data =~ /^\s*gem\s+['"]whenever['"]/
352
+ end
353
+ end
354
+
355
+ def delayed_job_gem_installed?
356
+ gem_installed?(:delayed_job) do
357
+ raise('Not implemented, yet. :(')
358
+ gem_file_data =~ /^\s*gem\s+['"]whenever['"]/
359
+ end
360
+ end
361
+
362
+ def sidekiq_gem_installed?
363
+ gem_installed?(:sidekiq) do
364
+ gem_file_data =~ /^\s*gem\s+['"]sidekiq['"]/
365
+ end
341
366
  end
342
367
 
343
368
  def db_rebuild
@@ -370,12 +395,12 @@ module Pvcglue
370
395
 
371
396
  def port_in_context(context)
372
397
  case context
373
- when :bootstrap, :manager
374
- port = "22"
375
- when :env, :build, :shell, :deploy, :maintenance
376
- port = project[:ssh_allowed_from_all_port] || "22"
377
- else
378
- raise "Context not specified or invalid"
398
+ when :bootstrap, :manager
399
+ port = "22"
400
+ when :env, :build, :shell, :deploy, :maintenance
401
+ port = project[:ssh_allowed_from_all_port] || "22"
402
+ else
403
+ raise "Context not specified or invalid"
379
404
  end
380
405
  puts "Setting port to #{port}"
381
406
  @port_in_node_context = port
@@ -538,25 +563,16 @@ module Pvcglue
538
563
  minion.users = machine.users
539
564
  minion.cloud_id = machine.cloud_id
540
565
  minion.remote_user_name = minion_user_name
541
- # TODO: sync all machine options here, automatically
542
- end
543
- # ap minion
544
- # puts "*"*175
545
- # ap minion.roles
546
- # ap item.role
547
- minion.roles << item.role
548
- # ap minion.roles
566
+ minion.machine_options = machine
549
567
 
550
- # if item.role_index?
551
- # minions
552
- # end
553
- # ap minion
568
+ minion.all_data = data
569
+ minion.project = project
570
+ minion.stage = stage
571
+ minion.default_cloud_provider = data.default_cloud_provider
572
+ minion.cloud = ::Pvcglue.cloud
573
+ end
554
574
 
555
- minion.all_data = data
556
- minion.project = project
557
- minion.stage = stage
558
- minion.cloud_provider = data.cloud_provider
559
- minion.cloud = ::Pvcglue.cloud
575
+ minion.roles << item.role
560
576
 
561
577
  minions[machine.name] = minion
562
578
  end
@@ -0,0 +1,34 @@
1
+ module Pvcglue
2
+ class CloudProviders
3
+ # REQUIRED_OPTIONS = []
4
+
5
+ def self.init(provider_options)
6
+ @options = provider_options
7
+ @name = provider_options.name
8
+ if provider_options.name == 'digital-ocean'
9
+ Pvcglue.logger.debug("Digital Ocean provider initialized for '#{provider_options.name}'.")
10
+ Pvcglue::CloudProviders::DigitalOcean.new(provider_options)
11
+ elsif provider_options.name == 'linode'
12
+ Pvcglue.logger.debug("Linode provider initialized for '#{provider_options.name}'.")
13
+ Pvcglue::CloudProviders::Linode.new(provider_options)
14
+ else
15
+ raise(Thor::Error, "Cloud Provider '#{provider_options.name}' not supported, use 'manual' mode.")
16
+ end
17
+ end
18
+
19
+ def name
20
+ @name
21
+ end
22
+
23
+ def options
24
+ @options
25
+ end
26
+
27
+ def validate_options!(options)
28
+ errors = []
29
+ REQUIRED_OPTIONS.each { |option_name| errors << "#{option_name} required" unless options[option_name] }
30
+ raise("Errors: #{errors.join(', ')}.") if errors.any?
31
+ end
32
+
33
+ end
34
+ end
@@ -0,0 +1,79 @@
1
+ module Pvcglue
2
+ class CloudProviders
3
+ REQUIRED_OPTIONS = %w(name region capacity image)
4
+
5
+ class DigitalOcean < Pvcglue::CloudProviders
6
+
7
+ def initialize(provider_options)
8
+ @options = provider_options
9
+ end
10
+
11
+ def create(options)
12
+ validate_options!(options)
13
+
14
+ opts = options.to_h
15
+ opts[:size] = opts.delete('capacity')
16
+
17
+ droplet_options = DropletKit::Droplet.new(opts)
18
+ droplet = client.droplets.create(droplet_options)
19
+ Pvcglue.logger.debug("Created Digital Ocean droplet, ID: #{droplet.id}")
20
+ droplet
21
+ end
22
+
23
+ def ready?(minion)
24
+ droplet = find_by_name(minion.machine_name)
25
+
26
+ droplet.raw_data[:status] == 'active'
27
+ end
28
+
29
+ def find_by_name(minion_name)
30
+ result = droplets.detect { |droplet| droplet.name == minion_name }
31
+ normalize_machine_data(result) if result
32
+ end
33
+
34
+ def reload_machine_data(minion)
35
+ find_by_name(minion.machine_name)
36
+ end
37
+
38
+ def normalize_machine_data(droplet)
39
+ machine = ::SafeMash.new
40
+ machine.raw_data = droplet
41
+ machine.id = droplet.id.to_s
42
+ machine.public_ip = get_public_ip(droplet)
43
+ machine.private_ip = get_private_ip(droplet)
44
+ machine.cloud_provider = 'digital-ocean'
45
+ machine
46
+ end
47
+
48
+ def get_private_ip(droplet)
49
+ get_ip_addresses(droplet).private
50
+ end
51
+
52
+ def get_public_ip(droplet)
53
+ get_ip_addresses(droplet).public
54
+ end
55
+
56
+ def droplets
57
+ client.droplets.all
58
+ # @droplets ||= client.droplets.all
59
+ end
60
+
61
+ def client
62
+ @client ||= get_client
63
+ end
64
+
65
+ def get_client
66
+ access_token = YAML::load(File.open(File.join(ENV['HOME'], '.config/doctl/config.yaml')))['access-token']
67
+ ::DropletKit::Client.new(access_token: access_token)
68
+ end
69
+
70
+ def get_ip_addresses(droplet)
71
+ ips = ::SafeMash.new
72
+ droplet.networks.v4.each do |network|
73
+ ips[network.type] = network.ip_address
74
+ end
75
+ ips
76
+ end
77
+ end
78
+ end
79
+ end
@@ -0,0 +1,129 @@
1
+ module Pvcglue
2
+ class CloudProviders
3
+ REQUIRED_OPTIONS = %w(name region capacity image)
4
+
5
+ class Linode < Pvcglue::CloudProviders
6
+
7
+ def create(options)
8
+ validate_options!(options)
9
+
10
+ cmd = "linode create #{options.name} "
11
+ cmd += "--location #{options.region} "
12
+ cmd += "--plan #{options.capacity} "
13
+ cmd += '--payment-term 1 '
14
+ cmd += "--distribution '#{options.image}' "
15
+ cmd += "--group '#{options.group}' " if options.group
16
+ cmd += "--password #{generate_password} "
17
+ cmd += "--pubkey-file '#{File.expand_path('~/.ssh/id_rsa.pub')}' "
18
+ cmd += '--json'
19
+
20
+ data, error = run(cmd)
21
+ raise(error) if error.present?
22
+
23
+ cmd = "linode ip-add --label #{options.name} --private "
24
+ cmd += '--json'
25
+ data, error = run(cmd)
26
+ raise(error) if error.present?
27
+
28
+ #<SafeMash staging-lb=#<SafeMash job="start" jobid=45919584 message="Completed. Booting staging-lb..." request_action="create" request_error="">>
29
+ machine = find_by_name(options.name)
30
+ Pvcglue.logger.debug("Created Linode, ID: #{machine.id}")
31
+ machine
32
+ end
33
+
34
+ def generate_password
35
+ password = "#{SecureRandom.hex}a1" # ensure required 'character classes'
36
+ Pvcglue.verbose? { password }
37
+ password
38
+ end
39
+
40
+ def reload_machine_data(minion)
41
+ find_by_name(minion.machine_name)
42
+ end
43
+
44
+ def ready?(minion)
45
+ machine = find_by_name(minion.machine_name)
46
+ machine.raw_data.values.first.status == 'running'
47
+ end
48
+
49
+ def find_by_name(name)
50
+ # return nil
51
+ cmd = "linode show --label #{name} "
52
+ cmd += '--json'
53
+
54
+ data, error = run(cmd)
55
+ if error =~ /Couldn't find/
56
+ return nil
57
+ elsif error.present?
58
+ raise(error)
59
+ end
60
+ normalize_machine_data(data)
61
+ end
62
+
63
+ =begin
64
+ > linode show staging-lb --json
65
+ {
66
+ "staging-lb" : {
67
+ "backupsenabled" : false,
68
+ "totalram" : "1.00GB",
69
+ "group" : "",
70
+ "request_error" : "",
71
+ "ips" : [
72
+ "192.168.132.194",
73
+ "104.237.159.149"
74
+ ],
75
+ "location" : "fremont",
76
+ "totalhd" : "20.00GB",
77
+ "status" : "running",
78
+ "label" : "staging-lb",
79
+ "request_action" : "show",
80
+ "linodeid" : 2817249
81
+ }
82
+ }
83
+ =end
84
+ def normalize_machine_data(data)
85
+ machine = ::SafeMash.new
86
+ machine.raw_data = data
87
+ machine.id = data.values.first.linodeid
88
+ machine.public_ip = get_public_ip(data.values.first.ips)
89
+ machine.private_ip = get_private_ip(data.values.first.ips)
90
+ machine.cloud_provider = 'linode'
91
+ machine
92
+ end
93
+
94
+ def get_private_ip(ips)
95
+ ips.each { |ip| return ip if is_private?(ip) }
96
+ nil
97
+ end
98
+
99
+ def get_public_ip(ips)
100
+ ips.each { |ip| return ip unless is_private?(ip) }
101
+ nil
102
+ end
103
+
104
+ def is_private?(ip)
105
+ ip =~ /^(?:10|127|172\.(?:1[6-9]|2[0-9]|3[01])|192\.168)\..*/m
106
+ end
107
+
108
+
109
+ def run(cmd)
110
+ result = Pvcglue.system_get_stdout(cmd)
111
+ data = ::SafeMash.new(JSON.parse(result))
112
+ Pvcglue.verbose? { data.inspect }
113
+ [data, request_error(data)]
114
+ end
115
+
116
+ def request_error(data)
117
+ data.values.first.request_error
118
+ end
119
+
120
+ # def get_ip_addresses(droplet)
121
+ # ips = ::SafeMash.new
122
+ # droplet.networks.v4.each do |network|
123
+ # ips[network.type] = network.ip_address
124
+ # end
125
+ # ips
126
+ # end
127
+ end
128
+ end
129
+ end