class Kitchen::Driver::Oci
Oracle OCI driver for Kitchen
.
@author Stephen Pearson <stephen.pearson@oracle.com>
Public Instance Methods
create(state)
click to toggle source
# File lib/kitchen/driver/oci.rb, line 68 def create(state) return if state[:server_id] state = process_windows_options(state) instance_id = launch_instance(state) state[:server_id] = instance_id state[:hostname] = instance_ip(instance_id) instance.transport.connection(state).wait_until_ready return unless config[:post_create_script] info('Running post create script') script = config[:post_create_script] instance.transport.connection(state).execute(script) end
destroy(state)
click to toggle source
# File lib/kitchen/driver/oci.rb, line 87 def destroy(state) return unless state[:server_id] instance.transport.connection(state).close if instance_type == 'compute' comp_api.terminate_instance(state[:server_id]) elsif instance_type == 'dbaas' dbaas_api.terminate_db_system(state[:server_id]) end state.delete(:server_id) state.delete(:hostname) end
process_windows_options(state)
click to toggle source
# File lib/kitchen/driver/oci.rb, line 112 def process_windows_options(state) state[:username] = config[:winrm_user] if config[:setup_winrm] if config[:setup_winrm] == true && config[:password].nil? && state[:password].nil? state[:password] = config[:winrm_password] || random_password end state end
Private Instance Methods
api_proxy()
click to toggle source
# File lib/kitchen/driver/oci.rb, line 148 def api_proxy prx = proxy_config return nil unless prx if prx.user OCI::ApiClientProxySettings.new(prx.host, prx.port, prx.user, prx.password) else OCI::ApiClientProxySettings.new(prx.host, prx.port) end end
comp_api()
click to toggle source
# File lib/kitchen/driver/oci.rb, line 175 def comp_api generic_api(OCI::Core::ComputeClient) end
compute_instance_ip(instance_id)
click to toggle source
# File lib/kitchen/driver/oci.rb, line 352 def compute_instance_ip(instance_id) vnic = vnics(instance_id).select(&:is_primary).first if public_ip_allowed? config[:use_private_ip] ? vnic.private_ip : vnic.public_ip else vnic.private_ip end end
compute_instance_request(state)
click to toggle source
# File lib/kitchen/driver/oci.rb, line 274 def compute_instance_request(state) request = compute_launch_details inject_powershell(state) if config[:setup_winrm] == true metadata = {} metadata.store('ssh_authorized_keys', pubkey) data = user_data metadata.store('user_data', data) if config[:user_data] && !config[:user_data].empty? request.metadata = metadata request end
compute_launch_details()
click to toggle source
# File lib/kitchen/driver/oci.rb, line 287 def compute_launch_details # rubocop:disable Metrics/MethodLength OCI::Core::Models::LaunchInstanceDetails.new.tap do |l| hostname = generate_hostname l.availability_domain = config[:availability_domain] l.compartment_id = config[:compartment_id] l.display_name = hostname l.source_details = instance_source_details l.shape = config[:shape] l.create_vnic_details = create_vnic_details(hostname) l.freeform_tags = process_freeform_tags(config[:freeform_tags]) l.preemptible_instance_config = preemptible_instance_config if config[:preemptible_instance] l.shape_config = shape_config unless config[:shape_config].empty? end end
create_database_details()
click to toggle source
# File lib/kitchen/driver/oci.rb, line 468 def create_database_details # rubocop:disable Metrics/MethodLength character_set = config[:dbaas][:character_set] ||= 'AL32UTF8' ncharacter_set = config[:dbaas][:ncharacter_set] ||= 'AL16UTF16' db_workload = config[:dbaas][:db_workload] ||= OCI::Database::Models::CreateDatabaseDetails::DB_WORKLOAD_OLTP admin_password = config[:dbaas][:admin_password] ||= random_password db_name = config[:dbaas][:db_name] ||= 'dbaas1' OCI::Database::Models::CreateDatabaseDetails.new.tap do |l| l.admin_password = admin_password l.character_set = character_set l.db_name = db_name l.db_workload = db_workload l.ncharacter_set = ncharacter_set l.pdb_name = config[:dbaas][:pdb_name] l.db_backup_config = db_backup_config end end
create_db_home_details()
click to toggle source
# File lib/kitchen/driver/oci.rb, line 458 def create_db_home_details raise 'db_version cannot be nil!' if config[:dbaas][:db_version].nil? OCI::Database::Models::CreateDbHomeDetails.new.tap do |l| l.database = create_database_details l.db_version = config[:dbaas][:db_version] l.display_name = ['dbhome', random_number(10)].compact.join('') end end
create_vnic_details(name)
click to toggle source
# File lib/kitchen/driver/oci.rb, line 326 def create_vnic_details(name) OCI::Core::Models::CreateVnicDetails.new( assign_public_ip: public_ip_allowed?, display_name: name, hostname_label: name, subnetId: config[:subnet_id] ) end
db_backup_config()
click to toggle source
# File lib/kitchen/driver/oci.rb, line 486 def db_backup_config OCI::Database::Models::DbBackupConfig.new.tap do |l| l.auto_backup_enabled = false end end
dbaas_api()
click to toggle source
# File lib/kitchen/driver/oci.rb, line 183 def dbaas_api generic_api(OCI::Database::DatabaseClient) end
dbaas_instance_ip(instance_id)
click to toggle source
# File lib/kitchen/driver/oci.rb, line 513 def dbaas_instance_ip(instance_id) vnic = dbaas_node(instance_id).select(&:vnic_id).first.vnic_id if public_ip_allowed? net_api.get_vnic(vnic).data.public_ip else net_api.get_vnic(vnic).data.private_ip end end
dbaas_launch_details()
click to toggle source
# File lib/kitchen/driver/oci.rb, line 433 def dbaas_launch_details # rubocop:disable Metrics/MethodLength cpu_core_count = config[:dbaas][:cpu_core_count] ||= 2 database_edition = config[:dbaas][:database_edition] ||= OCI::Database::Models::DbSystem::DATABASE_EDITION_ENTERPRISE_EDITION initial_data_storage_size_in_gb = config[:dbaas][:initial_data_storage_size_in_gb] ||= 256 license_model = config[:dbaas][:license_model] ||= OCI::Database::Models::DbSystem::LICENSE_MODEL_BRING_YOUR_OWN_LICENSE OCI::Database::Models::LaunchDbSystemDetails.new.tap do |l| l.availability_domain = config[:availability_domain] l.compartment_id = config[:compartment_id] l.cpu_core_count = cpu_core_count l.database_edition = database_edition l.db_home = create_db_home_details l.display_name = [config[:hostname_prefix], random_string(4), random_number(2)].compact.join('-') l.hostname = generate_hostname l.shape = config[:shape] l.ssh_public_keys = pubkey l.cluster_name = generate_cluster_name l.initial_data_storage_size_in_gb = initial_data_storage_size_in_gb l.node_count = 1 l.license_model = license_model l.subnet_id = config[:subnet_id] l.freeform_tags = process_freeform_tags(config[:freeform_tags]) end end
dbaas_node(instance_id)
click to toggle source
# File lib/kitchen/driver/oci.rb, line 502 def dbaas_node(instance_id) dbaas_api.list_db_nodes( config[:compartment_id], db_system_id: instance_id ).data end
dbaas_vnic(node_ocid)
click to toggle source
# File lib/kitchen/driver/oci.rb, line 509 def dbaas_vnic(node_ocid) dbaas_api.get_db_node(node_ocid).data end
generate_cluster_name()
click to toggle source
# File lib/kitchen/driver/oci.rb, line 492 def generate_cluster_name prefix = config[:hostname_prefix].split('-')[0] # 11 character limit for cluster_name in DBaaS if prefix.length >= 11 prefix[0, 11] else [prefix, random_string(10 - prefix.length)].compact.join('-') end end
generate_hostname()
click to toggle source
# File lib/kitchen/driver/oci.rb, line 220 def generate_hostname prefix = config[:hostname_prefix] if instance_type == 'compute' [prefix, random_hostname(instance.name)].compact.join('-') elsif instance_type == 'dbaas' # 30 character limit for hostname in DBaaS if prefix.length >= 30 [prefix[0, 26], 'db1'].compact.join('-') else [prefix, random_string(25 - prefix.length), 'db1'].compact.join('-') end end end
generic_api(klass)
click to toggle source
API setup #
# File lib/kitchen/driver/oci.rb, line 163 def generic_api(klass) api_prx = api_proxy if config[:use_instance_principals] sign = OCI::Auth::Signers::InstancePrincipalsSecurityTokenSigner.new params = { signer: sign } else params = { config: oci_config } end params[:proxy_settings] = api_prx if api_prx klass.new(**params) end
inject_powershell(state)
click to toggle source
# File lib/kitchen/driver/oci.rb, line 367 def inject_powershell(state) data = winrm_ps1(state) config[:user_data] ||= [] config[:user_data] << { type: 'x-shellscript', inline: data, filename: 'setup_winrm.ps1' } end
instance_ip(instance_id)
click to toggle source
# File lib/kitchen/driver/oci.rb, line 203 def instance_ip(instance_id) if instance_type == 'compute' compute_instance_ip(instance_id) elsif instance_type == 'dbaas' dbaas_instance_ip(instance_id) end end
instance_source_details()
click to toggle source
# File lib/kitchen/driver/oci.rb, line 302 def instance_source_details OCI::Core::Models::InstanceSourceViaImageDetails.new( sourceType: 'image', imageId: config[:image_id] ) end
instance_type()
click to toggle source
# File lib/kitchen/driver/oci.rb, line 124 def instance_type raise 'instance_type must be either compute or dbaas!' unless %w[compute dbaas].include?(config[:instance_type].downcase) config[:instance_type].downcase end
launch_compute_instance(state)
click to toggle source
Compute methods #
# File lib/kitchen/driver/oci.rb, line 262 def launch_compute_instance(state) request = compute_instance_request(state) response = comp_api.launch_instance(request) instance_id = response.data.id comp_api.get_instance(instance_id).wait_until( :lifecycle_state, OCI::Core::Models::Instance::LIFECYCLE_STATE_RUNNING ) instance_id end
launch_dbaas_instance()
click to toggle source
DBaaS methods #
# File lib/kitchen/driver/oci.rb, line 419 def launch_dbaas_instance request = dbaas_launch_details response = dbaas_api.launch_db_system(request) instance_id = response.data.id dbaas_api.get_db_system(instance_id).wait_until( :lifecycle_state, OCI::Database::Models::DbSystem::LIFECYCLE_STATE_AVAILABLE, max_interval_seconds: 900, max_wait_seconds: 21600 ) instance_id end
launch_instance(state)
click to toggle source
Common methods #
# File lib/kitchen/driver/oci.rb, line 190 def launch_instance(state) if instance_type == 'compute' launch_compute_instance(state) elsif instance_type == 'dbaas' launch_dbaas_instance end end
mime_parts(boundary)
click to toggle source
# File lib/kitchen/driver/oci.rb, line 388 def mime_parts(boundary) msg = [] config[:user_data].each do |m| msg << "--#{boundary}" msg << "Content-Disposition: attachment; filename=\"#{m[:filename]}\"" msg << 'Content-Transfer-Encoding: 7bit' msg << "Content-Type: text/#{m[:type]}" << 'Mime-Version: 1.0' << '' msg << read_part(m) << '' end msg << "--#{boundary}--" msg end
net_api()
click to toggle source
# File lib/kitchen/driver/oci.rb, line 179 def net_api generic_api(OCI::Core::VirtualNetworkClient) end
oci_config()
click to toggle source
OCI config setup #
# File lib/kitchen/driver/oci.rb, line 133 def oci_config opts = {} opts[:config_file_location] = config[:oci_config_file] if config[:oci_config_file] opts[:profile_name] = config[:oci_profile_name] if config[:oci_profile_name] OCI::ConfigFileLoader.load_config(**opts) end
preemptible_instance_config()
click to toggle source
# File lib/kitchen/driver/oci.rb, line 309 def preemptible_instance_config OCI::Core::Models::PreemptibleInstanceConfigDetails.new( preemption_action: OCI::Core::Models::TerminatePreemptionAction.new( type: 'TERMINATE', preserve_boot_volume: true ) ) end
proxy_config()
click to toggle source
# File lib/kitchen/driver/oci.rb, line 140 def proxy_config if config[:proxy_url] URI.parse(config[:proxy_url]) else URI.parse('http://').find_proxy end end
pubkey()
click to toggle source
# File lib/kitchen/driver/oci.rb, line 211 def pubkey if instance_type == 'compute' File.readlines(config[:ssh_keypath]).first.chomp elsif instance_type == 'dbaas' result = [] result << File.readlines(config[:ssh_keypath]).first.chomp end end
public_ip_allowed?()
click to toggle source
# File lib/kitchen/driver/oci.rb, line 198 def public_ip_allowed? subnet = net_api.get_subnet(config[:subnet_id]).data !subnet.prohibit_public_ip_on_vnic end
random_hostname(prefix)
click to toggle source
# File lib/kitchen/driver/oci.rb, line 234 def random_hostname(prefix) "#{prefix}-#{random_string(6)}" end
random_number(length)
click to toggle source
# File lib/kitchen/driver/oci.rb, line 255 def random_number(length) Array.new(length) { ('0'..'9').to_a.sample }.join end
random_password()
click to toggle source
# File lib/kitchen/driver/oci.rb, line 238 def random_password if instance_type == 'compute' special_chars = %w[@ - ( ) .] elsif instance_type == 'dbaas' special_chars = %w[# _ -] end (Array.new(5) { special_chars.sample } + Array.new(5) { ('a'..'z').to_a.sample } + Array.new(5) { ('A'..'Z').to_a.sample } + Array.new(5) { ('0'..'9').to_a.sample }).shuffle.join end
random_string(length)
click to toggle source
# File lib/kitchen/driver/oci.rb, line 251 def random_string(length) Array.new(length) { ('a'..'z').to_a.sample }.join end
read_part(part)
click to toggle source
# File lib/kitchen/driver/oci.rb, line 377 def read_part(part) if part[:path] content = File.read part[:path] elsif part[:inline] content = part[:inline] else raise 'Invalid user data' end content.split("\n") end
shape_config()
click to toggle source
# File lib/kitchen/driver/oci.rb, line 318 def shape_config OCI::Core::Models::LaunchInstanceShapeConfigDetails.new( ocpus: config[:shape_config][:ocpus], memory_in_gbs: config[:shape_config][:memory_in_gbs], baseline_ocpu_utilization: config[:shape_config][:baseline_ocpu_utilization] || 'BASELINE_1_1' ) end
user_data()
click to toggle source
# File lib/kitchen/driver/oci.rb, line 401 def user_data # rubocop:disable Metrics/MethodLength if config[:user_data].is_a? Array boundary = "MIMEBOUNDARY_#{random_string(20)}" msg = ["Content-Type: multipart/mixed; boundary=\"#{boundary}\"", 'MIME-Version: 1.0', ''] msg += mime_parts(boundary) txt = msg.join("\n") + "\n" gzip = Zlib::GzipWriter.new(StringIO.new) gzip << txt Base64.encode64(gzip.close.string).delete("\n") elsif config[:user_data].is_a? String Base64.encode64(config[:user_data]).delete("\n") end end
vnic_attachments(instance_id)
click to toggle source
# File lib/kitchen/driver/oci.rb, line 341 def vnic_attachments(instance_id) att = comp_api.list_vnic_attachments( config[:compartment_id], instance_id: instance_id ).data raise 'Could not find any VNIC attachments' unless att.any? att end
vnics(instance_id)
click to toggle source
# File lib/kitchen/driver/oci.rb, line 335 def vnics(instance_id) vnic_attachments(instance_id).map do |att| net_api.get_vnic(att.vnic_id).data end end
winrm_ps1(state)
click to toggle source
# File lib/kitchen/driver/oci.rb, line 361 def winrm_ps1(state) filename = File.join(__dir__, %w[.. .. .. tpl setup_winrm.ps1.erb]) tpl = ERB.new(File.read(filename)) tpl.result(binding) end