cloud-mu 3.0.1 → 3.0.2

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