cloud-mu 3.0.1 → 3.0.2

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
  SHA256:
3
- metadata.gz: c0ab46aed6ed1aaf58e3d8de76de9ea27adc49cbd754b51cc4ef7e6354a78a26
4
- data.tar.gz: 5b341646d7533692813097af86fb37c46f1ba23fb0faf6acfe09688a3456e13c
3
+ metadata.gz: 1d41e45463915304c58cf78023563876314b9877087d44263e0ad3360ab6aea1
4
+ data.tar.gz: e3926bc8af2bb1cd7d6e2f32fe84e5de21b6073a7e7eda1be908a626f08becd4
5
5
  SHA512:
6
- metadata.gz: e9c62154b428aa93f247fbf61589372744a167814f0403a339640e1e96042c8ece774b57617127860e7cfa46dc95c0c666022c3872beac77987f496cea65ad00
7
- data.tar.gz: 12a4ced1bb6cbfe64ef666699a34bafe1aaf0228d080d6f8ee3584bcaec967084eca3d3a4167a405e05d1f8bc0d171093f7bab46e5648d1ff3339750a36c60e8
6
+ metadata.gz: 745bd6c7016676750b1306c324eca784821d026a6a255f4e0e33e09d5ca2843501ce3a774fa5cc9dc1b0e6a53270bce0ac79963fe25c1031d7ead2ddb1263c98
7
+ data.tar.gz: d0bf047ad4aa61a160368daa0a4897fa2904d183f1e478207e93c6e3cacecc1833dab04e9b3d634414298bee5a38ad0987a09e2226df79008b52fc67bac9cc95
data/bin/mu-configure CHANGED
@@ -107,6 +107,12 @@ $CONFIGURABLES = {
107
107
  "desc" => "The local system's value for HOSTNAME",
108
108
  "changes" => ["chefrun", "hostname"]
109
109
  },
110
+ "disable_mommacat" => {
111
+ "title" => "Disable Momma Cat",
112
+ "default" => false,
113
+ "desc" => "Disable the Momma Cat grooming daemon. Nodes which require asynchronous Ansible/Chef bootstraps will not function. This option is only honored in gem-based installations.",
114
+ "boolean" => true
115
+ },
110
116
  "mommacat_port" => {
111
117
  "title" => "Momma Cat Listen Port",
112
118
  "pattern" => /^[0-9]+$/i,
@@ -804,7 +810,7 @@ if !$NOOP
804
810
  # Converts the current $CONFIGURABLES object to a Hash suitable for merging
805
811
  # with $MU_CFG.
806
812
  def setConfigTree(tree = $CONFIGURABLES)
807
- cfg = {}
813
+ cfg = $MU_CFG.nil? ? {} : $MU_CFG.dup
808
814
  tree.each_pair { |key, data|
809
815
  next if !AMROOT and data['rootonly']
810
816
  if data.has_key?("subtree")
data/cloud-mu.gemspec CHANGED
@@ -17,8 +17,8 @@ end
17
17
 
18
18
  Gem::Specification.new do |s|
19
19
  s.name = 'cloud-mu'
20
- s.version = '3.0.1'
21
- s.date = '2019-11-22'
20
+ s.version = '3.0.2'
21
+ s.date = '2019-12-03'
22
22
  s.require_paths = ['modules']
23
23
  s.required_ruby_version = '>= 2.4'
24
24
  s.summary = "The eGTLabs Mu toolkit for unified cloud deployments"
@@ -59,4 +59,6 @@ EOF
59
59
  s.add_runtime_dependency 'addressable', '~> 2.5'
60
60
  s.add_runtime_dependency 'slack-notifier', "~> 2.3"
61
61
  s.add_runtime_dependency 'azure_sdk', "~> 0.37"
62
+ s.add_runtime_dependency 'rack', "~> 2.0"
63
+ s.add_runtime_dependency 'thin', "~> 1.7"
62
64
  end
data/modules/mu/cloud.rb CHANGED
@@ -1381,8 +1381,16 @@ module MU
1381
1381
  if !@config['vpc']["id"].nil? and @config['vpc']["id"].is_a?(Hash)
1382
1382
  @config['vpc']["id"] = MU::Config::Ref.new(@config['vpc']["id"])
1383
1383
  end
1384
- if !@config['vpc']["id"].nil? and @config['vpc']["id"].is_a?(MU::Config::Ref) and !@config['vpc']["id"].kitten.nil?
1385
- @vpc = @config['vpc']["id"].kitten
1384
+ if !@config['vpc']["id"].nil?
1385
+ if @config['vpc']["id"].is_a?(MU::Config::Ref) and !@config['vpc']["id"].kitten.nil?
1386
+ @vpc = @config['vpc']["id"].kitten
1387
+ else
1388
+ if @config['vpc']['habitat']
1389
+ @config['vpc']['habitat'] = MU::Config::Ref.get(@config['vpc']['habitat'])
1390
+ end
1391
+ vpc_ref = MU::Config::Ref.get(@config['vpc'])
1392
+ @vpc = vpc_ref.kitten
1393
+ end
1386
1394
  elsif !@config['vpc']["name"].nil? and @deploy
1387
1395
  MU.log "Attempting findLitterMate on VPC for #{self}", loglevel, details: @config['vpc']
1388
1396
 
@@ -2054,6 +2062,15 @@ puts "CHOOSING #{@vpc.to_s} 'cause it has #{@config['vpc']['subnet_name']}"
2054
2062
  cloudclass.cleanup(params)
2055
2063
  rescue MuCloudResourceNotImplemented
2056
2064
  MU.log "No #{cloud} implementation of #{shortname}.cleanup, skipping", MU::DEBUG, details: flags
2065
+ rescue Exception => e
2066
+ in_msg = cloud
2067
+ if params and params[:region]
2068
+ in_msg += " "+params[:region]
2069
+ end
2070
+ if params and params[:flags] and params[:flags]["project"]
2071
+ in_msg += " project "+params[:flags]["project"]
2072
+ end
2073
+ MU.log "Skipping #{shortname} cleanup method in #{in_msg} due to exception: #{e.message}", MU::WARN
2057
2074
  end
2058
2075
  }
2059
2076
  MU::MommaCat.unlockAll
@@ -1044,6 +1044,9 @@ module MU
1044
1044
  "credentials" => cluster["credentials"],
1045
1045
  "type" => "service"
1046
1046
  }
