integrtae GCP Cloud DNS from the gce provider

This commit is contained in:
Samuel Beaulieu 2022-07-27 10:19:22 -05:00
parent 48ecaa7320
commit c028000a61
No known key found for this signature in database
GPG key ID: 12030F74136D0F34
5 changed files with 53 additions and 13 deletions

View file

@ -25,7 +25,16 @@ These steps expect two environment vars
### DNS ### DNS
AWS will setup a private ip and private dns hostname for the VM once running. Optionally we can setup a human readable DNS entry to resolve the VMPooler provider `spicy-proton` fqdn AWS will setup a private ip and private dns hostname for the VM once running. Optionally we can setup a human readable DNS entry to resolve the VMPooler provider `spicy-proton` fqdn
DNS is integrated via Google's CloudDNS service. To enable, a CloudDNS zone name must be provided in the config (see the example yaml file dns_zone_resource_name) DNS is integrated via Google's CloudDNS service.
GCE authorization is handled via a service account (or personal account) private key (json format) and can be configured via
1. GOOGLE_APPLICATION_CREDENTIALS environment variable eg GOOGLE_APPLICATION_CREDENTIALS=/my/home/directory/my_account_key.json
Provider config needed:
1. domain
2. project
3. dns_zone_resource_name
(see the example yaml file)
An A record is then created in that zone upon instance creation with the VM's internal IP, and deleted when the instance is destroyed. An A record is then created in that zone upon instance creation with the VM's internal IP, and deleted when the instance is destroyed.
@ -44,8 +53,7 @@ do not have the pool label, and can be configured to allow a specific list of un
### Pre-requisite ### Pre-requisite
- An IAM user must exist in the target AWS account with permissions to create, delete vms etc - An IAM user must exist in the target AWS account with permissions to create, delete vms etc
- if using DNS, a DNS zone needs to be created in CloudDNS, and configured in the provider's config section with the name of that zone (dns_zone_resource_name). When not specified, the DNS setup and teardown is skipped. - if using DNS see section above, and a service account with permissions to change Cloud DNS need to exist
## License ## License

View file

@ -3,6 +3,7 @@
require 'bigdecimal' require 'bigdecimal'
require 'bigdecimal/util' require 'bigdecimal/util'
require 'vmpooler/providers/base' require 'vmpooler/providers/base'
require 'vmpooler/cloud_dns'
require 'aws-sdk-ec2' require 'aws-sdk-ec2'
require 'vmpooler/aws_setup' require 'vmpooler/aws_setup'
@ -61,8 +62,6 @@ module Vmpooler
end end
end end
attr_reader :dns
# main configuration options # main configuration options
def region def region
return provider_config['region'] if provider_config['region'] return provider_config['region'] if provider_config['region']
@ -85,6 +84,10 @@ module Vmpooler
end end
# dns # dns
def project
provider_config['project']
end
def domain def domain
provider_config['domain'] provider_config['domain']
end end
@ -267,10 +270,13 @@ module Vmpooler
@logger.log('s', "[>] [#{pool_name}] '#{new_vmname}' instance ready to accept traffic") @logger.log('s', "[>] [#{pool_name}] '#{new_vmname}' instance ready to accept traffic")
created_instance = get_vm(pool_name, new_vmname) created_instance = get_vm(pool_name, new_vmname)
@redis.hset("vmpooler__vm__#{new_vmname}", 'host', created_instance['name']) @redis.with_metrics do |redis|
redis.hset("vmpooler__vm__#{new_vmname}", 'host', created_instance['name'])
end
# extra setup steps # extra setup steps
provision_node_aws(created_instance['private_dns_name'], pool_name, new_vmname) if to_provision(pool_name) == 'true' || to_provision(pool_name) == true provision_node_aws(created_instance['private_dns_name'], pool_name, new_vmname) if to_provision(pool_name) == 'true' || to_provision(pool_name) == true
dns_setup(created_instance) if domain
created_instance created_instance
end end
@ -363,7 +369,7 @@ module Vmpooler
# [String] vm_name : Name of the existing VM # [String] vm_name : Name of the existing VM
# returns # returns
# [boolean] true : once the operations are finished # [boolean] true : once the operations are finished
def destroy_vm(_pool_name, vm_name) def destroy_vm(pool_name, vm_name)
debug_logger('destroy_vm') debug_logger('destroy_vm')
deleted = false deleted = false
@ -374,6 +380,7 @@ module Vmpooler
instances = connection.instances(filters: filters).first instances = connection.instances(filters: filters).first
return true if instances.nil? return true if instances.nil?
instance_hash = get_vm(pool_name, vm_name)
debug_logger("trigger delete_instance #{vm_name}") debug_logger("trigger delete_instance #{vm_name}")
# vm_hash = get_vm(pool_name, vm_name) # vm_hash = get_vm(pool_name, vm_name)
instances.terminate instances.terminate
@ -384,6 +391,8 @@ module Vmpooler
debug_logger("failed waiting for instance terminated #{vm_name}: #{e}") debug_logger("failed waiting for instance terminated #{vm_name}: #{e}")
end end
dns_teardown(instance_hash) if domain
deleted deleted
end end
@ -437,6 +446,16 @@ module Vmpooler
# END BASE METHODS # END BASE METHODS
def dns_setup(created_instance)
dns = Vmpooler::PoolManager::CloudDns.new(project, dns_zone_resource_name)
dns.dns_create_or_replace(created_instance)
end
def dns_teardown(created_instance)
dns = Vmpooler::PoolManager::CloudDns.new(project, dns_zone_resource_name)
dns.dns_teardown(created_instance)
end
def get_current_user(vm_name) def get_current_user(vm_name)
@redis.with_metrics do |redis| @redis.with_metrics do |redis|
user = redis.hget("vmpooler__vm__#{vm_name}", 'token:user') user = redis.hget("vmpooler__vm__#{vm_name}", 'token:user')
@ -494,6 +513,7 @@ module Vmpooler
'status' => vm_object.state&.name, # One of the following values: pending, running, shutting-down, terminated, stopping, stopped 'status' => vm_object.state&.name, # One of the following values: pending, running, shutting-down, terminated, stopping, stopped
# 'zone' => vm_object.zone, # 'zone' => vm_object.zone,
'image_size' => vm_object.instance_type, 'image_size' => vm_object.instance_type,
'ip' => vm_object.private_ip_address,
'private_ip_address' => vm_object.private_ip_address, 'private_ip_address' => vm_object.private_ip_address,
'private_dns_name' => vm_object.private_dns_name 'private_dns_name' => vm_object.private_dns_name
} }

