app42 0.5.3
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.gitignore +19 -0
- data/Gemfile +4 -0
- data/LICENSE.txt +22 -0
- data/README.md +119 -0
- data/Rakefile +5 -0
- data/TODO.txt +36 -0
- data/app42.gemspec +41 -0
- data/bin/app42 +15 -0
- data/lib/app42.rb +23 -0
- data/lib/app42/base/constants.rb +33 -0
- data/lib/app42/base/help.rb +717 -0
- data/lib/app42/base/http_helper.rb +46 -0
- data/lib/app42/base/message.rb +35 -0
- data/lib/app42/base/shell.rb +39 -0
- data/lib/app42/base/util.rb +304 -0
- data/lib/app42/client/app42_rest_client.rb +451 -0
- data/lib/app42/client/rest_util.rb +66 -0
- data/lib/app42/command/app.rb +194 -0
- data/lib/app42/command/authorize.rb +29 -0
- data/lib/app42/command/base.rb +660 -0
- data/lib/app42/command/client.rb +232 -0
- data/lib/app42/command/config.rb +185 -0
- data/lib/app42/command/info.rb +101 -0
- data/lib/app42/command/service.rb +196 -0
- data/lib/app42/command/user.rb +140 -0
- data/lib/app42/command/user_key.rb +68 -0
- data/lib/app42/version.rb +13 -0
- data/spec/app42/base/constants_spec.rb +11 -0
- data/spec/app42/command/app_spec.rb +103 -0
- data/spec/app42/command/base_spec.rb +7 -0
- data/spec/app42/command/config_spec.rb +20 -0
- data/spec/app42/command/info_spec.rb +27 -0
- data/spec/app42/command/service_spec.rb +98 -0
- data/spec/app42/command/user_spec.rb +7 -0
- data/spec/app42/command/user_token_spec.rb +40 -0
- data/spec/app42/version_spec.rb +7 -0
- data/spec/app42_spec.rb +2 -0
- data/spec/data/info.yml +16 -0
- data/spec/data/services.yml +25 -0
- data/spec/data/state.yml +16 -0
- data/spec/data/user_services.yml +18 -0
- data/spec/spec_helper.rb +18 -0
- metadata +257 -0
@@ -0,0 +1,196 @@
|
|
1
|
+
|
2
|
+
module App42::Command
|
3
|
+
class Service < Base
|
4
|
+
|
5
|
+
# list all available service of requested user
|
6
|
+
def get_services
|
7
|
+
build_get_request params, 'info', 'services'
|
8
|
+
end
|
9
|
+
|
10
|
+
# ask service name to user
|
11
|
+
def get_service
|
12
|
+
service_hash = {}
|
13
|
+
|
14
|
+
get_services['services'].select {|each_service| service_hash["#{each_service['id']}"] = each_service['name'] + ' ' + each_service['version']}
|
15
|
+
service = input "Select Service", service_hash.values, true
|
16
|
+
|
17
|
+
service_id = nil
|
18
|
+
service_hash.each_pair{|s| service_id = s[0] if s[1] == service}
|
19
|
+
return service_id
|
20
|
+
end
|
21
|
+
|
22
|
+
def get_user_services#:nodoc:
|
23
|
+
build_get_request params, 'service', nil
|
24
|
+
end
|
25
|
+
|
26
|
+
# ask service name to user
|
27
|
+
def ask_service_name
|
28
|
+
service_name = input "Enter Service Name", [], true
|
29
|
+
valid_service_name = validate_app_and_service_name "Service name", service_name.strip
|
30
|
+
valid_service_name ? (return valid_service_name) : ask_service_name
|
31
|
+
end
|
32
|
+
|
33
|
+
# ask old password to user
|
34
|
+
def ask_old_password
|
35
|
+
input "Enter Old Password", [], true
|
36
|
+
end
|
37
|
+
|
38
|
+
# ask source id to user which he want to bind to service
|
39
|
+
def ask_source_ip what
|
40
|
+
ip = input "#{Message::BIND_NOTE}", [], true if what.to_s == 'bind'
|
41
|
+
ip = input "#{Message::UNBIND_NOTE}", [], true if what.to_s == 'unbind'
|
42
|
+
if ip_address_valid? ip
|
43
|
+
return ip
|
44
|
+
else
|
45
|
+
message "#{Message::IP_NOT_VALID}", true, 'red'
|
46
|
+
ask_source_ip what
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
# ask database name to user
|
51
|
+
def ask_database_name
|
52
|
+
database_name = input "Enter Database Name", [], true
|
53
|
+
valid_database_name = validate_database_name "Database name", database_name
|
54
|
+
valid_database_name ? (return valid_database_name) : ask_database_name
|
55
|
+
end
|
56
|
+
|
57
|
+
# ask users service name to user
|
58
|
+
def ask_user_service_name
|
59
|
+
service_list = []
|
60
|
+
get_user_services['services'].select {|service| service_list << service['name'] }
|
61
|
+
input "Select Service", service_list, true
|
62
|
+
end
|
63
|
+
|
64
|
+
|
65
|
+
# ask service name to user
|
66
|
+
def get_service_name
|
67
|
+
service_name = ask_service_name
|
68
|
+
service_name = service_name_availability service_name
|
69
|
+
service_name ? (return service_name) : get_service_name
|
70
|
+
end
|
71
|
+
|
72
|
+
# collect all required data from user to create new service
|
73
|
+
def create
|
74
|
+
service_name = get_service_name
|
75
|
+
|
76
|
+
service = get_service
|
77
|
+
|
78
|
+
database = ask_database_name
|
79
|
+
|
80
|
+
vm_type = get_vm_types
|
81
|
+
|
82
|
+
iaas = get_iaas_providers
|
83
|
+
|
84
|
+
os = get_os_for_service iaas, vm_type, service
|
85
|
+
|
86
|
+
vmconfig = get_vmconfig vm_type, iaas
|
87
|
+
|
88
|
+
create_service service, service_name , database, vm_type, iaas, vmconfig, os
|
89
|
+
|
90
|
+
end
|
91
|
+
|
92
|
+
# collect service name from user and proceed service delete request
|
93
|
+
def delete
|
94
|
+
@options[:service] = ask_service_name if @options[:service].nil?
|
95
|
+
response = delete_service @options[:service] if is_service_exist? @options[:service]
|
96
|
+
exit! if response
|
97
|
+
end
|
98
|
+
|
99
|
+
# collect service name from user and proceed service resetPassword request
|
100
|
+
def reset_pass
|
101
|
+
@options[:service] = ask_service_name if @options[:service].nil?
|
102
|
+
old_password = ask_old_password if is_service_exist? @options[:service]
|
103
|
+
res = reset_password @options[:service], old_password
|
104
|
+
(puts message "Your new password is: #{res['service']['password']}", false, 'green') && exit! if res
|
105
|
+
end
|
106
|
+
|
107
|
+
# collect service name,source IP and access time from user and proceed service resetPassword request
|
108
|
+
def service_bind
|
109
|
+
@options[:service] = ask_service_name if @options[:service].nil?
|
110
|
+
source_ip = ask_source_ip 'bind' if is_service_exist? @options[:service]
|
111
|
+
create_service_tunnel @options[:service], source_ip
|
112
|
+
end
|
113
|
+
|
114
|
+
# collect service name and source IP from user and proceed service unbind request
|
115
|
+
def service_unbind
|
116
|
+
@options[:service] = ask_service_name if @options[:service].nil?
|
117
|
+
source_ip = ask_source_ip 'unbind' if is_service_exist? @options[:service]
|
118
|
+
res = delete_service_tunnel @options[:service], source_ip
|
119
|
+
exit! if res
|
120
|
+
end
|
121
|
+
|
122
|
+
# list details of specific service
|
123
|
+
def service_bindInfo
|
124
|
+
@options[:service] = ask_user_service_name if @options[:service].nil?
|
125
|
+
query_params = params
|
126
|
+
query_params.store('serviceName', @options[:service])
|
127
|
+
service_info = build_get_request query_params, 'service', "tunnel/#{@options[:service]}"
|
128
|
+
|
129
|
+
rows, rows_header_final, rows_header = [], [], nil
|
130
|
+
if service_info && service_info['service']
|
131
|
+
rows_header = service_info['service'].keys
|
132
|
+
rows << service_info['service'].values
|
133
|
+
|
134
|
+
rows_header.map { |e| rows_header_final << camel_case_to_whitespace(e) }
|
135
|
+
|
136
|
+
table = Terminal::Table.new :title => Paint["=== #{@options[:service]} Details ===", :green], :headings => rows_header_final, :rows => rows
|
137
|
+
puts table
|
138
|
+
end
|
139
|
+
end
|
140
|
+
|
141
|
+
# list all available service on app42pass
|
142
|
+
def app42pass_services
|
143
|
+
rows, rows_header_final, rows_header = [], [], nil
|
144
|
+
services = get_services
|
145
|
+
if services && services['services']
|
146
|
+
services['services'].each do |e|
|
147
|
+
e.delete('id')
|
148
|
+
rows_header = e.keys
|
149
|
+
rows << e.values
|
150
|
+
end #unless services.nil?
|
151
|
+
|
152
|
+
rows_header.map { |e| rows_header_final << camel_case_to_whitespace(e) }
|
153
|
+
|
154
|
+
table = Terminal::Table.new :title => Paint["=== App42 PaaS Services ===", :green], :headings => rows_header_final, :rows => rows
|
155
|
+
puts table
|
156
|
+
end
|
157
|
+
end
|
158
|
+
|
159
|
+
# list all available service on app42pass
|
160
|
+
def services
|
161
|
+
rows, rows_header_final, rows_header = [], [], nil
|
162
|
+
services = get_user_services
|
163
|
+
if services && services['services']
|
164
|
+
services['services'].each do |e|
|
165
|
+
rows_header = e.keys
|
166
|
+
rows << e.values
|
167
|
+
end
|
168
|
+
|
169
|
+
rows_header.map { |e| rows_header_final << camel_case_to_whitespace(e) }
|
170
|
+
|
171
|
+
table = Terminal::Table.new :title => Paint["=== Service List ===", :green], :headings => rows_header_final, :rows => rows
|
172
|
+
puts table
|
173
|
+
end
|
174
|
+
end
|
175
|
+
|
176
|
+
# list details of specific service
|
177
|
+
def info
|
178
|
+
@options[:service] = ask_user_service_name if @options[:service].nil?
|
179
|
+
query_params = params
|
180
|
+
query_params.store('serviceName', @options[:service])
|
181
|
+
service_info = build_get_request query_params, 'service', "#{@options[:service]}"
|
182
|
+
|
183
|
+
rows, rows_header_final, rows_header = [], [], nil
|
184
|
+
if service_info && service_info['service']
|
185
|
+
rows_header = service_info['service'].keys
|
186
|
+
rows << service_info['service'].values
|
187
|
+
|
188
|
+
rows_header.map { |e| rows_header_final << camel_case_to_whitespace(e) }
|
189
|
+
|
190
|
+
table = Terminal::Table.new :title => Paint["=== #{@options[:service]} Details ===", :green], :headings => rows_header_final, :rows => rows
|
191
|
+
puts table
|
192
|
+
end
|
193
|
+
end
|
194
|
+
|
195
|
+
end
|
196
|
+
end
|
@@ -0,0 +1,140 @@
|
|
1
|
+
|
2
|
+
require 'highline/import'
|
3
|
+
require "interact"
|
4
|
+
require 'paint'
|
5
|
+
require 'fileutils'
|
6
|
+
|
7
|
+
module App42
|
8
|
+
module Command
|
9
|
+
class User
|
10
|
+
|
11
|
+
include App42::Command::UserToken
|
12
|
+
include App42::Base::Util
|
13
|
+
include Interactive
|
14
|
+
|
15
|
+
# @return
|
16
|
+
# dup argument to get a non-frozen string
|
17
|
+
def initialize(options={} )
|
18
|
+
@options = options.dup
|
19
|
+
end
|
20
|
+
|
21
|
+
# list local api and secret key
|
22
|
+
def keys
|
23
|
+
if check_key_file?
|
24
|
+
puts message "#{Message::KEYS}", false, 'green'
|
25
|
+
api_key, secret_key = get_keys
|
26
|
+
puts "API Key = #{api_key}"
|
27
|
+
puts "Secret Key = #{secret_key}"
|
28
|
+
else
|
29
|
+
message "#{Message::KEYS_NOT_FIND}", true, 'red'
|
30
|
+
# TODO, should be dynamic
|
31
|
+
App42::Base::Help.addKeys
|
32
|
+
end
|
33
|
+
|
34
|
+
end
|
35
|
+
|
36
|
+
# clear local credentials
|
37
|
+
def clear
|
38
|
+
if App42::Command::Auth.logged_in? then
|
39
|
+
begin
|
40
|
+
ans = ask "Do you want to delete existing keys?", :default => true
|
41
|
+
print_new_line
|
42
|
+
if ans == true
|
43
|
+
key_file = remove_key_file
|
44
|
+
puts message "#{Message::KEYS_CLEARED}", false, 'green'
|
45
|
+
else
|
46
|
+
exit!
|
47
|
+
end
|
48
|
+
rescue
|
49
|
+
message "#{Message::SOMETHING_WRONG}", false, 'red'
|
50
|
+
end
|
51
|
+
else
|
52
|
+
puts message "#{Message::KEYS_NOT_FIND}", false, 'red'
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
# Configure app42 credentials
|
57
|
+
def add
|
58
|
+
update_key if App42::Command::Auth.logged_in?
|
59
|
+
api_key, secret_key = collect_app42_credentials
|
60
|
+
if is_api_key_valid? api_key, secret_key
|
61
|
+
configure_app42 api_key, secret_key
|
62
|
+
print Paint["Adding keys...", :yellow]
|
63
|
+
puts Paint["done", :green]
|
64
|
+
else
|
65
|
+
puts Paint["#{Message::WRONG_KEY}", :red]
|
66
|
+
remove_key_file
|
67
|
+
print_new_line
|
68
|
+
exit!
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
# update existing key
|
73
|
+
def update_key
|
74
|
+
puts message "#{Message::KEYS_EXIST}", false, 'red'
|
75
|
+
ans = ask "\nDo you want to update existing keys?", :default => true
|
76
|
+
print_new_line
|
77
|
+
ans == true ? (return) : (exit!)
|
78
|
+
end
|
79
|
+
|
80
|
+
def is_api_key_valid? api_key, secret_key #:nodoc:
|
81
|
+
key_validate_params = {
|
82
|
+
'apiKey'=> api_key,
|
83
|
+
'version' => VERSION,
|
84
|
+
'timeStamp' => Time.now.utc.strftime("%Y-%m-%dT%H:%M:%S.%LZ")
|
85
|
+
}
|
86
|
+
api_key_valid = validate_api_and_secret_key key_validate_params, 'info', 'authenticate', secret_key
|
87
|
+
return api_key_valid['success']
|
88
|
+
end
|
89
|
+
|
90
|
+
# validate api and secret key
|
91
|
+
def validate_api_and_secret_key query_params, resource, action, secret_key
|
92
|
+
url = resource_url(resource, action)
|
93
|
+
sign = App42::Client::RestUtil.new.sign(secret_key, query_params )
|
94
|
+
response = App42::Client::App42RestClient.new.get(sign, url, query_params)
|
95
|
+
end
|
96
|
+
|
97
|
+
# collect keys for keys:add
|
98
|
+
# Get api key
|
99
|
+
# Get secret key
|
100
|
+
def collect_app42_credentials
|
101
|
+
api_key = @options[:api] if @options[:api]
|
102
|
+
secret_key = @options[:secret] if @options[:secret]
|
103
|
+
message '=== Enter your App42PaaS keys ===', true, 'blue' if api_key.nil? && secret_key.nil?
|
104
|
+
api_key = get_api_key if api_key.nil?
|
105
|
+
secret_key = get_secret_key if secret_key.nil?
|
106
|
+
return api_key, secret_key
|
107
|
+
end
|
108
|
+
|
109
|
+
# collect api key from client
|
110
|
+
def get_api_key(prompt = Paint["Enter API Key:", :bright])
|
111
|
+
api_key = @options[:api_key] if @options[:api_key]
|
112
|
+
api_key = ask(prompt) {|q| q.echo = true} if api_key.nil?
|
113
|
+
return api_key.strip
|
114
|
+
end
|
115
|
+
|
116
|
+
# collect secret key from client
|
117
|
+
def get_secret_key(prompt = Paint["Enter Secret Key:", :bright])
|
118
|
+
secret_key = @options[:secret_key] if @options[:secret_key]
|
119
|
+
secret_key = ask(prompt) {|q| q.echo = true} if secret_key.nil?
|
120
|
+
return secret_key.strip
|
121
|
+
end
|
122
|
+
|
123
|
+
private
|
124
|
+
|
125
|
+
# make sure, have configuration file
|
126
|
+
# configure api and secrete key
|
127
|
+
def configure_app42 api_key, secret_key
|
128
|
+
if api_key && secret_key
|
129
|
+
begin
|
130
|
+
ensure_config_dir
|
131
|
+
local_app42_key api_key, secret_key
|
132
|
+
rescue Exception => e
|
133
|
+
puts e
|
134
|
+
end
|
135
|
+
end
|
136
|
+
end
|
137
|
+
|
138
|
+
end
|
139
|
+
end
|
140
|
+
end
|
@@ -0,0 +1,68 @@
|
|
1
|
+
|
2
|
+
require 'fileutils'
|
3
|
+
require 'yaml'
|
4
|
+
|
5
|
+
module App42
|
6
|
+
module Command
|
7
|
+
module UserToken
|
8
|
+
|
9
|
+
# make sure configuration root directory exist?
|
10
|
+
# create new dir unless file.exist?
|
11
|
+
def ensure_config_dir
|
12
|
+
FileUtils.mkdir_p(config_path) unless File.exist? config_path
|
13
|
+
end
|
14
|
+
|
15
|
+
# Load yaml config file
|
16
|
+
# make sure file contain api and secret key
|
17
|
+
def check_key_file?
|
18
|
+
info = YAML.load_file(key_path) if File.exist? key_path
|
19
|
+
true unless info.nil? || info['api_key'].nil? || info['secret_key'].nil?
|
20
|
+
end
|
21
|
+
|
22
|
+
# Load yaml config file
|
23
|
+
# read api and secret key
|
24
|
+
def get_keys
|
25
|
+
keys = YAML.load_file(key_path) if File.exist? key_path
|
26
|
+
return nil, nil if keys.nil? || keys.empty?
|
27
|
+
return keys['api_key'], keys['secret_key'] unless keys.empty? || keys.nil?
|
28
|
+
end
|
29
|
+
|
30
|
+
# expand key file path
|
31
|
+
# And open in write mode and configure api and secret key
|
32
|
+
def local_app42_key api_key, secret_key
|
33
|
+
key_file = File.expand_path(App42::KEYS_FILE)
|
34
|
+
|
35
|
+
File.open(key_file, "w") { |f|
|
36
|
+
f.puts "api_key:"
|
37
|
+
f.puts " #{api_key}"
|
38
|
+
f.puts "secret_key:"
|
39
|
+
f.puts " #{secret_key}"
|
40
|
+
}
|
41
|
+
end
|
42
|
+
|
43
|
+
# Extract key path
|
44
|
+
# and remove from configuration file
|
45
|
+
def remove_key_file
|
46
|
+
FileUtils.rm_f(key_path)
|
47
|
+
end
|
48
|
+
|
49
|
+
# Expand key path
|
50
|
+
def key_path
|
51
|
+
File.expand_path(App42::KEYS_FILE)
|
52
|
+
end
|
53
|
+
|
54
|
+
# Extract app42pass config dir path
|
55
|
+
# and remove from configuration file
|
56
|
+
def config_path
|
57
|
+
File.expand_path(App42::CONFIG_DIR)
|
58
|
+
end
|
59
|
+
|
60
|
+
# collect key path from constants
|
61
|
+
# mkdir key file
|
62
|
+
def ensure_key_file
|
63
|
+
FileUtils.mkdir_p(key_path) unless File.exist? key_path
|
64
|
+
end
|
65
|
+
|
66
|
+
end
|
67
|
+
end
|
68
|
+
end
|
@@ -0,0 +1,103 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe 'App42::Command' do
|
4
|
+
describe "App" do
|
5
|
+
|
6
|
+
before(:all) do
|
7
|
+
@app_name = 'demo'
|
8
|
+
@new_app_name = 'demo1'
|
9
|
+
@existing_app_name = 'demo'
|
10
|
+
@iaas = 1
|
11
|
+
@vm_type = 'Shared'
|
12
|
+
@runtime = 4
|
13
|
+
@framework = 4
|
14
|
+
@web_server = 4
|
15
|
+
@os = 1
|
16
|
+
@vm_config = 1
|
17
|
+
@instance = 1
|
18
|
+
end
|
19
|
+
|
20
|
+
context "With valid input data" do
|
21
|
+
|
22
|
+
it 'Should return app name available' do
|
23
|
+
response = App42::Command::Base.new.app_url_availability @new_app_name, @iaas, @vm_type
|
24
|
+
response.should eql true
|
25
|
+
end
|
26
|
+
|
27
|
+
it 'Should setup infrastructure' do
|
28
|
+
response = App42::Command::Base.new.create_infrastructure @app_name, @iaas, @vm_type, @runtime, @framework, @web_server, @os, @vm_config
|
29
|
+
response.should eql true
|
30
|
+
end
|
31
|
+
|
32
|
+
it 'should list all apps' do
|
33
|
+
response = App42::Command::App.new.apps
|
34
|
+
end
|
35
|
+
|
36
|
+
it 'Should scale app by instance 1:' do
|
37
|
+
response = App42::Command::Base.new.scale_or_descale_app 'scale', @instance, @app_name
|
38
|
+
response.should eql true
|
39
|
+
end
|
40
|
+
|
41
|
+
it 'Should descale app by instance 1:' do
|
42
|
+
response = App42::Command::Base.new.scale_or_descale_app 'descale', @instance, @app_name
|
43
|
+
response.should eql true
|
44
|
+
end
|
45
|
+
|
46
|
+
it 'Should start app:' do
|
47
|
+
response = App42::Command::Base.new.app_operation 'start', @app_name
|
48
|
+
response.should eql true
|
49
|
+
end
|
50
|
+
|
51
|
+
it 'Should stop app:' do
|
52
|
+
response = App42::Command::Base.new.app_operation 'stop', @app_name
|
53
|
+
response.should eql true
|
54
|
+
end
|
55
|
+
|
56
|
+
it 'Should restart app:' do
|
57
|
+
response = App42::Command::Base.new.app_operation 'restart', @app_name
|
58
|
+
response.should eql true
|
59
|
+
end
|
60
|
+
|
61
|
+
it 'Should return correct app information json' do
|
62
|
+
respone = App42::Command::Base.new.app_information 'info', @app_name
|
63
|
+
path = "#{APP_ROOT}/app42/spec/data/info.yml"
|
64
|
+
info = YAML.load_file(path)
|
65
|
+
respone.should eql info
|
66
|
+
end
|
67
|
+
|
68
|
+
it 'Should return correct app state json' do
|
69
|
+
respone = App42::Command::Base.new.app_information 'state', @app_name
|
70
|
+
path = "#{APP_ROOT}/app42/spec/data/state.yml"
|
71
|
+
info = YAML.load_file(path)
|
72
|
+
respone.should eql info
|
73
|
+
end
|
74
|
+
|
75
|
+
it 'Should delete app:' do
|
76
|
+
response = App42::Command::Base.new.app_operation 'delete', @app_name
|
77
|
+
response.should eql true
|
78
|
+
end
|
79
|
+
end
|
80
|
+
|
81
|
+
context "Check app name availability with existing app name" do
|
82
|
+
it 'Should return rest exception: App with name demo is not available.' do
|
83
|
+
response = App42::Command::Base.new.app_url_availability @existing_app_name, @iaas, @vm_type
|
84
|
+
puts response
|
85
|
+
end
|
86
|
+
end
|
87
|
+
|
88
|
+
context "Setup-infra with existing app name" do
|
89
|
+
it 'Should return rest exception: App with name demo is not available.' do
|
90
|
+
response = App42::Command::Base.new.create_infrastructure @existing_app_name, @iaas, @vm_type, @runtime, @framework, @web_server, @os, @vm_config
|
91
|
+
response.should eql true
|
92
|
+
end
|
93
|
+
end
|
94
|
+
|
95
|
+
context "Setup-infra with existing app name" do
|
96
|
+
it 'Should return rest exception: App with name demo is not available.' do
|
97
|
+
response = App42::Command::Base.new.create_infrastructure @existing_app_name, @iaas, @vm_type, @runtime, @framework, @web_server, @os, @vm_config
|
98
|
+
response.should eql true
|
99
|
+
end
|
100
|
+
end
|
101
|
+
|
102
|
+
end
|
103
|
+
end
|