1047
+ if user["name"].length < 6
1048
+ user["name"] += Password.pronounceable(6)
1049
+ end
1047
1050
  configurator.insertKitten(user, "users", true)
1048
1051
  cluster['dependencies'] ||= []
1049
1052
  cluster['service_account'] = MU::Config::Ref.get(
@@ -45,8 +45,17 @@ module MU
45
45
  def create
46
46
  @cloud_id = @mu_name.downcase.gsub(/[^-a-z0-9]/, "-")
47
47
 
48
- vpc_id = @vpc.url if !@vpc.nil?
49
- vpc_id ||= @config['vpc']['vpc_id'] if @config['vpc'] and @config['vpc']['vpc_id']
48
+ vpc_id = if @vpc
49
+ @vpc.url if !@vpc.nil?
50
+ else
51
+ vpc_ref = MU::Config::Ref.get(@config['vpc'])
52
+ if !vpc_ref.kitten
53
+ MU.log "Failed to resolve VPC for FirewallRule #{@mu_name}", MU::ERR, details: @config['vpc']
54
+ raise MuError, "Failed to resolve VPC for FirewallRule #{@mu_name}"
55
+ else
56
+ vpc_ref.kitten.url
57
+ end
58
+ end
50
59
 
51
60
  if vpc_id.nil?
52
61
  raise MuError, "Failed to resolve VPC for #{self}"
@@ -419,16 +428,22 @@ end
419
428
  # @return [Boolean]: True if validation succeeded, False otherwise
420
429
  def self.validateConfig(acl, config)
421
430
  ok = true
422
- acl['project'] ||= MU::Cloud::Google.defaultProject(acl['credentials'])
423
431
 
424
432
  if acl['vpc']
425
- acl['vpc']['project'] ||= acl['project']
426
- acl['vpc'] = MU::Cloud::Google::VPC.pickVPC(
433
+ if !acl['vpc']['habitat']
434
+ acl['vpc']['project'] ||= acl['project']
435
+ elsif acl['vpc']['habitat'] and acl['vpc']['habitat']['id']
436
+ acl['vpc']['project'] = acl['vpc']['habitat']['id']
437
+ elsif acl['vpc']['habitat'] and acl['vpc']['habitat']['name']
438
+ acl['vpc']['project'] = acl['vpc']['habitat']['name']
439
+ end
440
+ correct_vpc = MU::Cloud::Google::VPC.pickVPC(
427
441
  acl['vpc'],
428
442
  acl,
429
443
  "firewall_rule",
430
444
  config
431
445
  )
446
+ acl['vpc'] = correct_vpc if correct_vpc
432
447
  end
433
448
 
434
449
  acl['rules'] ||= []
@@ -1424,6 +1424,9 @@ next if !create
1424
1424
  "credentials" => server["credentials"],
1425
1425
  "type" => "service"
1426
1426
  }
1427
+ if user["name"].length < 6
1428
+ user["name"] += Password.pronounceable(6)
1429
+ end
1427
1430
  if server['roles']
1428
1431
  user['roles'] = server['roles'].dup
1429
1432
  end
@@ -1432,13 +1435,13 @@ next if !create
1432
1435
  server['service_account'] = MU::Config::Ref.get(
1433
1436
  type: "users",
1434
1437
  cloud: "Google",
1435
- name: server["name"],
1436
- project: server["project"],
1437
- credentials: server["credentials"]
1438
+ name: user["name"],
1439
+ project: user["project"],
1440
+ credentials: user["credentials"]
1438
1441
  )
1439
1442
  server['dependencies'] << {
1440
1443
  "type" => "user",
1441
- "name" => server["name"]
1444
+ "name" => user["name"]
1442
1445
  }
1443
1446
  end
1444
1447
 
@@ -380,6 +380,9 @@ start = Time.now
380
380
  "credentials" => pool["credentials"],
381
381
  "type" => "service"
382
382
  }
