vagrant-oci 0.1.1

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 ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: 72d739d292b54d5033ecf2c7d35e17f23d488049eccb24f5ea9fb0866253a270
4
+ data.tar.gz: 2e45ec6e8e308db1c175a4c06aee21c4617e40edfb432657c780d20f770d2ff2
5
+ SHA512:
6
+ metadata.gz: 2f80ef326a3f181483cc2b75fc7ce50a518c19012ad1136d9bddfcba632b957e6764f8974cf5b4d4e21dcd12a3a4b24c386964ac326d1a0809d18a577748f06f
7
+ data.tar.gz: 2a1e97b3b3066dc9a337dc573e2c1107facb634f49c53a317ebebe653ee3a81aad0120d24f9de9fe9a3d9053204a8ebcac58b557ecadce8f41bb905df381ac46
data/.gitignore ADDED
@@ -0,0 +1,11 @@
1
+ Gemfile.lock
2
+ /.bundle/
3
+ /.yardoc
4
+ /_yardoc/
5
+ /coverage/
6
+ /doc/
7
+ /pkg/
8
+ /spec/reports/
9
+ /tmp/
10
+ .vagrant
11
+ /example_box/*.box
data/Gemfile ADDED
@@ -0,0 +1,12 @@
1
+ source "https://rubygems.org"
2
+
3
+ # Specify your gem's dependencies in vagrant-oci.gemspec
4
+
5
+ group :development do
6
+ gem "vagrant", git: "https://github.com/hashicorp/vagrant.git"
7
+ end
8
+
9
+ group :plugins do
10
+ gemspec
11
+ end
12
+
data/README.md ADDED
@@ -0,0 +1,20 @@
1
+ # Vagrant OCI Plugin
2
+
3
+ A Vagrant plugin for Oracle Cloud Infrastructure (OCI)
4
+
5
+ ## Installation
6
+
7
+ Build the gem:
8
+
9
+ ```bash
10
+ rake build
11
+ ```
12
+
13
+ Install it into Vagrant:
14
+ ```bash
15
+ vagrant plugin install ./pkg/vagrant-oci-<version>.gem
16
+ ```
17
+
18
+ ## Usage
19
+
20
+ See the example [Vagrantfile](Vagrantfile.sample/Vagrantfile)
data/Rakefile ADDED
@@ -0,0 +1,2 @@
1
+ require "bundler/gem_tasks"
2
+ task :default => :spec
@@ -0,0 +1,50 @@
1
+ # -*- mode: ruby -*-
2
+ # vi: set ft=ruby :
3
+
4
+ Vagrant.configure("2") do |config|
5
+ # Dummy box for oci provider, not the image ocid.
6
+ # Leave alone unless you know what you're doing.
7
+ config.vm.box = "stephenpearson/oci"
8
+
9
+ # For remote cloud instances, use rsync synced folders.
10
+ config.vm.synced_folder ".", "/vagrant", type: 'rsync'
11
+
12
+ # Define default provider options
13
+ config.vm.provider :oci do |oci, override|
14
+ oci.config_file = '~/.oci/config'
15
+ oci.profile = 'DEFAULT'
16
+ oci.region = 'us-phoenix-1'
17
+ override.ssh.username = 'opc'
18
+ override.ssh.private_key_path = '~/.ssh/id_rsa'
19
+ # override.ssh.port = 22
20
+ # oci.defined_tags = {
21
+ # MyTagNameSpace: {
22
+ # foo: "bar"
23
+ # }
24
+ # }
25
+ end
26
+
27
+ config.vm.define :srv1 do |srv1|
28
+ srv1.vm.provision :ansible do |ansible|
29
+ ansible.playbook = "site.yml"
30
+ end
31
+ srv1.vm.provider :oci do |oci, override|
32
+ # oci.freeform_tags = {
33
+ # vagrant: "true"
34
+ # }
35
+ oci.shape = 'VM.Standard2.1'
36
+ oci.image_compartment_name = 'Images'
37
+ oci.image_regex = '^Oracle-Linux-7.6-20'
38
+ oci.server_compartment_name = 'Infrastructure'
39
+ # Ensure the AD matches the subnet's AD (except for regional subnets).
40
+ oci.ad = 1
41
+
42
+ oci.subnet_vcn_compartment_name = 'Networks'
43
+ oci.subnet_vcn_dns_label = 'phx1'
44
+ oci.subnet_compartment_name = 'Networks'
45
+ oci.subnet_dns_label = 'wh1n1'
46
+
47
+ # oci.use_private_network = false
48
+ end
49
+ end
50
+ end
@@ -0,0 +1,11 @@
1
+ ---
2
+ - name: Test
3
+ hosts:
4
+ - all
5
+
6
+ become: true
7
+ become_user: root
8
+
9
+ tasks:
10
+ - debug:
11
+ msg: "hello world"
@@ -0,0 +1,13 @@
1
+ # Vagrant OCI Example Box
2
+
3
+ Vagrant providers each require a custom provider-specific box format.
4
+ This folder shows the example contents of a box for the `oci` provider.
5
+ To turn this into a box:
6
+
7
+ ```
8
+ $ tar cvzf oci.box ./metadata.json ./Vagrantfile
9
+ ```
10
+
11
+ This box works by using Vagrant's built-in Vagrantfile merging to setup
12
+ defaults for OCI. These defaults can easily be overwritten by higher-level
13
+ Vagrantfiles (such as project root Vagrantfiles).
@@ -0,0 +1,7 @@
1
+ # -*- mode: ruby -*-
2
+ # vi: set ft=ruby :
3
+
4
+ Vagrant.configure("2") do |config|
5
+ config.vm.provider :oci do |oci|
6
+ end
7
+ end
@@ -0,0 +1,3 @@
1
+ {
2
+ "provider": "oci"
3
+ }
@@ -0,0 +1,18 @@
1
+ require "pathname"
2
+
3
+ require "vagrant-oci/plugin"
4
+
5
+ module VagrantPlugins
6
+ module OCI
7
+ lib_path = Pathname.new(File.expand_path("../vagrant-oci", __FILE__))
8
+ autoload :Action, lib_path.join("action")
9
+ autoload :Errors, lib_path.join("errors")
10
+
11
+ # This returns the path to the source of this plugin.
12
+ #
13
+ # @return [Pathname]
14
+ def self.source_root
15
+ @source_root ||= Pathname.new(File.expand_path("../../", __FILE__))
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,160 @@
1
+ require "vagrant/action/builder"
2
+
3
+ module VagrantPlugins
4
+ module OCI
5
+ module Action # rubocop:disable Metrics/ModuleLength
6
+ # Include the built-in modules so we can use them as top-level things.
7
+ include Vagrant::Action::Builtin
8
+
9
+ def self.action_read_state
10
+ Vagrant::Action::Builder.new.tap do |b|
11
+ b.use ConfigValidate
12
+ b.use ConnectOCI
13
+ b.use ReadState
14
+ end
15
+ end
16
+
17
+ def self.action_read_ssh_info
18
+ Vagrant::Action::Builder.new.tap do |b|
19
+ b.use ConfigValidate
20
+ b.use ConnectOCI
21
+ b.use ReadSSHInfo
22
+ end
23
+ end
24
+
25
+ # This action is called to SSH into the machine.
26
+ def self.action_ssh
27
+ Vagrant::Action::Builder.new.tap do |b|
28
+ b.use ConfigValidate
29
+ b.use Call, IsCreated do |env, b2|
30
+ unless env[:result]
31
+ b2.use MessageNotCreated
32
+ next
33
+ end
34
+
35
+ b2.use SSHExec
36
+ end
37
+ end
38
+ end
39
+
40
+ def self.action_ssh_run
41
+ Vagrant::Action::Builder.new.tap do |b|
42
+ b.use ConfigValidate
43
+ b.use Call, IsCreated do |env, b2|
44
+ unless env[:result]
45
+ b2.use MessageNotCreated
46
+ next
47
+ end
48
+
49
+ b2.use SSHRun
50
+ end
51
+ end
52
+ end
53
+
54
+ def self.action_up
55
+ Vagrant::Action::Builder.new.tap do |b|
56
+ b.use HandleBox
57
+ b.use ConfigValidate
58
+ b.use BoxCheckOutdated
59
+ b.use ConnectOCI
60
+ b.use Call, IsCreated do |env1, b1|
61
+ if env1[:result]
62
+ b1.use Call, IsTerminated do |env2, b2|
63
+ if env2[:result]
64
+ b2.use Provision
65
+ b2.use SyncedFolders
66
+ b2.use WarnNetworks
67
+ b2.use WarnSshKeys
68
+ b2.use RunInstance
69
+ else
70
+ b2.use Call, IsStopped do |env3, b3|
71
+ if env3[:result]
72
+ b3.use StartInstance
73
+ else
74
+ b2.use MessageAlreadyCreated # TODO write a better message
75
+ end
76
+ end
77
+ end
78
+ end
79
+ else
80
+ b1.use Provision
81
+ b1.use SyncedFolders
82
+ b1.use WarnNetworks
83
+ b1.use WarnSshKeys
84
+ b1.use RunInstance
85
+ end
86
+ end
87
+ end
88
+ end
89
+
90
+ def self.action_provision
91
+ Vagrant::Action::Builder.new.tap do |b|
92
+ b.use ConfigValidate
93
+ b.use Call, IsCreated do |env, b2|
94
+ unless env[:result]
95
+ b2.use MessageNotCreated
96
+ next
97
+ end
98
+
99
+ b2.use Provision
100
+ b2.use SyncedFolders
101
+ end
102
+ end
103
+ end
104
+
105
+ def self.action_halt
106
+ Vagrant::Action::Builder.new.tap do |b|
107
+ b.use ConfigValidate
108
+ b.use Call, IsCreated do |env, b2|
109
+ if !env[:result]
110
+ b2.use MessageNotCreated
111
+ next
112
+ end
113
+
114
+ b2.use ConnectOCI
115
+ b2.use StopInstance
116
+ end
117
+ end
118
+ end
119
+
120
+ def self.action_destroy
121
+ Vagrant::Action::Builder.new.tap do |b|
122
+ b.use Call, DestroyConfirm do |env, b2|
123
+ if env[:result]
124
+ b2.use ConfigValidate
125
+ b2.use Call, IsCreated do |env2, b3|
126
+ unless env2[:result]
127
+ b3.use MessageNotCreated
128
+ next
129
+ end
130
+ b3.use ConnectOCI
131
+ b3.use TerminateInstance
132
+ end
133
+ else
134
+ b2.use MessageWillNotDestroy
135
+ end
136
+ end
137
+ end
138
+ end
139
+
140
+ action_root = Pathname.new(File.expand_path("../action", __FILE__))
141
+
142
+ autoload :ConnectOCI, action_root.join("connect_oci")
143
+ autoload :IsCreated, action_root.join("is_created")
144
+ autoload :IsTerminated, action_root.join("is_terminated")
145
+ autoload :IsStopped, action_root.join("is_stopped")
146
+ autoload :MessageAlreadyCreated, action_root.join("message_already_created")
147
+ autoload :MessageNotCreated, action_root.join("message_not_created")
148
+ autoload :MessageWillNotDestroy, action_root.join("message_will_not_destroy")
149
+ autoload :ReadSSHInfo, action_root.join("read_ssh_info")
150
+ autoload :ReadState, action_root.join("read_state")
151
+ autoload :RunInstance, action_root.join("run_instance")
152
+ autoload :StartInstance, action_root.join("start_instance")
153
+ autoload :StopInstance, action_root.join("stop_instance")
154
+ autoload :TerminateInstance, action_root.join("terminate_instance")
155
+ autoload :WarnNetworks, action_root.join("warn_networks")
156
+ autoload :WarnNetworks, action_root.join("warn_networks")
157
+ autoload :WarnSshKeys, action_root.join("warn_ssh_keys")
158
+ end
159
+ end
160
+ end
@@ -0,0 +1,60 @@
1
+ require 'log4r'
2
+ require 'oci'
3
+
4
+ module VagrantPlugins
5
+ module OCI
6
+ module Action
7
+ class ConnectOCI
8
+ def initialize(app, env)
9
+ @app = app
10
+ @logger = Log4r::Logger.new("vagrant_oci::action::connect_oci")
11
+ end
12
+
13
+ def call(env)
14
+ provider_config = env[:machine].provider_config
15
+
16
+ region = provider_config.region
17
+ config_file = provider_config.config_file || ::OCI::ConfigFileLoader::DEFAULT_CONFIG_FILE
18
+ profile_name = provider_config.profile || ::OCI::ConfigFileLoader::DEFAULT_PROFILE
19
+
20
+ oci_config = ::OCI::ConfigFileLoader.load_config(config_file_location: config_file,
21
+ profile_name: profile_name)
22
+ env[:oci_config] = oci_config
23
+
24
+ @logger.info("Creating OCI API compute client and adding to Vagrant environment")
25
+ env[:oci_compute] = ::OCI::Core::ComputeClient.new(config: oci_config, region: region)
26
+ env[:oci_network] = ::OCI::Core::VirtualNetworkClient.new(config: oci_config, region: region)
27
+ env[:oci_identity] = ::OCI::Identity::IdentityClient.new(config: oci_config, region: region)
28
+
29
+ @@ad_list ||= {}
30
+ @@ad_list[oci_config.tenancy] ||= {}
31
+ @@ad_list[oci_config.tenancy][region] ||= env[:oci_identity].list_availability_domains(oci_config.tenancy).data.map(&:to_hash).sort_by {|i| i[:name]}
32
+ env[:ad_name] = @@ad_list[oci_config.tenancy][region][provider_config.ad.to_i - 1][:name]
33
+
34
+ @@compartment_list ||= env[:oci_identity].list_compartments(oci_config.tenancy, compartment_id_in_subtree: true).flat_map {|i| i}
35
+ compartment_map = @@compartment_list.flat_map {|i| i.data}.inject({}) {|a, v| a[v.name] = v.id; a}
36
+ if provider_config.server_compartment_id.nil? and provider_config.server_compartment_name
37
+ env[:machine].provider_config.server_compartment_id = compartment_map[provider_config.server_compartment_name]
38
+ end
39
+ if provider_config.image_id.nil? and provider_config.image_compartment_name
40
+ env[:machine].provider_config.image_compartment_id = compartment_map[provider_config.image_compartment_name]
41
+ end
42
+ if provider_config.subnet_vcn_compartment_id.nil? and provider_config.subnet_vcn_compartment_name
43
+ env[:machine].provider_config.subnet_vcn_compartment_id = compartment_map[provider_config.subnet_vcn_compartment_name]
44
+ end
45
+ if provider_config.subnet_compartment_id.nil? and provider_config.subnet_compartment_name
46
+ env[:machine].provider_config.subnet_compartment_id = compartment_map[provider_config.subnet_compartment_name]
47
+ end
48
+
49
+ if provider_config.image_regex
50
+ @@image_list ||= {}
51
+ @@image_list[oci_config.tenancy] ||= {}
52
+ @@image_list[oci_config.tenancy][region] ||= env[:oci_compute].list_images(provider_config.image_compartment_id).data.map(&:to_hash).sort_by {|i| i[:name]}.reverse
53
+ end
54
+
55
+ @app.call(env)
56
+ end
57
+ end
58
+ end
59
+ end
60
+ end
@@ -0,0 +1,16 @@
1
+ module VagrantPlugins
2
+ module OCI
3
+ module Action
4
+ class IsCreated
5
+ def initialize(app, env)
6
+ @app = app
7
+ end
8
+
9
+ def call(env)
10
+ env[:result] = env[:machine].state.id != :not_created
11
+ @app.call(env)
12
+ end
13
+ end
14
+ end
15
+ end
16
+ end
@@ -0,0 +1,19 @@
1
+ module VagrantPlugins
2
+ module OCI
3
+ module Action
4
+ class IsStopped
5
+ def initialize(app, env)
6
+ @app = app
7
+ end
8
+
9
+ def call(env)
10
+ ocid = env[:machine].id
11
+
12
+ instance_data = env[:oci_compute].get_instance(ocid).data.to_hash
13
+ env[:result] = %w[STOPPED STOPPING].include? instance_data[:lifecycleState].upcase
14
+ @app.call(env)
15
+ end
16
+ end
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,18 @@
1
+ module VagrantPlugins
2
+ module OCI
3
+ module Action
4
+ class IsTerminated
5
+ def initialize(app, env)
6
+ @app = app
7
+ end
8
+
9
+ def call(env)
10
+ ocid = env[:machine].id
11
+ instance_data = env[:oci_compute].get_instance(ocid).data.to_hash
12
+ env[:result] = %w[TERMINATED TERMINATING].include? instance_data[:lifecycleState].upcase
13
+ @app.call(env)
14
+ end
15
+ end
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,16 @@
1
+ module VagrantPlugins
2
+ module OCI
3
+ module Action
4
+ class MessageAlreadyCreated
5
+ def initialize(app, env)
6
+ @app = app
7
+ end
8
+
9
+ def call(env)
10
+ env[:ui].info(I18n.t("vagrant_oci.already_created"))
11
+ @app.call(env)
12
+ end
13
+ end
14
+ end
15
+ end
16
+ end
@@ -0,0 +1,16 @@
1
+ module VagrantPlugins
2
+ module OCI
3
+ module Action
4
+ class MessageNotCreated
5
+ def initialize(app, env)
6
+ @app = app
7
+ end
8
+
9
+ def call(env)
10
+ env[:ui].info(I18n.t("vagrant_oci.not_created"))
11
+ @app.call(env)
12
+ end
13
+ end
14
+ end
15
+ end
16
+ end
@@ -0,0 +1,45 @@
1
+ require "log4r"
2
+
3
+ module VagrantPlugins
4
+ module OCI
5
+ module Action
6
+ # This action reads the SSH info for the machine and puts it into the
7
+ # `:machine_ssh_info` key in the environment.
8
+ class ReadSSHInfo
9
+ def initialize(app, env)
10
+ @app = app
11
+ @logger = Log4r::Logger.new("vagrant_oci::action::read_ssh_info")
12
+ end
13
+
14
+ def call(env)
15
+ env[:machine_ssh_info] = read_ssh_info(env)
16
+
17
+ @app.call(env)
18
+ end
19
+
20
+ def read_ssh_info(env)
21
+ machine = env[:machine]
22
+ return nil if machine.id.nil?
23
+
24
+ server_ocid = env[:machine].id
25
+ provider_config = env[:machine].provider_config
26
+ vnic_attachments_data = env[:oci_compute].list_vnic_attachments(provider_config.server_compartment_id, :instance_id => server_ocid).data.map(&:to_hash)
27
+ vnic_id = vnic_attachments_data.first[:vnicId]
28
+ vnic_data = env[:oci_network].get_vnic(vnic_id).data.to_hash
29
+ private_ip = vnic_data[:privateIp]
30
+ public_ip = vnic_data[:publicIp]
31
+ ip_addr = provider_config.use_private_network ? private_ip : public_ip || private_ip
32
+
33
+ ssh_info = {
34
+ :host => ip_addr,
35
+ :port => env[:machine].config.ssh.port || 22
36
+ }
37
+ env[:machine_ssh_info] = ssh_info
38
+
39
+ # Return SSH network info
40
+ return ssh_info
41
+ end
42
+ end
43
+ end
44
+ end
45
+ end
@@ -0,0 +1,44 @@
1
+ require 'log4r'
2
+
3
+ module VagrantPlugins
4
+ module OCI
5
+ module Action
6
+ # This action reads the state of the machine and puts it in the
7
+ # `:machine_state_id` key in the environment.
8
+ class ReadState
9
+ def initialize(app, env)
10
+ @app = app
11
+ @logger = Log4r::Logger.new("vagrant_oci::action::read_state")
12
+ end
13
+
14
+ def call(env)
15
+ env[:machine_state_id] = read_state(env[:oci_compute], env[:machine])
16
+
17
+ @app.call(env)
18
+ end
19
+
20
+ def read_state(oci, machine)
21
+ return :not_created if machine.id.nil?
22
+
23
+ # Find the machine
24
+ begin
25
+ server = oci.get_instance(machine.id)
26
+ rescue OCI::Errors::ServiceError
27
+ return :not_created
28
+ end
29
+
30
+ lifecycle_state = server.data.lifecycle_state
31
+ if lifecycle_state.nil? || %w[Stopped Terminating].include?(lifecycle_state)
32
+ # The machine can't be found
33
+ @logger.info("Machine not found or terminated, assuming it got destroyed.")
34
+ machine.id = nil
35
+ return :not_created
36
+ end
37
+
38
+ # Return the state
39
+ return lifecycle_state
40
+ end
41
+ end
42
+ end
43
+ end
44
+ end
@@ -0,0 +1,116 @@
1
+ require "log4r"
2
+ require 'vagrant/util/is_port_open'
3
+ require 'net/ssh'
4
+ require 'timeout'
5
+
6
+ module VagrantPlugins
7
+ module OCI
8
+ module Action
9
+ class RunInstance
10
+ include Vagrant::Util::IsPortOpen
11
+
12
+ def initialize(app, env)
13
+ @app = app
14
+ @logger = Log4r::Logger.new("vagrant_oci::action::run_instance")
15
+ end
16
+
17
+ def call(env)
18
+ # Initialize metrics if they haven't been
19
+ env[:metrics] ||= {}
20
+
21
+ provider_config = env[:machine].provider_config
22
+ oci_config = env[:oci_config]
23
+ metadata = {}
24
+ metadata.store('hostname', env[:machine].name)
25
+
26
+ if provider_config.image_regex and provider_config.image_id.nil?
27
+ @@image_list ||= {}
28
+ @@image_list[oci_config.tenancy] ||= {}
29
+ @@image_list[oci_config.tenancy][provider_config.region] ||= env[:oci_compute].list_images(provider_config.image_compartment_id).data.map(&:to_hash).sort_by {|i| i['display-name']}.reverse
30
+ r = Regexp.new(provider_config.image_regex)
31
+ provider_config.image_id = @@image_list[oci_config.tenancy][provider_config.region].filter {|i| r.match(i[:displayName])}.first[:id]
32
+ end
33
+
34
+ if provider_config.subnet_id.nil? and provider_config.subnet_vcn_compartment_name and provider_config.subnet_vcn_dns_label and provider_config.subnet_compartment_name and provider_config.subnet_dns_label
35
+ @@vcn_list ||= {}
36
+ @@vcn_list[oci_config.tenancy] ||= {}
37
+ @@vcn_list[oci_config.tenancy][provider_config.region] ||= env[:oci_network].list_vcns(provider_config.subnet_vcn_compartment_id).data.map(&:to_hash)
38
+ vcn_map = @@vcn_list[oci_config.tenancy][provider_config.region].inject({}) {|a, v| a[v[:dnsLabel]] = v[:id]; a}
39
+ vcn_id = vcn_map[provider_config.subnet_vcn_dns_label]
40
+
41
+ @@subnet_list ||= {}
42
+ @@subnet_list[oci_config.tenancy] ||= {}
43
+ @@subnet_list[oci_config.tenancy][provider_config.region] ||= {}
44
+ @@subnet_list[oci_config.tenancy][provider_config.region][vcn_id] ||= env[:oci_network].list_subnets(provider_config.subnet_compartment_id, vcn_id).data.map(&:to_hash)
45
+ subnet_map = @@subnet_list[oci_config.tenancy][provider_config.region][vcn_id].inject({}) {|a, v| a[v[:dnsLabel]] = v[:id]; a}
46
+ provider_config.subnet_id = subnet_map[provider_config.subnet_dns_label]
47
+ end
48
+
49
+ create_vnic_details = ::OCI::Core::Models::CreateVnicDetails.new(:subnet_id => provider_config.subnet_id)
50
+
51
+ ssh_private_key_path = env[:machine].config.ssh.private_key_path.first
52
+ ssh_private_key = File.read(File.expand_path(ssh_private_key_path)).chomp
53
+ key = OpenSSL::PKey::RSA.new(ssh_private_key)
54
+ type = key.ssh_type
55
+ data = [key.to_blob].pack('m0')
56
+ openssh_pubkey = "#{type} #{data}"
57
+ metadata.store('ssh_authorized_keys', openssh_pubkey)
58
+
59
+ api_request = ::OCI::Core::Models::LaunchInstanceDetails.new
60
+ api_request.availability_domain = env[:ad_name]
61
+ api_request.compartment_id = provider_config.server_compartment_id
62
+ api_request.display_name = env[:machine].name
63
+ api_request.shape = provider_config.shape
64
+ api_request.image_id = provider_config.image_id
65
+ api_request.metadata = metadata
66
+ api_request.create_vnic_details = create_vnic_details
67
+ api_request.freeform_tags = provider_config.freeform_tags
68
+ api_request.defined_tags = provider_config.defined_tags
69
+ compute_api = env[:oci_compute]
70
+
71
+ request_start_time = Time.now.to_i
72
+ puts "Launching new instance .."
73
+ ci = launch_instance_data = env[:oci_compute].launch_instance(api_request).data.to_hash
74
+ env[:machine].id = ci[:id]
75
+
76
+ vnic_attachments_data = nil
77
+ puts "Waiting for vnic attachments .."
78
+ loop do
79
+ vnic_attachments_data = env[:oci_compute].list_vnic_attachments(provider_config.server_compartment_id, :instance_id => ci[:id]).data.map(&:to_hash)
80
+ break if vnic_attachments_data.any?
81
+ sleep 5
82
+ end
83
+
84
+ vnic_id = vnic_attachments_data.first[:vnicId]
85
+ vnic_data = env[:oci_network].get_vnic(vnic_id).data.to_hash
86
+ private_ip = vnic_data[:privateIp]
87
+ public_ip = vnic_data[:publicIp]
88
+ ip_addr = provider_config.use_private_network ? private_ip : public_ip || private_ip
89
+
90
+ env[:ui].info(I18n.t("vagrant_oci.waiting_for_ready"))
91
+ original_stderr = $stderr.clone
92
+ $stderr.reopen(File.new(IO::NULL, 'w'))
93
+ begin
94
+ loop do
95
+ conn = nil
96
+ begin
97
+ Timeout::timeout(10) do
98
+ conn = Net::SSH.start(ip_addr, env[:machine].config.ssh.username, key_data: [ssh_private_key])
99
+ end
100
+ rescue
101
+ conn = nil
102
+ end
103
+ break if conn
104
+ end
105
+ $stderr.reopen(original_stderr)
106
+ env[:metrics]["instance_ready_time"] = Time.now.to_i - request_start_time
107
+ @logger.info("Time for instance ready: #{env[:metrics]["instance_ready_time"]}")
108
+ env[:ui].info(I18n.t("vagrant_oci.ready"))
109
+ rescue
110
+ env[:interrupted] = true
111
+ end
112
+ end
113
+ end
114
+ end
115
+ end
116
+ end
@@ -0,0 +1,34 @@
1
+ require "log4r"
2
+
3
+ module VagrantPlugins
4
+ module OCI
5
+ module Action
6
+ # This stops the running instance.
7
+ class StartInstance
8
+ def initialize(app, env)
9
+ @app = app
10
+ @logger = Log4r::Logger.new("vagrant_oci::action::start_instance")
11
+ end
12
+
13
+ def call(env)
14
+ return :not_created if env[:machine].id.nil?
15
+
16
+ begin
17
+ server = env[:oci_compute].get_instance(env[:machine].id)
18
+ rescue OCI::Errors::ServiceError
19
+ return :not_created
20
+ end
21
+ lifecycle_state = server.data.lifecycle_state.upcase
22
+ if %w[STARTING RUNNING].include?(lifecycle_state)
23
+ env[:ui].info(I18n.t("vagrant_oci.already_status", :status => lifecycle_state))
24
+ else
25
+ env[:ui].info(I18n.t("vagrant_oci.starting"))
26
+ env[:oci_compute].instance_action(env[:machine].id, 'START')
27
+ end
28
+
29
+ @app.call(env)
30
+ end
31
+ end
32
+ end
33
+ end
34
+ end
@@ -0,0 +1,34 @@
1
+ require "log4r"
2
+
3
+ module VagrantPlugins
4
+ module OCI
5
+ module Action
6
+ # This stops the running instance.
7
+ class StopInstance
8
+ def initialize(app, env)
9
+ @app = app
10
+ @logger = Log4r::Logger.new("vagrant_oci::action::stop_instance")
11
+ end
12
+
13
+ def call(env)
14
+ return :not_created if env[:machine].id.nil?
15
+
16
+ begin
17
+ server = env[:oci_compute].get_instance(env[:machine].id)
18
+ rescue OCI::Errors::ServiceError
19
+ return :not_created
20
+ end
21
+ lifecycle_state = server.data.lifecycle_state.upcase
22
+ if %w[STOPPED STOPPING].include?(lifecycle_state)
23
+ env[:ui].info(I18n.t("vagrant_oci.already_status", :status => lifecycle_state))
24
+ else
25
+ env[:ui].info(I18n.t("vagrant_oci.stopping"))
26
+ env[:oci_compute].instance_action(env[:machine].id, 'STOP')
27
+ end
28
+
29
+ @app.call(env)
30
+ end
31
+ end
32
+ end
33
+ end
34
+ end
@@ -0,0 +1,25 @@
1
+ require "log4r"
2
+
3
+ module VagrantPlugins
4
+ module OCI
5
+ module Action
6
+ class TerminateInstance
7
+ def initialize(app, env)
8
+ @app = app
9
+ @logger = Log4r::Logger.new("vagrant_oci::action::terminate_instance")
10
+ end
11
+
12
+ def call(env)
13
+ server_ocid = env[:machine].id
14
+ return nil if server_ocid.nil?
15
+
16
+ env[:ui].info(I18n.t("vagrant_oci.terminating"))
17
+ env[:oci_compute].terminate_instance(server_ocid)
18
+ env[:machine].id = nil
19
+
20
+ @app.call(env)
21
+ end
22
+ end
23
+ end
24
+ end
25
+ end
@@ -0,0 +1,20 @@
1
+ module VagrantPlugins
2
+ module OCI
3
+ module Action
4
+ class WarnNetworks
5
+ def initialize(app, env)
6
+ @app = app
7
+ end
8
+
9
+ def call(env)
10
+ # Default SSH forward always exists so "> 1"
11
+ if env[:machine].config.vm.networks.length > 1
12
+ env[:ui].warn(I18n.t("vagrant_oci.warn_networks"))
13
+ end
14
+
15
+ @app.call(env)
16
+ end
17
+ end
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,20 @@
1
+ module VagrantPlugins
2
+ module OCI
3
+ module Action
4
+ class WarnSshKeys
5
+ def initialize(app, env)
6
+ @app = app
7
+ end
8
+
9
+ def call(env)
10
+ # Warn on ssh-key overrides
11
+ if env[:machine].config.ssh.username.nil?
12
+ env[:ui].warn(I18n.t("vagrant_oci.warn_ssh_vagrant_user"))
13
+ end
14
+
15
+ @app.call(env)
16
+ end
17
+ end
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,29 @@
1
+ require "vagrant"
2
+
3
+ module VagrantPlugins
4
+ module OCI
5
+ class Config < Vagrant.plugin("2", :config)
6
+ attr_accessor :ad
7
+ attr_accessor :config_file
8
+ attr_accessor :defined_tags
9
+ attr_accessor :freeform_tags
10
+ attr_accessor :image_compartment_id
11
+ attr_accessor :image_compartment_name
12
+ attr_accessor :image_id
13
+ attr_accessor :image_regex
14
+ attr_accessor :profile
15
+ attr_accessor :region
16
+ attr_accessor :server_compartment_id
17
+ attr_accessor :server_compartment_name
18
+ attr_accessor :shape
19
+ attr_accessor :subnet_compartment_id
20
+ attr_accessor :subnet_compartment_name
21
+ attr_accessor :subnet_dns_label
22
+ attr_accessor :subnet_id
23
+ attr_accessor :subnet_vcn_compartment_id
24
+ attr_accessor :subnet_vcn_compartment_name
25
+ attr_accessor :subnet_vcn_dns_label
26
+ attr_accessor :use_private_network
27
+ end
28
+ end
29
+ end
@@ -0,0 +1,69 @@
1
+ begin
2
+ require "vagrant"
3
+ rescue LoadError
4
+ raise "The Vagrant OCI plugin must be run within Vagrant."
5
+ end
6
+
7
+ # This is a sanity check to make sure no one is attempting to install
8
+ # this into an early Vagrant version.
9
+ if Vagrant::VERSION < "1.2.0"
10
+ raise "The Vagrant OCI plugin is only compatible with Vagrant 1.2+"
11
+ end
12
+
13
+ module VagrantPlugins
14
+ module OCI
15
+ class Plugin < Vagrant.plugin("2")
16
+ name "OCI"
17
+ description <<-DESC
18
+ This plugin installs a provider that allows Vagrant to manage
19
+ machines in OCI.
20
+ DESC
21
+
22
+ config(:oci, :provider) do
23
+ require_relative "config"
24
+ Config
25
+ end
26
+
27
+ provider(:oci, parallel: true) do
28
+ setup_logging
29
+ setup_i18n
30
+
31
+ require_relative "provider"
32
+ Provider
33
+ end
34
+
35
+ def self.setup_i18n
36
+ I18n.load_path << File.expand_path("locales/en.yml", OCI.source_root)
37
+ I18n.reload!
38
+ end
39
+
40
+ def self.setup_logging
41
+ require "log4r"
42
+
43
+ level = nil
44
+ begin
45
+ level = Log4r.const_get(ENV["VAGRANT_LOG"].upcase)
46
+ rescue NameError
47
+ # This means that the logging constant wasn't found,
48
+ # which is fine. We just keep `level` as `nil`. But
49
+ # we tell the user.
50
+ level = nil
51
+ end
52
+
53
+ # Some constants, such as "true" resolve to booleans, so the
54
+ # above error checking doesn't catch it. This will check to make
55
+ # sure that the log level is an integer, as Log4r requires.
56
+ level = nil if !level.is_a?(Integer)
57
+
58
+ # Set the logging level on all "vagrant" namespaced
59
+ # logs as long as we have a valid level.
60
+ if level
61
+ logger = Log4r::Logger.new("vagrant_oci")
62
+ logger.outputters = Log4r::Outputter.stderr
63
+ logger.level = level
64
+ logger = nil
65
+ end
66
+ end
67
+ end
68
+ end
69
+ end
@@ -0,0 +1,45 @@
1
+ require "vagrant"
2
+
3
+ module VagrantPlugins
4
+ module OCI
5
+ class Provider < Vagrant.plugin("2", :provider)
6
+ def initialize(machine)
7
+ @machine = machine
8
+ @machine.config.nfs.functional = false unless ENV.has_key?('VAGRANT_OCI_ENABLE_NFS')
9
+ @machine.config.smb.functional = false unless ENV.has_key?('VAGRANT_OCI_ENABLE_SMB')
10
+ end
11
+
12
+ def action(name)
13
+ # Attempt to get the action method from the Action class if it
14
+ # exists, otherwise return nil to show that we don't support the
15
+ # given action.
16
+ action_method = "action_#{name}"
17
+ return Action.send(action_method) if Action.respond_to?(action_method)
18
+ nil
19
+ end
20
+
21
+ def ssh_info
22
+ env = @machine.action("read_ssh_info")
23
+ env[:machine_ssh_info]
24
+ end
25
+
26
+ def state
27
+ env = @machine.action("read_state")
28
+
29
+ state_id = env[:machine_state_id]
30
+
31
+ # Get the short and long description
32
+ short = I18n.t("vagrant_oci.states.short_#{state_id}")
33
+ long = I18n.t("vagrant_oci.states.long_#{state_id}")
34
+
35
+ # Return the MachineState object
36
+ Vagrant::MachineState.new(state_id, short, long)
37
+ end
38
+
39
+ def to_s
40
+ id = @machine.id.nil? ? "new" : @machine.id
41
+ "OCI (#{id})"
42
+ end
43
+ end
44
+ end
45
+ end
@@ -0,0 +1,5 @@
1
+ module VagrantPlugins
2
+ module OCI
3
+ VERSION = '0.1.1'
4
+ end
5
+ end
data/locales/en.yml ADDED
@@ -0,0 +1,70 @@
1
+ en:
2
+ vagrant_oci:
3
+ warn_networks: |-
4
+ Warning! The AWS provider doesn't support any of the Vagrant
5
+ high-level network configurations (`config.vm.network`). They
6
+ will be silently ignored.
7
+ warn_ssh_vagrant_user: |-
8
+ Warning! SSH credentials are not set (`ssh.username`, `ssh.private_key`).
9
+ waiting_for_ready: |-
10
+ Waiting for instance to become "ready"...
11
+ ready: |-
12
+ Machine is booted and ready for use!
13
+ already_created: |-
14
+ The machine is already created.
15
+ not_created: |-
16
+ Instance is not created. Please run `vagrant up` first.
17
+ terminating: |-
18
+ Terminating the instance...
19
+ already_status: |-
20
+ The machine is already %{status}.
21
+ stopping: |-
22
+ Stopping the instance...
23
+ starting: |-
24
+ Starting the instance...
25
+ states:
26
+ short_not_created: |-
27
+ not created
28
+ long_not_created: |-
29
+ The OCI instance is not created. Run `vagrant up` to create it.
30
+
31
+ short_PROVISIONING: |-
32
+ provsioning
33
+ long_PROVISIONING: |-
34
+ Resources are being reserved for this instance. This instance is
35
+ not yet running.
36
+
37
+ short_STARTING: |-
38
+ starting
39
+ long_STARTING: |-
40
+ The OCI instance is starting up.
41
+
42
+ short_STOPPING: |-
43
+ stopping
44
+ long_STOPPING: |-
45
+ The OCI instance is stopping. Wait until is completely stopped to
46
+ run `vagrant up` and start it.
47
+
48
+ short_RUNNING: |-
49
+ running
50
+ long_RUNNING: |-
51
+ The OCI instance is running. To stop this machine, you can run
52
+ `vagrant halt`. To destroy the machine, you can run `vagrant destroy`.
53
+
54
+ short_STOPPED: |-
55
+ stopped
56
+ long_STOPPED: |-
57
+ The OCI instance has been shut down. To start the instance up again
58
+ you can run `vagrant up`.
59
+
60
+ short_TERMINATING: |-
61
+ terminating
62
+ long_TERMINATING: |-
63
+ The OCI instance is being terminated. To start the instance up again
64
+ you can run `vagrant up`.
65
+
66
+ short_TERMINATED: |-
67
+ terminated
68
+ long_TERMINATED: |-
69
+ The OCI instance was terminated for some reason. You can
70
+ attempt to restart the instance by running `vagrant up`.
@@ -0,0 +1,29 @@
1
+
2
+ lib = File.expand_path("../lib", __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'vagrant-oci/version'
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = "vagrant-oci"
8
+ spec.version = VagrantPlugins::OCI::VERSION
9
+ spec.authors = ["Stephen Pearson"]
10
+ spec.email = ["stephen.pearson@oracle.com"]
11
+
12
+ spec.summary = %q{Create instances in Oracle OCI..}
13
+ spec.description = %q{Create instances in Oracle OCI.}
14
+ spec.homepage = "https://github.com/stephenpearson/vagrant-oci.git"
15
+
16
+ # Specify which files should be added to the gem when it is released.
17
+ # The `git ls-files -z` loads the files in the RubyGem that have been added into git.
18
+ spec.files = Dir.chdir(File.expand_path('..', __FILE__)) do
19
+ `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
20
+ end
21
+ spec.bindir = "bin"
22
+ spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
23
+ spec.require_paths = ["lib"]
24
+
25
+ spec.add_development_dependency "bundler", "~> 2.0"
26
+ spec.add_development_dependency "rake", "~> 10.0"
27
+
28
+ spec.add_runtime_dependency 'oci', '~> 2.5'
29
+ end
metadata ADDED
@@ -0,0 +1,115 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: vagrant-oci
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.1
5
+ platform: ruby
6
+ authors:
7
+ - Stephen Pearson
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2019-06-09 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: bundler
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '2.0'
20
+ type: :development
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '2.0'
27
+ - !ruby/object:Gem::Dependency
28
+ name: rake
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: '10.0'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: '10.0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: oci
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - "~>"
46
+ - !ruby/object:Gem::Version
47
+ version: '2.5'
48
+ type: :runtime
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - "~>"
53
+ - !ruby/object:Gem::Version
54
+ version: '2.5'
55
+ description: Create instances in Oracle OCI.
56
+ email:
57
+ - stephen.pearson@oracle.com
58
+ executables: []
59
+ extensions: []
60
+ extra_rdoc_files: []
61
+ files:
62
+ - ".gitignore"
63
+ - Gemfile
64
+ - README.md
65
+ - Rakefile
66
+ - Vagrantfile.sample/Vagrantfile
67
+ - Vagrantfile.sample/site.yml
68
+ - example_box/README.md
69
+ - example_box/Vagrantfile
70
+ - example_box/metadata.json
71
+ - lib/vagrant-oci.rb
72
+ - lib/vagrant-oci/action.rb
73
+ - lib/vagrant-oci/action/connect_oci.rb
74
+ - lib/vagrant-oci/action/is_created.rb
75
+ - lib/vagrant-oci/action/is_stopped.rb
76
+ - lib/vagrant-oci/action/is_terminated.rb
77
+ - lib/vagrant-oci/action/message_already_created.rb
78
+ - lib/vagrant-oci/action/message_not_created.rb
79
+ - lib/vagrant-oci/action/read_ssh_info.rb
80
+ - lib/vagrant-oci/action/read_state.rb
81
+ - lib/vagrant-oci/action/run_instance.rb
82
+ - lib/vagrant-oci/action/start_instance.rb
83
+ - lib/vagrant-oci/action/stop_instance.rb
84
+ - lib/vagrant-oci/action/terminate_instance.rb
85
+ - lib/vagrant-oci/action/warn_networks.rb
86
+ - lib/vagrant-oci/action/warn_ssh_keys.rb
87
+ - lib/vagrant-oci/config.rb
88
+ - lib/vagrant-oci/plugin.rb
89
+ - lib/vagrant-oci/provider.rb
90
+ - lib/vagrant-oci/version.rb
91
+ - locales/en.yml
92
+ - vagrant-oci.gemspec
93
+ homepage: https://github.com/stephenpearson/vagrant-oci.git
94
+ licenses: []
95
+ metadata: {}
96
+ post_install_message:
97
+ rdoc_options: []
98
+ require_paths:
99
+ - lib
100
+ required_ruby_version: !ruby/object:Gem::Requirement
101
+ requirements:
102
+ - - ">="
103
+ - !ruby/object:Gem::Version
104
+ version: '0'
105
+ required_rubygems_version: !ruby/object:Gem::Requirement
106
+ requirements:
107
+ - - ">="
108
+ - !ruby/object:Gem::Version
109
+ version: '0'
110
+ requirements: []
111
+ rubygems_version: 3.0.1
112
+ signing_key:
113
+ specification_version: 4
114
+ summary: Create instances in Oracle OCI..
115
+ test_files: []