View file

@ -53,23 +53,28 @@ EOT
describe '#manual tests live' do describe '#manual tests live' do
context 'in itsysops' do context 'in itsysops' do
let(:vmname) { "instance-50" } let(:vmname) { "instance-60" }
let(:poolname) { "ubuntu-2004-arm64" } let(:poolname) { "amazon-7-x86_64-local" }
let(:amisize) { "c5.xlarge" }
let(:config) { YAML.load(<<~EOT let(:config) { YAML.load(<<~EOT
--- ---
:config: :config:
max_tries: 3 max_tries: 3
retry_factor: 10 retry_factor: 10
site_name: 'vmpooler-local-dev'
:providers: :providers:
:ec2: :ec2:
connection_pool_timeout: 1 connection_pool_timeout: 1
zone: '#{zone}' zone: '#{zone}'
region: '#{region}' region: '#{region}'
project: 'vmpooler-test'
dns_zone_resource_name: 'vmpooler-test-puppet-net'
domain: 'vmpooler-test.puppet.net'
:pools: :pools:
- name: '#{poolname}' - name: '#{poolname}'
alias: [ 'mockpool' ] alias: [ 'mockpool' ]
amisize: 'a1.large' amisize: '#{amisize}'
template: 'ami-03c1b544a7566b3e5' template: 'ami-31394949'
size: 5 size: 5
timeout: 10 timeout: 10
ready_ttl: 1440 ready_ttl: 1440
@ -83,6 +88,7 @@ EOT
} }
skip 'gets a vm' do skip 'gets a vm' do
result = subject.create_vm(poolname, vmname) result = subject.create_vm(poolname, vmname)
result = subject.destroy_vm(poolname, vmname)
#subject.vms_in_pool("amazon-6-x86_64-ec2") #subject.vms_in_pool("amazon-6-x86_64-ec2")
#subject.provision_node_aws("ip-10-227-4-97.amz-dev.puppet.net", poolname) #subject.provision_node_aws("ip-10-227-4-97.amz-dev.puppet.net", poolname)
# subject.create_snapshot(poolname, vmname, "foo") # subject.create_snapshot(poolname, vmname, "foo")

View file

@ -16,9 +16,11 @@ Gem::Specification.new do |s|
s.files = Dir[ "lib/**/*" ] s.files = Dir[ "lib/**/*" ]
s.require_paths = ["lib"] s.require_paths = ["lib"]
s.add_dependency 'aws-sdk-ec2', '~> 1' s.add_dependency 'aws-sdk-ec2', '~> 1'
s.add_dependency 'net-ssh', '~> 6.2.0.rc2' s.add_dependency 'net-ssh', '>= 6.2', '< 7.1'
s.add_development_dependency 'vmpooler', '>= 1.3.0', '~> 2.3' s.add_development_dependency 'vmpooler', '>= 1.3.0', '~> 2.3'
#s.add_development_dependency 'vmpooler-provider-gce', '>= 0.4.0', '~> 0.4'
s.add_development_dependency 'vmpooler-provider-gce', '>= 0.4.0', '~> 0.4'
# Testing dependencies # Testing dependencies
s.add_development_dependency 'climate_control', '>= 0.2.0' s.add_development_dependency 'climate_control', '>= 0.2.0'

View file

@ -81,7 +81,10 @@
# Overwrites the global domain parameter. This should match the dns zone domain set for the dns_zone_resource_name. # Overwrites the global domain parameter. This should match the dns zone domain set for the dns_zone_resource_name.
# It is used to infer the domain part of the FQDN ie $vm_name.$domain # It is used to infer the domain part of the FQDN ie $vm_name.$domain
# When setting multiple providers at the same time, this value should be set for each GCE pools. # When setting multiple providers at the same time, this value should be set for each GCE pools.
# (optional) If not explicitely set, the FQDN is inferred using the global 'domain' config parameter # (optional) when not set, the dns setup / teardown is skipped and the instance is reachable via the private_dns_name
# - project
# The GCP project name where the DNS zone resource exists
# (optional)
# Example: # Example:
:aws: :aws:
@ -91,6 +94,7 @@
volume_size: '10' volume_size: '10'
dns_zone_resource_name: 'subdomain-example-com' dns_zone_resource_name: 'subdomain-example-com'
domain: 'subdomain.example.com' domain: 'subdomain.example.com'
project: 'gcp-project-1'
# :pools: # :pools:
# #