vagrant-aliyun 0.0.2
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.gitignore +9 -0
- data/Gemfile +14 -0
- data/Gemfile.lock +111 -0
- data/README.md +36 -0
- data/Rakefile +15 -0
- data/example_box/README.md +8 -0
- data/example_box/dummy_aliyun.box +0 -0
- data/example_box/metadata.json +3 -0
- data/lib/vagrant-aliyun/action/is_created.rb +18 -0
- data/lib/vagrant-aliyun/action/is_stopped.rb +18 -0
- data/lib/vagrant-aliyun/action/message_already_created.rb +16 -0
- data/lib/vagrant-aliyun/action/message_not_created.rb +16 -0
- data/lib/vagrant-aliyun/action/message_will_not_destroy.rb +16 -0
- data/lib/vagrant-aliyun/action/read_ssh_info.rb +38 -0
- data/lib/vagrant-aliyun/action/read_state.rb +47 -0
- data/lib/vagrant-aliyun/action/run_instance.rb +100 -0
- data/lib/vagrant-aliyun/action/start_instance.rb +90 -0
- data/lib/vagrant-aliyun/action/stop_instance.rb +52 -0
- data/lib/vagrant-aliyun/action/terminate_instance.rb +51 -0
- data/lib/vagrant-aliyun/action/wait_for_state.rb +41 -0
- data/lib/vagrant-aliyun/action/warn_networks.rb +19 -0
- data/lib/vagrant-aliyun/action.rb +182 -0
- data/lib/vagrant-aliyun/config.rb +55 -0
- data/lib/vagrant-aliyun/errors.rb +24 -0
- data/lib/vagrant-aliyun/plugin.rb +73 -0
- data/lib/vagrant-aliyun/provider.rb +50 -0
- data/lib/vagrant-aliyun/util/timer.rb +17 -0
- data/lib/vagrant-aliyun/version.rb +5 -0
- data/lib/vagrant-aliyun.rb +18 -0
- data/locales/en.yml +96 -0
- data/pkg/vagrant-aliyun-0.0.1.gem +0 -0
- data/pkg/vagrant-aliyun-0.0.2.gem +0 -0
- data/vagrant-aliyun.gemspec +52 -0
- metadata +76 -0
@@ -0,0 +1,90 @@
|
|
1
|
+
require "log4r"
|
2
|
+
require 'json'
|
3
|
+
require "aliyun"
|
4
|
+
|
5
|
+
module VagrantPlugins
|
6
|
+
module AliyunECS
|
7
|
+
module Action
|
8
|
+
# This runs the configured instance.
|
9
|
+
class StartInstance
|
10
|
+
|
11
|
+
def initialize(app, env)
|
12
|
+
@app = app
|
13
|
+
@logger = Log4r::Logger.new("vagrant_aliyun::action::start_instance")
|
14
|
+
end
|
15
|
+
|
16
|
+
def call(env)
|
17
|
+
start_instance(env[:machine], env)
|
18
|
+
|
19
|
+
@app.call(env)
|
20
|
+
end
|
21
|
+
|
22
|
+
def start_instance(machine, env)
|
23
|
+
return nil if machine.id.nil?
|
24
|
+
|
25
|
+
config = machine.provider_config
|
26
|
+
options = {
|
27
|
+
:access_key_id => config.access_key_id,
|
28
|
+
:access_key_secret => config.access_key_secret
|
29
|
+
}
|
30
|
+
Aliyun.config options
|
31
|
+
ecs = Aliyun::ECS.new
|
32
|
+
|
33
|
+
env[:ui].info(I18n.t("vagrant_aliyun.starting"))
|
34
|
+
ecs.start_instance :instance_id=>machine.id
|
35
|
+
|
36
|
+
# Wait for the instance to be ready first
|
37
|
+
env[:ui].info(I18n.t("vagrant_aliyun.waiting_for_ready"))
|
38
|
+
begin
|
39
|
+
instance = ecs.describe_instance_attribute :instance_id=>machine.id
|
40
|
+
Timeout.timeout(config.instance_ready_timeout) do
|
41
|
+
until instance["Status"] == "Running"
|
42
|
+
sleep 2
|
43
|
+
instance = ecs.describe_instance_attribute :instance_id=>machine.id
|
44
|
+
end
|
45
|
+
end
|
46
|
+
rescue Timeout::Error
|
47
|
+
env[:result] = false # couldn't reach state in time
|
48
|
+
# Delete the instance
|
49
|
+
terminate(env)
|
50
|
+
|
51
|
+
# Notify the user
|
52
|
+
raise Errors::InstanceReadyTimeout,
|
53
|
+
timeout: config.instance_ready_timeout
|
54
|
+
end
|
55
|
+
|
56
|
+
if !env[:interrupted]
|
57
|
+
# Wait for SSH to be ready.
|
58
|
+
env[:ui].info(I18n.t("vagrant_aliyun.waiting_for_ssh"))
|
59
|
+
network_ready_retries = 0
|
60
|
+
network_ready_retries_max = 10
|
61
|
+
while true
|
62
|
+
# If we're interrupted then just back out
|
63
|
+
break if env[:interrupted]
|
64
|
+
# When an ECS instance comes up, it's networking may not be ready
|
65
|
+
# by the time we connect.
|
66
|
+
begin
|
67
|
+
break if env[:machine].communicate.ready?
|
68
|
+
rescue Exception => e
|
69
|
+
if network_ready_retries < network_ready_retries_max then
|
70
|
+
network_ready_retries += 1
|
71
|
+
@logger.warn(I18n.t("vagrant_aliyun.waiting_for_ssh, retrying"))
|
72
|
+
else
|
73
|
+
raise e
|
74
|
+
end
|
75
|
+
end
|
76
|
+
sleep 2
|
77
|
+
end
|
78
|
+
|
79
|
+
# Ready and booted!
|
80
|
+
env[:ui].info(I18n.t("vagrant_aliyun.ready"))
|
81
|
+
end
|
82
|
+
|
83
|
+
# Terminate the instance if we were interrupted
|
84
|
+
terminate(env) if env[:interrupted]
|
85
|
+
end
|
86
|
+
|
87
|
+
end
|
88
|
+
end
|
89
|
+
end
|
90
|
+
end
|
@@ -0,0 +1,52 @@
|
|
1
|
+
require "log4r"
|
2
|
+
|
3
|
+
module VagrantPlugins
|
4
|
+
module AliyunECS
|
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_aliyun::action::stop_instance")
|
11
|
+
end
|
12
|
+
|
13
|
+
def call(env)
|
14
|
+
stop_instance(env[:machine], env)
|
15
|
+
|
16
|
+
@app.call(env)
|
17
|
+
end
|
18
|
+
|
19
|
+
def stop_instance(machine, env)
|
20
|
+
return nil if machine.id.nil?
|
21
|
+
|
22
|
+
config = machine.provider_config
|
23
|
+
options = {
|
24
|
+
:access_key_id => config.access_key_id,
|
25
|
+
:access_key_secret => config.access_key_secret
|
26
|
+
}
|
27
|
+
Aliyun.config options
|
28
|
+
ecs = Aliyun::ECS.new
|
29
|
+
|
30
|
+
if machine.state.id == :stopped
|
31
|
+
env[:ui].info(I18n.t("vagrant_aliyun.already_status", :status => machine.state.id))
|
32
|
+
else
|
33
|
+
env[:ui].info(I18n.t("vagrant_aliyun.stopping"))
|
34
|
+
ecs.stop_instance :instance_id=>machine.id
|
35
|
+
begin
|
36
|
+
instance = ecs.describe_instance_attribute :instance_id=>machine.id
|
37
|
+
Timeout.timeout(config.instance_ready_timeout) do
|
38
|
+
until instance["Status"] == "Stopped"
|
39
|
+
sleep 2
|
40
|
+
instance = ecs.describe_instance_attribute :instance_id=>machine.id
|
41
|
+
end
|
42
|
+
end
|
43
|
+
rescue Timeout::Error
|
44
|
+
env[:result] = false # couldn't reach state in time
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
@@ -0,0 +1,51 @@
|
|
1
|
+
require "log4r"
|
2
|
+
|
3
|
+
module VagrantPlugins
|
4
|
+
module AliyunECS
|
5
|
+
module Action
|
6
|
+
# This stops the running instance.
|
7
|
+
class TerminateInstance
|
8
|
+
def initialize(app, env)
|
9
|
+
@app = app
|
10
|
+
@logger = Log4r::Logger.new("vagrant_aliyun::action::terminate_instance")
|
11
|
+
end
|
12
|
+
|
13
|
+
def call(env)
|
14
|
+
terminate_instance(env[:machine], env)
|
15
|
+
|
16
|
+
@app.call(env)
|
17
|
+
end
|
18
|
+
|
19
|
+
def terminate_instance(machine, env)
|
20
|
+
return nil if machine.id.nil?
|
21
|
+
|
22
|
+
config = machine.provider_config
|
23
|
+
options = {
|
24
|
+
:access_key_id => config.access_key_id,
|
25
|
+
:access_key_secret => config.access_key_secret
|
26
|
+
}
|
27
|
+
Aliyun.config options
|
28
|
+
ecs = Aliyun::ECS.new
|
29
|
+
|
30
|
+
env[:ui].info(I18n.t("vagrant_aliyun.terminating"))
|
31
|
+
ecs.stop_instance :instance_id=>machine.id
|
32
|
+
|
33
|
+
begin
|
34
|
+
instance = ecs.describe_instance_attribute :instance_id=>machine.id
|
35
|
+
Timeout.timeout(config.instance_ready_timeout) do
|
36
|
+
until instance["Status"] == "Stopped"
|
37
|
+
sleep 2
|
38
|
+
instance = ecs.describe_instance_attribute :instance_id=>machine.id
|
39
|
+
end
|
40
|
+
end
|
41
|
+
rescue Timeout::Error
|
42
|
+
env[:result] = false # couldn't reach state in time
|
43
|
+
end
|
44
|
+
|
45
|
+
ecs.delete_instance :instance_id=>machine.id
|
46
|
+
machine.id = nil
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
@@ -0,0 +1,41 @@
|
|
1
|
+
require "log4r"
|
2
|
+
require "timeout"
|
3
|
+
|
4
|
+
module VagrantPlugins
|
5
|
+
module AliyunECS
|
6
|
+
module Action
|
7
|
+
# This action will wait for a machine to reach a specific state or quit by timeout
|
8
|
+
class WaitForState
|
9
|
+
# env[:result] will be false in case of timeout.
|
10
|
+
# @param [Symbol] state Target machine state.
|
11
|
+
# @param [Number] timeout Timeout in seconds.
|
12
|
+
def initialize(app, env, state, timeout)
|
13
|
+
@app = app
|
14
|
+
@logger = Log4r::Logger.new("vagrant_aliyun::action::wait_for_state")
|
15
|
+
@state = state
|
16
|
+
@timeout = timeout
|
17
|
+
end
|
18
|
+
|
19
|
+
def call(env)
|
20
|
+
env[:result] = true
|
21
|
+
if env[:machine].state.id == @state
|
22
|
+
@logger.info(I18n.t("vagrant_aliyun.already_status", :status => @state))
|
23
|
+
else
|
24
|
+
@logger.info("Waiting for machine to reach state #{@state}")
|
25
|
+
begin
|
26
|
+
Timeout.timeout(@timeout) do
|
27
|
+
until env[:machine].state.id == @state
|
28
|
+
sleep 2
|
29
|
+
end
|
30
|
+
end
|
31
|
+
rescue Timeout::Error
|
32
|
+
env[:result] = false # couldn't reach state in time
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
@app.call(env)
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
module VagrantPlugins
|
2
|
+
module AliyunECS
|
3
|
+
module Action
|
4
|
+
class WarnNetworks
|
5
|
+
def initialize(app, env)
|
6
|
+
@app = app
|
7
|
+
end
|
8
|
+
|
9
|
+
def call(env)
|
10
|
+
if env[:machine].config.vm.networks.length > 0
|
11
|
+
env[:ui].warn(I18n.t("vagrant_aliyun.warn_networks"))
|
12
|
+
end
|
13
|
+
|
14
|
+
@app.call(env)
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
@@ -0,0 +1,182 @@
|
|
1
|
+
require "pathname"
|
2
|
+
require "aliyun"
|
3
|
+
require "vagrant/action/builder"
|
4
|
+
|
5
|
+
module VagrantPlugins
|
6
|
+
module AliyunECS
|
7
|
+
module Action
|
8
|
+
# Include the built-in modules so we can use them as top-level things.
|
9
|
+
include Vagrant::Action::Builtin
|
10
|
+
|
11
|
+
# This action is called to halt the remote machine.
|
12
|
+
def self.action_halt
|
13
|
+
Vagrant::Action::Builder.new.tap do |b|
|
14
|
+
b.use ConfigValidate
|
15
|
+
b.use Call, IsCreated do |env, b2|
|
16
|
+
if !env[:result]
|
17
|
+
b2.use MessageNotCreated
|
18
|
+
next
|
19
|
+
end
|
20
|
+
|
21
|
+
b2.use StopInstance
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
# This action is called to terminate the remote machine.
|
27
|
+
def self.action_destroy
|
28
|
+
Vagrant::Action::Builder.new.tap do |b|
|
29
|
+
b.use Call, DestroyConfirm do |env, b2|
|
30
|
+
if env[:result]
|
31
|
+
b2.use ConfigValidate
|
32
|
+
b2.use Call, IsCreated do |env2, b3|
|
33
|
+
if !env2[:result]
|
34
|
+
b3.use MessageNotCreated
|
35
|
+
next
|
36
|
+
end
|
37
|
+
b3.use TerminateInstance
|
38
|
+
b3.use ProvisionerCleanup if defined?(ProvisionerCleanup)
|
39
|
+
end
|
40
|
+
else
|
41
|
+
b2.use MessageWillNotDestroy
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
# This action is called when `vagrant provision` is called.
|
48
|
+
def self.action_provision
|
49
|
+
Vagrant::Action::Builder.new.tap do |b|
|
50
|
+
b.use ConfigValidate
|
51
|
+
b.use Call, IsCreated do |env, b2|
|
52
|
+
if !env[:result]
|
53
|
+
b2.use MessageNotCreated
|
54
|
+
next
|
55
|
+
end
|
56
|
+
|
57
|
+
b2.use Provision
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
# This action is called to read the SSH info of the machine. The
|
63
|
+
# resulting state is expected to be put into the `:machine_ssh_info`
|
64
|
+
# key.
|
65
|
+
def self.action_read_ssh_info
|
66
|
+
Vagrant::Action::Builder.new.tap do |b|
|
67
|
+
b.use ConfigValidate
|
68
|
+
b.use ReadSSHInfo
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
# This action is called to read the state of the machine. The
|
73
|
+
# resulting state is expected to be put into the `:machine_state_id`
|
74
|
+
# key.
|
75
|
+
def self.action_read_state
|
76
|
+
Vagrant::Action::Builder.new.tap do |b|
|
77
|
+
b.use ConfigValidate
|
78
|
+
b.use ReadState
|
79
|
+
end
|
80
|
+
end
|
81
|
+
|
82
|
+
# This action is called to SSH into the machine.
|
83
|
+
def self.action_ssh
|
84
|
+
Vagrant::Action::Builder.new.tap do |b|
|
85
|
+
b.use ConfigValidate
|
86
|
+
b.use Call, IsCreated do |env, b2|
|
87
|
+
if !env[:result]
|
88
|
+
b2.use MessageNotCreated
|
89
|
+
next
|
90
|
+
end
|
91
|
+
|
92
|
+
b2.use SSHExec
|
93
|
+
end
|
94
|
+
end
|
95
|
+
end
|
96
|
+
|
97
|
+
def self.action_ssh_run
|
98
|
+
Vagrant::Action::Builder.new.tap do |b|
|
99
|
+
b.use ConfigValidate
|
100
|
+
b.use Call, IsCreated do |env, b2|
|
101
|
+
if !env[:result]
|
102
|
+
b2.use MessageNotCreated
|
103
|
+
next
|
104
|
+
end
|
105
|
+
|
106
|
+
b2.use SSHRun
|
107
|
+
end
|
108
|
+
end
|
109
|
+
end
|
110
|
+
|
111
|
+
def self.action_prepare_boot
|
112
|
+
Vagrant::Action::Builder.new.tap do |b|
|
113
|
+
b.use Provision
|
114
|
+
b.use SyncedFolders
|
115
|
+
b.use WarnNetworks
|
116
|
+
end
|
117
|
+
end
|
118
|
+
|
119
|
+
# This action is called to bring the box up from nothing.
|
120
|
+
def self.action_up
|
121
|
+
Vagrant::Action::Builder.new.tap do |b|
|
122
|
+
b.use HandleBox
|
123
|
+
b.use ConfigValidate
|
124
|
+
b.use BoxCheckOutdated
|
125
|
+
b.use Call, IsCreated do |env1, b1|
|
126
|
+
if env1[:result]
|
127
|
+
b1.use Call, IsStopped do |env2, b2|
|
128
|
+
if env2[:result]
|
129
|
+
b2.use action_prepare_boot
|
130
|
+
b2.use StartInstance # restart this instance
|
131
|
+
else
|
132
|
+
b2.use MessageAlreadyCreated # TODO write a better message
|
133
|
+
end
|
134
|
+
end
|
135
|
+
else
|
136
|
+
b1.use action_prepare_boot
|
137
|
+
b1.use RunInstance # launch a new instance
|
138
|
+
end
|
139
|
+
end
|
140
|
+
end
|
141
|
+
end
|
142
|
+
|
143
|
+
def self.action_reload
|
144
|
+
Vagrant::Action::Builder.new.tap do |b|
|
145
|
+
b.use ConfigValidate
|
146
|
+
b.use Call, IsCreated do |env, b2|
|
147
|
+
if !env[:result]
|
148
|
+
b2.use MessageNotCreated
|
149
|
+
next
|
150
|
+
end
|
151
|
+
|
152
|
+
b2.use action_halt
|
153
|
+
b2.use Call, WaitForState, :stopped, 120 do |env2, b3|
|
154
|
+
if env2[:result]
|
155
|
+
b3.use action_up
|
156
|
+
else
|
157
|
+
# TODO we couldn't reach :stopped, what now?
|
158
|
+
end
|
159
|
+
end
|
160
|
+
end
|
161
|
+
end
|
162
|
+
end
|
163
|
+
|
164
|
+
# The autoload farm
|
165
|
+
action_root = Pathname.new(File.expand_path("../action", __FILE__))
|
166
|
+
autoload :IsCreated, action_root.join("is_created")
|
167
|
+
autoload :IsStopped, action_root.join("is_stopped")
|
168
|
+
autoload :MessageAlreadyCreated, action_root.join("message_already_created")
|
169
|
+
autoload :MessageNotCreated, action_root.join("message_not_created")
|
170
|
+
autoload :MessageWillNotDestroy, action_root.join("message_will_not_destroy")
|
171
|
+
autoload :ReadSSHInfo, action_root.join("read_ssh_info")
|
172
|
+
autoload :ReadState, action_root.join("read_state")
|
173
|
+
autoload :RunInstance, action_root.join("run_instance")
|
174
|
+
autoload :StartInstance, action_root.join("start_instance")
|
175
|
+
autoload :StopInstance, action_root.join("stop_instance")
|
176
|
+
autoload :TerminateInstance, action_root.join("terminate_instance")
|
177
|
+
autoload :WaitForState, action_root.join("wait_for_state")
|
178
|
+
autoload :WarnNetworks, action_root.join("warn_networks")
|
179
|
+
|
180
|
+
end
|
181
|
+
end
|
182
|
+
end
|
@@ -0,0 +1,55 @@
|
|
1
|
+
require "vagrant"
|
2
|
+
|
3
|
+
module VagrantPlugins
|
4
|
+
module AliyunECS
|
5
|
+
class Config < Vagrant.plugin("2", :config)
|
6
|
+
|
7
|
+
attr_accessor :access_key_id
|
8
|
+
attr_accessor :access_key_secret
|
9
|
+
attr_accessor :region_id
|
10
|
+
attr_accessor :image_id
|
11
|
+
attr_accessor :instance_type
|
12
|
+
attr_accessor :internet_max_bandwidth_out
|
13
|
+
attr_accessor :security_group_id
|
14
|
+
attr_accessor :password
|
15
|
+
attr_accessor :instance_ready_timeout
|
16
|
+
|
17
|
+
def initialize()
|
18
|
+
@access_key_id = UNSET_VALUE
|
19
|
+
@access_key_secret = UNSET_VALUE
|
20
|
+
@region_id = UNSET_VALUE
|
21
|
+
@image_id = UNSET_VALUE
|
22
|
+
@instance_type = UNSET_VALUE
|
23
|
+
@internet_max_bandwidth_out = UNSET_VALUE
|
24
|
+
@security_group_id = UNSET_VALUE
|
25
|
+
@password = UNSET_VALUE
|
26
|
+
@instance_ready_timeout = UNSET_VALUE
|
27
|
+
end
|
28
|
+
|
29
|
+
def finalize!
|
30
|
+
@access_key_id = nil if @access_key_id == UNSET_VALUE
|
31
|
+
@access_key_secret = nil if @access_key_secret == UNSET_VALUE
|
32
|
+
@region_id = nil if @region_id == UNSET_VALUE
|
33
|
+
@image_id = nil if @image_id == UNSET_VALUE
|
34
|
+
@instance_type = nil if @instance_type == UNSET_VALUE
|
35
|
+
@internet_max_bandwidth_out = nil if @internet_max_bandwidth_out == UNSET_VALUE
|
36
|
+
@security_group_id = nil if @security_group_id == UNSET_VALUE
|
37
|
+
@password = nil if @password == UNSET_VALUE
|
38
|
+
@instance_ready_timeout = 120 if @instance_ready_timeout == UNSET_VALUE
|
39
|
+
end
|
40
|
+
|
41
|
+
def validate(machine)
|
42
|
+
errors = _detected_errors
|
43
|
+
errors << I18n.t("vagrant_aliyun.config.access_key_id_required") if @access_key_id.nil?
|
44
|
+
errors << I18n.t("vagrant_aliyun.config.access_key_secret_required") if @access_key_secret.nil?
|
45
|
+
errors << I18n.t("vagrant_aliyun.config.region_id_required") if @region_id.nil?
|
46
|
+
errors << I18n.t("vagrant_aliyun.config.image_id_required") if @image_id.nil?
|
47
|
+
errors << I18n.t("vagrant_aliyun.config.instance_type_required") if @instance_type.nil?
|
48
|
+
errors << I18n.t("vagrant_aliyun.config.internet_max_bandwidth_out_required") if @internet_max_bandwidth_out.nil?
|
49
|
+
errors << I18n.t("vagrant_aliyun.config.security_group_id_required") if @security_group_id.nil?
|
50
|
+
errors << I18n.t("vagrant_aliyun.config.password_required") if @password.nil?
|
51
|
+
{ "Aliyun Provider" => errors }
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|