vagrant-oci 0.1.1

Sign up to get free protection for your applications and to get access to all the features.
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: []