383
+ if user["name"].length < 6
384
+ user["name"] += Password.pronounceable(6)
385
+ end
383
386
  configurator.insertKitten(user, "users", true)
384
387
  pool['dependencies'] ||= []
385
388
  pool['service_account'] = MU::Config::Ref.get(
@@ -165,8 +165,8 @@ module MU
165
165
 
166
166
  # blow up if this resource *has* to live in a project
167
167
  if cloudobj.cloudclass.canLiveIn == [:Habitat]
168
- MU.log "Failed to find project for cloudobj of class #{cloudobj.cloudclass.class.name}", MU::ERR, details: cloudobj
169
- raise MuError, "Failed to find project for cloudobj of class #{cloudobj.cloudclass.class.name}"
168
+ MU.log "Failed to find project for cloudobj #{cloudobj.to_s}", MU::ERR, details: cloudobj
169
+ raise MuError, "Failed to find project for cloudobj #{cloudobj.to_s}"
170
170
  end
171
171
 
172
172
  nil
@@ -816,6 +816,10 @@ MU.log e.message, MU::WARN, details: e.inspect
816
816
  def self.admin_directory(subclass = nil, credentials: nil)
817
817
  require 'google/apis/admin_directory_v1'
818
818
 
819
+ # fill in the default credential set name so we don't generate
820
+ # dopey extra warnings about falling back on scopes
821
+ credentials ||= MU::Cloud::Google.credConfig(credentials, name_only: true)
822
+
819
823
  writescopes = ['admin.directory.group.member', 'admin.directory.group', 'admin.directory.user', 'admin.directory.domain', 'admin.directory.orgunit', 'admin.directory.rolemanagement', 'admin.directory.customer', 'admin.directory.user.alias', 'admin.directory.userschema']
820
824
  readscopes = ['admin.directory.group.member.readonly', 'admin.directory.group.readonly', 'admin.directory.user.readonly', 'admin.directory.domain.readonly', 'admin.directory.orgunit.readonly', 'admin.directory.rolemanagement.readonly', 'admin.directory.customer.readonly', 'admin.directory.user.alias.readonly', 'admin.directory.userschema.readonly']
821
825
  @@readonly_semaphore.synchronize {
@@ -826,7 +830,7 @@ MU.log e.message, MU::WARN, details: e.inspect
826
830
 
827
831
  if subclass.nil?
828
832
  begin
829
- @@admin_directory_api[credentials] ||= MU::Cloud::Google::GoogleEndpoint.new(api: "AdminDirectoryV1::DirectoryService", scopes: use_scopes, masquerade: MU::Cloud::Google.credConfig(credentials)['masquerade_as'], credentials: credentials)
833
+ @@admin_directory_api[credentials] ||= MU::Cloud::Google::GoogleEndpoint.new(api: "AdminDirectoryV1::DirectoryService", scopes: use_scopes, masquerade: MU::Cloud::Google.credConfig(credentials)['masquerade_as'], credentials: credentials, auth_error_quiet: true)
830
834
  rescue Signet::AuthorizationError => e
831
835
  MU.log "Falling back to read-only access to DirectoryService API for credential set '#{credentials}'", MU::WARN
832
836
  @@admin_directory_api[credentials] ||= MU::Cloud::Google::GoogleEndpoint.new(api: "AdminDirectoryV1::DirectoryService", scopes: readscopes, masquerade: MU::Cloud::Google.credConfig(credentials)['masquerade_as'], credentials: credentials)
@@ -1035,7 +1039,7 @@ MU.log e.message, MU::WARN, details: e.inspect
1035
1039
  # Create a Google Cloud Platform API client
1036
1040
  # @param api [String]: Which API are we wrapping?
1037
1041
  # @param scopes [Array<String>]: Google auth scopes applicable to this API
1038
- def initialize(api: "ComputeV1::ComputeService", scopes: ['https://www.googleapis.com/auth/cloud-platform', 'https://www.googleapis.com/auth/compute.readonly'], masquerade: nil, credentials: nil)
1042
+ def initialize(api: "ComputeV1::ComputeService", scopes: ['https://www.googleapis.com/auth/cloud-platform', 'https://www.googleapis.com/auth/compute.readonly'], masquerade: nil, credentials: nil, auth_error_quiet: false)
1039
1043
  @credentials = credentials
1040
1044
  @scopes = scopes.map { |s|
1041
1045
  if !s.match(/\//) # allow callers to use shorthand
@@ -1052,11 +1056,16 @@ MU.log e.message, MU::WARN, details: e.inspect
1052
1056
  @api.authorization.sub = @masquerade
1053
1057
  @api.authorization.fetch_access_token!
1054
1058
  rescue Signet::AuthorizationError => e
1055
- MU.log "Cannot masquerade as #{@masquerade} to API #{api}: #{e.message}", MU::ERROR, details: @scopes
1056
- if e.message.match(/client not authorized for any of the scopes requested/)
1059
+ if auth_error_quiet
1060
+ MU.log "Cannot masquerade as #{@masquerade} to API #{api}: #{e.message}", MU::DEBUG, details: @scopes
1061
+ else
1062
+ MU.log "Cannot masquerade as #{@masquerade} to API #{api}: #{e.message}", MU::ERROR, details: @scopes
1063
+ if e.message.match(/client not authorized for any of the scopes requested/)
1057
1064
  # XXX it'd be helpful to list *all* scopes we like, as well as the API client's numeric id
1058
- MU.log "To grant access to API scopes for this service account, see:", MU::ERR, details: "https://admin.google.com/AdminHome?chromeless=1#OGX:ManageOauthClients"
1065
+ MU.log "To grant access to API scopes for this service account, see:", MU::ERR, details: "https://admin.google.com/AdminHome?chromeless=1#OGX:ManageOauthClients"
1066
+ end
1059
1067
  end
1068
+
1060
1069
  raise e
1061
1070
  end
1062
1071
  end
data/modules/mu/config.rb CHANGED
@@ -525,7 +525,7 @@ end
525
525
  region: @region,
526
526
  habitats: hab_arg,
527
527
  credentials: @credentials,
528
- dummy_ok: (["habitats", "folders", "users", "groups"].include?(@type))
528
+ dummy_ok: (["habitats", "folders", "users", "groups", "vpcs"].include?(@type))
529
529
  )
530
530
  @obj ||= found.first if found
531
531
  rescue ThreadError => e
@@ -1786,6 +1786,9 @@ $CONFIGURABLES
1786
1786
 
1787
1787
 
1788
1788
  acl = {"name" => name, "rules" => rules, "vpc" => realvpc, "cloud" => cloud, "admin" => true, "credentials" => credentials }
1789
+ if cloud == "Google" and acl["vpc"] and acl["vpc"]["habitat"]
1790
+ acl['project'] = acl["vpc"]["habitat"]["id"] || acl["vpc"]["habitat"]["name"]
1791
+ end
1789
1792
  acl.delete("vpc") if !acl["vpc"]
1790
1793
  if !resclass.isGlobal? and !region.nil? and !region.empty?
1791
1794
  acl["region"] = region
@@ -1972,6 +1975,13 @@ $CONFIGURABLES
1972
1975
 
1973
1976
  # Namespace magic to pass to ERB's result method.
1974
1977
  def get_binding(keyset)
1978
+ environment = $environment
1979
+ myPublicIp = $myPublicIp
1980
+ myRoot = $myRoot
1981
+ myAZ = $myAZ
1982
+ myRegion = $myRegion
1983
+ myAppName = $myAppName
1984
+
1975
1985
  # return MU::Config.global_bindings[keyset] if MU::Config.global_bindings[keyset]
1976
1986
  MU::Config.global_bindings[keyset] = binding
1977
1987
  MU::Config.global_bindings[keyset]
@@ -2762,6 +2762,9 @@ MESSAGE_END
2762
2762
  # Start the Momma Cat daemon and return the exit status of the command used
2763
2763
  # @return [Integer]
2764
2764
  def self.start
2765
+ if MU.inGem? and MU.muCfg['disable_mommacat']
2766
+ return
2767
+ end
2765
2768
  base = (Process.uid == 0 and !MU.localOnly) ? "/var" : MU.dataDir
2766
2769
  [base, "#{base}/log", "#{base}/run"].each { |dir|
2767
2770
  if !Dir.exist?(dir)
@@ -2784,20 +2787,19 @@ MESSAGE_END
2784
2787
 
2785
2788
  MU.log cmd, MU::NOTICE
2786
2789
 
2787
- output = %x{#{cmd}}
2788
-
2789
- Dir.chdir(origdir)
2790
-
2791
2790
  retries = 0
2792
2791
  begin
2792
+ output = %x{#{cmd}}
2793
2793
  sleep 1
2794
2794
  retries += 1
2795
2795
  if retries >= 10
2796
- MU.log "MommaCat failed to start (command was #{cmd})", MU::WARN, details: output
2796
+ MU.log "MommaCat failed to start (command was #{cmd}, working directory #{MU.myRoot}/modules)", MU::WARN, details: output
2797
2797
  pp caller
2798
2798
  return $?.exitstatus
2799
2799
  end
2800
2800
  end while !status
2801
+
2802
+ Dir.chdir(origdir)
2801
2803
 
2802
2804
  if $?.exitstatus != 0
2803
2805
  exit 1
@@ -2809,6 +2811,9 @@ MESSAGE_END
2809
2811
  # Return true if the Momma Cat daemon appears to be running
2810
2812
  # @return [Boolean]
2811
2813
  def self.status
2814
+ if MU.inGem? and MU.muCfg['disable_mommacat']
2815
+ return true
2816
+ end
2812
2817
  if File.exist?(daemonPidFile)
2813
2818
  pid = File.read(daemonPidFile).chomp.to_i
2814
2819
  begin
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: cloud-mu
3
3
  version: !ruby/object:Gem::Version
4
- version: 3.0.1
4
+ version: 3.0.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - John Stange
@@ -11,7 +11,7 @@ authors:
11
11
  autorequire:
12
12
  bindir: bin
13
13
  cert_chain: []
14
- date: 2019-11-22 00:00:00.000000000 Z
14
+ date: 2019-12-03 00:00:00.000000000 Z
15
15
  dependencies:
16
16
  - !ruby/object:Gem::Dependency
17
17
  name: erubis
@@ -355,6 +355,34 @@ dependencies:
355
355
  - - "~>"
356
356
  - !ruby/object:Gem::Version
357
357
  version: '0.37'
358
+ - !ruby/object:Gem::Dependency
359
+ name: rack
360
+ requirement: !ruby/object:Gem::Requirement
361
+ requirements:
362
+ - - "~>"
363
+ - !ruby/object:Gem::Version
364
+ version: '2.0'
365
+ type: :runtime
366
+ prerelease: false
367
+ version_requirements: !ruby/object:Gem::Requirement
368
+ requirements:
369
+ - - "~>"
370
+ - !ruby/object:Gem::Version
371
+ version: '2.0'
372
+ - !ruby/object:Gem::Dependency
373
+ name: thin
374
+ requirement: !ruby/object:Gem::Requirement
375
+ requirements:
376
+ - - "~>"
377
+ - !ruby/object:Gem::Version
378
+ version: '1.7'
379
+ type: :runtime
380
+ prerelease: false
381
+ version_requirements: !ruby/object:Gem::Requirement
382
+ requirements:
383
+ - - "~>"
384
+ - !ruby/object:Gem::Version
385
+ version: '1.7'
358
386
  description: |+
359
387
  The eGTLabs Mu toolkit for unified cloud deployments. This gem contains the Mu deployment interface to cloud provider APIs. It will generate a sample configuration the first time it is invoked.
360
388