pvcglue 0.9.3 → 0.9.4

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
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