forj 0.0.30 → 0.0.31
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.
- data/README.md +10 -1
- data/bin/forj +4 -2
- data/lib/boot.rb +48 -20
- data/lib/build_tmpl/build-env.py +293 -0
- data/lib/catalog.yaml +11 -2
- data/lib/compute.rb +38 -0
- data/lib/down.rb +16 -15
- data/lib/network.rb +32 -1
- data/lib/repositories.rb +18 -0
- data/lib/security.rb +28 -2
- data/lib/setup.rb +52 -1
- data/lib/ssh.rb +5 -0
- data/lib/ssh.sh +3 -2
- data/spec/spec_helper.rb +3 -3
- metadata +15 -13
data/README.md
CHANGED
@@ -4,6 +4,15 @@ Forj cli
|
|
4
4
|
|
5
5
|
Installation
|
6
6
|
=====================
|
7
|
+
For ruby 2.0
|
8
|
+
Fedora/CentOS/Redhat/rpm like system :
|
9
|
+
sudo yum install ruby-dev build-essential libopenssl-ruby libssl-dev zlib1g-dev -y
|
10
|
+
sudo gem install forj
|
11
|
+
|
12
|
+
Ubuntu/Debian/debian like system (not tested)
|
13
|
+
sudo apt-get install ruby-dev build-essential libopenssl-ruby1.9.1 libssl-dev zlib1g-dev -y
|
14
|
+
sudo gem install forj
|
15
|
+
|
7
16
|
For ruby 1.9
|
8
17
|
|
9
18
|
sudo apt-get install ruby-dev build-essential libopenssl-ruby1.9.1 libssl-dev zlib1g-dev -y
|
@@ -59,4 +68,4 @@ your development today!
|
|
59
68
|
|
60
69
|
License
|
61
70
|
=====================
|
62
|
-
Forj Cli is licensed under the Apache License, Version 2.0. See LICENSE for full license text.
|
71
|
+
Forj Cli is licensed under the Apache License, Version 2.0. See LICENSE for full license text.
|
data/bin/forj
CHANGED
@@ -78,12 +78,13 @@ class Forj < Thor
|
|
78
78
|
method_option :build_config_dir, :aliases => '-d', :desc => 'Defines the build configuration directory to load the build configuration file. You can set FORJ_BLD_CONF_DIR. By default, it will look in your current directory.'
|
79
79
|
method_option :build_config, :aliases => '-c', :desc => 'The build config file to load <confdir>/<BoxName>.<Config>.env. By default, uses "master" as Config.'
|
80
80
|
method_option :branch, :aliases => '-b', :desc => 'The build will extract from git branch name. It sets the configuration build <config> to the branch name <branch>.'
|
81
|
-
method_option :test_box, :aliases => '-t', :desc => 'Create test-box meta from the repository path provided.'
|
81
|
+
method_option :test_box, :aliases => '-t', :desc => 'Create test.rb-box meta from the repository path provided.'
|
82
82
|
method_option :git_repo, :aliases => '-r', :desc => 'The box built will use a different git repository sent out to <user_data>. This repository needs to be read only. No keys are sent.'
|
83
83
|
method_option :boothook, :aliases => '-h', :desc => 'By default, boothook file used is build/bin/build-tools/boothook.sh. Use this option to set another one.'
|
84
84
|
method_option :box_name, :aliases => '-x', :desc => 'Defines the name of the box or box image to build.'
|
85
85
|
method_option :key_name, :aliases => '-k', :desc => 'Import a key pair.'
|
86
86
|
method_option :key_path, :aliases => '-p', :desc => 'Public key data'
|
87
|
+
method_option :catalog, :aliases => '-y', :desc => 'A path for the yaml file data about the blueprint'
|
87
88
|
|
88
89
|
def boot(blueprint, on, cloud_provider, as, name, test = false)
|
89
90
|
Boot.boot(blueprint, cloud_provider, name,
|
@@ -91,7 +92,8 @@ class Forj < Thor
|
|
91
92
|
options[:build_config], options[:branch],
|
92
93
|
options[:git_repo], options[:boothook],
|
93
94
|
options[:box_name], options[:key_name],
|
94
|
-
options[:key_path],
|
95
|
+
options[:key_path],options[:region],
|
96
|
+
options[:catalog], test)
|
95
97
|
end
|
96
98
|
|
97
99
|
desc 'down', 'delete the Maestro box and all systems installed by the blueprint'
|
data/lib/boot.rb
CHANGED
@@ -38,7 +38,7 @@ module Boot
|
|
38
38
|
def boot(blueprint, cloud_provider, name,
|
39
39
|
build, build_config_dir, build_config,
|
40
40
|
branch, git_repo, boothook, box_name,
|
41
|
-
key_name, key_path,
|
41
|
+
key_name, key_path, region, catalog,
|
42
42
|
test = false)
|
43
43
|
begin
|
44
44
|
initial_msg = 'booting %s on %s' % [blueprint , cloud_provider]
|
@@ -48,33 +48,58 @@ module Boot
|
|
48
48
|
|
49
49
|
forj_dir = File.expand_path(File.dirname(__FILE__))
|
50
50
|
Dir.chdir(forj_dir)
|
51
|
-
|
51
|
+
|
52
|
+
if catalog
|
53
|
+
definitions = YamlParse.get_values(catalog)
|
54
|
+
else
|
55
|
+
definitions = YamlParse.get_values('catalog.yaml')
|
56
|
+
end
|
52
57
|
|
53
58
|
maestro_url = definitions['default']['maestro']
|
54
59
|
|
55
60
|
Repositories.clone_repo(maestro_url)
|
61
|
+
infra_exists = nil
|
62
|
+
|
63
|
+
begin
|
64
|
+
if File.directory?(definitions[blueprint]['infra'])
|
65
|
+
infra_exists = true
|
66
|
+
else
|
67
|
+
Repositories.create_infra
|
68
|
+
end
|
69
|
+
rescue => e
|
70
|
+
infra_exists = false
|
71
|
+
puts e.message
|
72
|
+
end
|
73
|
+
|
56
74
|
|
57
|
-
network = Network.
|
58
|
-
|
59
|
-
|
60
|
-
|
75
|
+
network = Network.get_or_create_network(definitions[blueprint]['network'])
|
76
|
+
begin
|
77
|
+
subnet = Network.get_or_create_subnet(network.id, name)
|
78
|
+
router = Network.get_router(definitions[blueprint]['router'])
|
79
|
+
Network.create_router_interface(subnet.id, router)
|
80
|
+
rescue => e
|
81
|
+
puts e.message
|
82
|
+
end
|
61
83
|
|
62
|
-
security_group = SecurityGroup.
|
84
|
+
security_group = SecurityGroup.get_or_create_security_group(definitions[blueprint]['security_group'])
|
63
85
|
|
64
|
-
key_name = '
|
65
|
-
key_path = '
|
86
|
+
key_name = definitions[blueprint]['keypair_name'] unless key_name
|
87
|
+
key_path = definitions[blueprint]['keypair_path'] unless key_path
|
66
88
|
SecurityGroup.upload_existing_key(key_name, key_path)
|
67
89
|
|
68
|
-
ports = definitions[
|
90
|
+
ports = definitions[blueprint]['ports']
|
69
91
|
|
70
92
|
ports.each do|port|
|
71
|
-
Network.
|
93
|
+
Network.get_or_create_rule(security_group.id, 'tcp', port, port)
|
72
94
|
end
|
73
95
|
|
74
96
|
ENV['FORJ_HPC_NETID'] = network.id
|
75
97
|
ENV['FORJ_SECURITY_GROUP'] = security_group.name
|
76
98
|
ENV['FORJ_KEYPAIR'] = key_name
|
77
|
-
ENV['
|
99
|
+
ENV['FORJ_HPC_KEYPUB'] = key_path
|
100
|
+
if region
|
101
|
+
ENV['FORJ_REGION'] = region
|
102
|
+
end
|
78
103
|
|
79
104
|
# run build.sh to boot maestro
|
80
105
|
current_dir = Dir.pwd
|
@@ -84,20 +109,23 @@ module Boot
|
|
84
109
|
|
85
110
|
build = 'bin/build.sh' unless build
|
86
111
|
|
87
|
-
|
88
|
-
|
89
|
-
|
112
|
+
if infra_exists
|
113
|
+
build_config_dir = definitions[blueprint]['infra'] unless build_config_dir
|
114
|
+
else
|
115
|
+
build_config_dir = definitions[blueprint]['build_config_dir'] unless build_config_dir
|
116
|
+
end
|
90
117
|
|
91
|
-
|
118
|
+
build_config = definitions[blueprint]['build_config'] unless build_config
|
92
119
|
|
93
|
-
|
120
|
+
branch = definitions[blueprint]['branch'] unless branch
|
94
121
|
|
95
|
-
box_name = '
|
122
|
+
box_name = definitions[blueprint]['box_name'] unless box_name
|
96
123
|
|
97
|
-
|
124
|
+
meta = '--meta blueprint=%s --meta HPCLOUD_PRIV=~/.cache/forj/master.forj-13.5.g64' % [blueprint]
|
98
125
|
|
99
|
-
command = '%s --build_ID %s --box-name %s --build-conf-dir %s --build-config %s --gitBranch %s --
|
126
|
+
command = '%s --build_ID %s --box-name %s --build-conf-dir %s --build-config %s --gitBranch %s --debug-box %s' % [build, name, box_name, build_config_dir, build_config, branch, meta]
|
100
127
|
|
128
|
+
Logging.info('using build.sh for %s' % [name])
|
101
129
|
Kernel.system(command)
|
102
130
|
Dir.chdir(current_dir)
|
103
131
|
|
@@ -0,0 +1,293 @@
|
|
1
|
+
#!/bin/env python
|
2
|
+
#
|
3
|
+
# (c) Copyright 2014 Hewlett-Packard Development Company, L.P.
|
4
|
+
#
|
5
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
6
|
+
# you may not use this file except in compliance with the License.
|
7
|
+
# You may obtain a copy of the License at
|
8
|
+
#
|
9
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
10
|
+
#
|
11
|
+
# Unless required by applicable law or agreed to in writing, software
|
12
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
13
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
14
|
+
# See the License for the specific language governing permissions and
|
15
|
+
# limitations under the License.
|
16
|
+
|
17
|
+
# This script is used to create a env file used by build.sh.
|
18
|
+
# It is based on Maestro/templates/infra/maestro.box.GITBRANCH.env.tmpl
|
19
|
+
|
20
|
+
# This script detects few tags, and ask to enter the appropriate vallue,
|
21
|
+
# then save the result to a directory given by the user.
|
22
|
+
|
23
|
+
# As this script is very early in the boot process, we are running on end user worstation.
|
24
|
+
# We will avoid adding non default module like:
|
25
|
+
# - ptemplates, django for template interpreter. We use our own simple code to make it work with basics rules.
|
26
|
+
# It provides variable detection, with comments and default variables.
|
27
|
+
|
28
|
+
import sys
|
29
|
+
import getopt
|
30
|
+
#import urllib2
|
31
|
+
#from urlparse import urlparse,ParseResult
|
32
|
+
import re
|
33
|
+
import logging
|
34
|
+
import logging.handlers
|
35
|
+
import yaml
|
36
|
+
import os
|
37
|
+
#import subprocess
|
38
|
+
#import distutils.spawn
|
39
|
+
#import string
|
40
|
+
#from datetime import date,datetime
|
41
|
+
#import time
|
42
|
+
#import tempfile
|
43
|
+
import readline
|
44
|
+
|
45
|
+
# Defining defaults
|
46
|
+
|
47
|
+
GITBRANCH='master'
|
48
|
+
MAESTRO_RPATH_TMPL="templates/infra/"
|
49
|
+
MAESTRO_TMPL_FILE="maestro.box.GITBRANCH.env.tmpl"
|
50
|
+
MAESTRO_TMPL_PROVIDER='hpcloud'
|
51
|
+
|
52
|
+
#
|
53
|
+
#
|
54
|
+
|
55
|
+
##############################
|
56
|
+
def help(sMsg):
|
57
|
+
print 'build-env.py [-h|--help] --maestro-repo MaestroPath --env-path BuildEnvPath [--gitbranch BranchName] [-d|--debug] [-v|--verbose]'
|
58
|
+
|
59
|
+
# TODO Support for re-build it.
|
60
|
+
|
61
|
+
##############################
|
62
|
+
# TODO: split this function in 3, for code readibility
|
63
|
+
|
64
|
+
def BuildEnv(EnvPath, MaestroFile, MaestroPath, GitBranch):
|
65
|
+
"""Build env file if doesn't exist."""
|
66
|
+
|
67
|
+
global MAESTRO_TMPL_FILE
|
68
|
+
oLogging=logging.getLogger('build-env')
|
69
|
+
|
70
|
+
# -----------------------------------------------
|
71
|
+
# Check step ------------------------------------
|
72
|
+
|
73
|
+
if not os.path.exists(EnvPath):
|
74
|
+
oLogging.error("'%s' do not exist. This directory is required. (--env-path)", EnvPath)
|
75
|
+
sys.exit(1)
|
76
|
+
|
77
|
+
if not os.path.isdir(EnvPath):
|
78
|
+
oLogging.error("'%s' is not a valid directory (--env_path)", EnvPath)
|
79
|
+
sys.exit(1)
|
80
|
+
|
81
|
+
if not os.path.isdir(MaestroPath):
|
82
|
+
oLogging.error("'%s' is not a valid directory. Should refer to Maestro repository root dir.(--maestro-path)", MaestroPath)
|
83
|
+
sys.exit(1)
|
84
|
+
|
85
|
+
|
86
|
+
sInputFile=os.path.join(MaestroPath, MaestroFile)
|
87
|
+
if not os.path.exists(sInputFile):
|
88
|
+
oLogging.error("Unable to find template '%s' from '%s'. Are you sure about Maestro Repository root path given? Check and retry.", MaestroPath, MaestroFile)
|
89
|
+
sys.exit(1)
|
90
|
+
|
91
|
+
# Replace GITBRANCH Name by real git branch value.
|
92
|
+
sOutputFile=os.path.join(EnvPath,re.sub('GITBRANCH',GITBRANCH,MAESTRO_TMPL_FILE))
|
93
|
+
sOutputFile=re.sub('.tmpl$','',sOutputFile)
|
94
|
+
|
95
|
+
if os.path.exists(sOutputFile):
|
96
|
+
# TODO Support for re-build it.
|
97
|
+
oLogging.info("'%s' exists. If you want to rewrite it, remove the file before.", sOutputFile)
|
98
|
+
sys.exit(0)
|
99
|
+
|
100
|
+
# Load template variables and build list of variable to query
|
101
|
+
oLogging.debug("Opening template '%s'",sInputFile)
|
102
|
+
try:
|
103
|
+
fTmpl=open(sInputFile)
|
104
|
+
except IOError as e:
|
105
|
+
oLogging.error("Unable to open '%s'. Errno: %s (%s)", sInputFile, e.errno, e.strerror)
|
106
|
+
sys.exit(2)
|
107
|
+
|
108
|
+
# -----------------------------------------------
|
109
|
+
# Reading template ------------------------------
|
110
|
+
|
111
|
+
print("Reading template '{0}'".format(sInputFile))
|
112
|
+
oComments={}
|
113
|
+
oVars={}
|
114
|
+
|
115
|
+
# Search for Variable. If the variable name ends with '!', this value could not be null.
|
116
|
+
reVar=re.compile('[^$]{([A-Z_-]+)(!)?(:.*?)?}')
|
117
|
+
# 1: Variable Name
|
118
|
+
# 2: Required if = '!'
|
119
|
+
# 3: Default
|
120
|
+
|
121
|
+
|
122
|
+
# Search for comment
|
123
|
+
reComment=re.compile('^ *# +([A-Z_-]+): (.*)$')
|
124
|
+
|
125
|
+
for line in fTmpl:
|
126
|
+
|
127
|
+
# Detecting comment
|
128
|
+
oComment=reComment.search(line)
|
129
|
+
if oComment <> None:
|
130
|
+
oLogging.debug('Found "%s" = "%s"', oComment.group(1), oComment.group(2))
|
131
|
+
if oVars.has_key(oComment.group(1)):
|
132
|
+
oComments[oComment.group(1)]=oVars[oVar.group(1)]['comments']+'\n# '+oComment.group(2)
|
133
|
+
elif oComments.has_key(oComment.group(1)):
|
134
|
+
oComments[oComment.group(1)]=oComments[oComment.group(1)]+'\n# '+ oComment.group(2)
|
135
|
+
else:
|
136
|
+
oComments[oComment.group(1)]='# '+oComment.group(2)
|
137
|
+
|
138
|
+
oVar=reVar.search(line)
|
139
|
+
if oVar <> None:
|
140
|
+
oLogging.debug('Found var "%s" from "%s"',oVar.group(1),line)
|
141
|
+
|
142
|
+
sComment=''
|
143
|
+
if oComments.has_key(oVar.group(1)):
|
144
|
+
sComment=oComments[oVar.group(1)]
|
145
|
+
else:
|
146
|
+
oComments.remove(oVar.group(1))
|
147
|
+
|
148
|
+
sDefault=''
|
149
|
+
bRequired=False
|
150
|
+
if oVar.group(2) <> None :
|
151
|
+
bRequired=True
|
152
|
+
oLogging.debug("'%s' is required",oVar.group(1))
|
153
|
+
if oVar.group(3) <> None:
|
154
|
+
sDefault=oVar.group(3)[1:]
|
155
|
+
oLogging.debug("'%s' default value is '%s'",oVar.group(1),sDefault)
|
156
|
+
|
157
|
+
|
158
|
+
oVars[oVar.group(1)]={ 'comments': sComment,
|
159
|
+
'required': bRequired,
|
160
|
+
'default': sDefault }
|
161
|
+
|
162
|
+
oLogging.debug('template loaded.')
|
163
|
+
|
164
|
+
# -----------------------------------------------
|
165
|
+
# Ask section -----------------------------------
|
166
|
+
|
167
|
+
print "We need some information from you. Please ask the following question:\n"
|
168
|
+
# Time to ask information to the user.
|
169
|
+
|
170
|
+
for sElem in oVars:
|
171
|
+
print '{0}'.format(oVars[sElem]['comments'])
|
172
|
+
sPar="# "
|
173
|
+
if oVars[sElem]['default'] <> '':
|
174
|
+
sPar+='Default is "'+oVars[sElem]['default']+'".'
|
175
|
+
if oVars[sElem]['required'] :
|
176
|
+
if sPar <> "# " :
|
177
|
+
sPar+=' Required.'
|
178
|
+
else:
|
179
|
+
sPar='# Required.'
|
180
|
+
|
181
|
+
if sPar <> "":
|
182
|
+
print sPar
|
183
|
+
sValue=""
|
184
|
+
|
185
|
+
while sValue == "":
|
186
|
+
sValue=raw_input(sElem+'=')
|
187
|
+
|
188
|
+
if sValue == "":
|
189
|
+
sValue=oVars[sElem]['default']
|
190
|
+
|
191
|
+
if oVars[sElem]['required']:
|
192
|
+
if sValue == "":
|
193
|
+
print "[1mValue required[0m. Please enter a value.[2A[K"
|
194
|
+
else:
|
195
|
+
break
|
196
|
+
|
197
|
+
oVars[sElem]['value']=sValue
|
198
|
+
print '[A{0}="[1m{1}[0m"\n[K'.format(sElem,sValue)
|
199
|
+
|
200
|
+
|
201
|
+
fTmpl.seek(0) # Read the file again to replace data
|
202
|
+
try:
|
203
|
+
fOutputFile=open(sOutputFile,"w+")
|
204
|
+
except IOError as e:
|
205
|
+
oLogging.error("Unable to open '%s' for write. Errno: %s (%s)", sOutputFile, e.errno, e.strerror)
|
206
|
+
sys.exit(2)
|
207
|
+
|
208
|
+
print "--------------------------------\nThank you\nWriting '{0}'".format(sOutputFile)
|
209
|
+
|
210
|
+
# -----------------------------------------------
|
211
|
+
# Time to save the template. --------------------
|
212
|
+
|
213
|
+
reReplaced=re.compile('([^$])({([A-Z_-]+)(!)?(:.*?)?})')
|
214
|
+
for line in fTmpl:
|
215
|
+
oVar=reReplaced.search(line)
|
216
|
+
|
217
|
+
if oVar <> None:
|
218
|
+
|
219
|
+
if oVar.group(1) <> None:
|
220
|
+
sValue=oVar.group(1)+oVars[oVar.group(3)]['value']
|
221
|
+
else:
|
222
|
+
sValue=oVars[oVar.group(3)]['value']
|
223
|
+
sNewLine=reReplaced.sub(sValue,line)
|
224
|
+
else:
|
225
|
+
sNewLine=line
|
226
|
+
|
227
|
+
sys.stdout.flush()
|
228
|
+
fOutputFile.write(sNewLine)
|
229
|
+
|
230
|
+
fOutputFile.close()
|
231
|
+
fTmpl.close()
|
232
|
+
print 'Done'
|
233
|
+
|
234
|
+
|
235
|
+
|
236
|
+
##############################
|
237
|
+
def main(argv):
|
238
|
+
"""Main function"""
|
239
|
+
|
240
|
+
global GITBRANCH
|
241
|
+
global MAESTRO_TMPL_PROVIDER
|
242
|
+
global MAESTRO_RPATH_TMPL
|
243
|
+
|
244
|
+
oLogging=logging.getLogger('build-env')
|
245
|
+
oLogging.setLevel(20)
|
246
|
+
|
247
|
+
try:
|
248
|
+
opts,args = getopt.getopt(argv,"hp:vd:r:P:", ["help", "--for-provider=", "env-path=" , "maestro-path=" ,"debug" ,"verbose" ])
|
249
|
+
except getopt.GetoptError, e:
|
250
|
+
oLogging.error('Error: '+e.msg)
|
251
|
+
help()
|
252
|
+
sys.exit(2)
|
253
|
+
|
254
|
+
for opt, arg in opts:
|
255
|
+
if opt in ('-h', '--help'):
|
256
|
+
help()
|
257
|
+
sys.exit()
|
258
|
+
elif opt in ('-v','--verbose'):
|
259
|
+
if oLogging.level >20:
|
260
|
+
oLogging.setLevel(oLogging.level-10)
|
261
|
+
elif opt in ('--debug','-d'):
|
262
|
+
logging.getLogger().setLevel(logging.DEBUG)
|
263
|
+
logging.debug("Setting debug mode")
|
264
|
+
oLogging.setLevel(logging.DEBUG)
|
265
|
+
elif opt in ('-p', '--env-path'):
|
266
|
+
ENV_PATH=arg
|
267
|
+
elif opt in ('--gitbranch'):
|
268
|
+
GITBRANCH=arg
|
269
|
+
elif opt in ('-r','--maestro-path'):
|
270
|
+
MAESTRO_PATH=arg
|
271
|
+
elif opt in ('-P','--for-provider'):
|
272
|
+
TMPL_PROVIDER=arg
|
273
|
+
|
274
|
+
# Start Main tasks - Testing required variables.
|
275
|
+
if not 'ENV_PATH' in locals() or not 'MAESTRO_PATH' in locals():
|
276
|
+
oLogging.error("--env-path or --maestro-path values missing. Please check command flags.")
|
277
|
+
sys.exit(1)
|
278
|
+
|
279
|
+
|
280
|
+
global MAESTRO_TMPL_FILE # template file to use.
|
281
|
+
|
282
|
+
sMaestroFile=os.path.join(MAESTRO_RPATH_TMPL, MAESTRO_TMPL_PROVIDER+'-'+MAESTRO_TMPL_FILE)
|
283
|
+
BuildEnv(ENV_PATH, sMaestroFile, MAESTRO_PATH, GITBRANCH)
|
284
|
+
|
285
|
+
sys.exit(0)
|
286
|
+
|
287
|
+
#####################################
|
288
|
+
logging.basicConfig(format='%(asctime)s: %(levelname)s - %(message)s', datefmt='%m/%d/%Y %I:%M:%S %p')
|
289
|
+
|
290
|
+
if __name__ == "__main__":
|
291
|
+
main(sys.argv[1:])
|
292
|
+
|
293
|
+
|
data/lib/catalog.yaml
CHANGED
@@ -16,9 +16,18 @@ redstone:
|
|
16
16
|
image: proto2b
|
17
17
|
flavor: standard.xsmall
|
18
18
|
ports: [22, 80, 443, 3131, 3000, 3132, 3133, 3134, 3135, 4505, 4506, 5000, 5666, 8000, 8080, 8081, 8083, 8125, 8139, 8140, 8773, 8774, 8776, 9292, 29418, 35357]
|
19
|
-
|
19
|
+
keypair_path: ~/.hpcloud/keypairs/nova
|
20
|
+
keypair_name: nova
|
20
21
|
router: private-ext
|
21
|
-
|
22
|
+
security_group: default
|
23
|
+
network: private
|
24
|
+
# at this point you have to clone the infra project manually
|
25
|
+
build_config_dir: ~/forj/infra/build/boxes/maestro
|
26
|
+
build_config: box-13.5
|
27
|
+
branch: master
|
28
|
+
box_name: maestro
|
29
|
+
infra: ~/.forj/infra
|
30
|
+
|
22
31
|
|
23
32
|
modus:
|
24
33
|
ports: []
|
data/lib/compute.rb
ADDED
@@ -0,0 +1,38 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
# encoding: UTF-8
|
3
|
+
|
4
|
+
# (c) Copyright 2014 Hewlett-Packard Development Company, L.P.
|
5
|
+
#
|
6
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
7
|
+
# you may not use this file except in compliance with the License.
|
8
|
+
# You may obtain a copy of the License at
|
9
|
+
#
|
10
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
11
|
+
#
|
12
|
+
# Unless required by applicable law or agreed to in writing, software
|
13
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
14
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
15
|
+
# See the License for the specific language governing permissions and
|
16
|
+
# limitations under the License.
|
17
|
+
|
18
|
+
require 'rubygems'
|
19
|
+
require 'require_relative'
|
20
|
+
|
21
|
+
require_relative 'connection.rb'
|
22
|
+
include Connection
|
23
|
+
require_relative 'log.rb'
|
24
|
+
include Logging
|
25
|
+
|
26
|
+
#
|
27
|
+
# compute module
|
28
|
+
#
|
29
|
+
module Compute
|
30
|
+
def delete_forge(name)
|
31
|
+
instances = Connection.compute.servers.all(:name => name)
|
32
|
+
instances.each do|instance|
|
33
|
+
# make sure we don't delete another forge because fog filters
|
34
|
+
# the name in a "like syntax" way
|
35
|
+
Connection.compute.servers.get(instance.id).destroy
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
data/lib/down.rb
CHANGED
@@ -24,6 +24,12 @@ require_relative 'yaml_parse.rb'
|
|
24
24
|
include YamlParse
|
25
25
|
require_relative 'security.rb'
|
26
26
|
include SecurityGroup
|
27
|
+
require_relative 'log.rb'
|
28
|
+
include Logging
|
29
|
+
require_relative 'ssh.rb'
|
30
|
+
include Ssh
|
31
|
+
require_relative 'compute.rb'
|
32
|
+
include Compute
|
27
33
|
|
28
34
|
#
|
29
35
|
# Down module
|
@@ -32,30 +38,25 @@ module Down
|
|
32
38
|
def down(name)
|
33
39
|
begin
|
34
40
|
|
35
|
-
|
41
|
+
initial_msg = 'deleting forge "%s"' % [name]
|
42
|
+
Logging.info(initial_msg)
|
43
|
+
puts (initial_msg)
|
36
44
|
|
37
|
-
|
45
|
+
Compute.delete_forge(name)
|
38
46
|
|
39
|
-
|
40
|
-
subnet = Network
|
41
|
-
|
42
|
-
# delete the router interface
|
43
|
-
router = Network::get_router(definitions['redstone']['router'])
|
47
|
+
router = Network.get_router('private-ext')
|
48
|
+
subnet = Network.get_subnet(name)
|
44
49
|
Network.delete_router_interface(subnet.id, router)
|
45
50
|
|
46
|
-
# delete subnet
|
47
51
|
Network.delete_subnet(subnet.id)
|
48
|
-
|
49
|
-
|
50
|
-
# Network.delete_security_group(security_group.id)
|
51
|
-
|
52
|
-
# delete network
|
53
|
-
Network.delete_network(name)
|
52
|
+
network = Network.get_network(name)
|
53
|
+
Network.delete_network(network.name)
|
54
54
|
|
55
55
|
rescue SystemExit, Interrupt
|
56
56
|
puts 'process interrupted by user'
|
57
|
+
Logging.error('process interrupted by user')
|
57
58
|
rescue Exception => e
|
58
|
-
|
59
|
+
Logging.error(e.message)
|
59
60
|
end
|
60
61
|
end
|
61
62
|
end
|
data/lib/network.rb
CHANGED
@@ -27,6 +27,25 @@ include Logging
|
|
27
27
|
# Network module
|
28
28
|
#
|
29
29
|
module Network
|
30
|
+
def get_or_create_network(name)
|
31
|
+
network = get_network(name)
|
32
|
+
if network == nil
|
33
|
+
network = create_network(name)
|
34
|
+
end
|
35
|
+
network
|
36
|
+
end
|
37
|
+
|
38
|
+
def get_network(name)
|
39
|
+
begin
|
40
|
+
info = 'getting network %s' % [name]
|
41
|
+
Logging.info(info)
|
42
|
+
Connection.network.networks.all(:name => name)[0]
|
43
|
+
rescue => e
|
44
|
+
puts e.message
|
45
|
+
Logging.error(e.message)
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
30
49
|
def create_network(name)
|
31
50
|
begin
|
32
51
|
info = 'creating network %s' % [name]
|
@@ -39,13 +58,25 @@ module Network
|
|
39
58
|
|
40
59
|
def delete_network(network_name)
|
41
60
|
begin
|
42
|
-
network =
|
61
|
+
network = get_network(network_name)
|
43
62
|
Connection.network.networks.get(network.id).destroy
|
44
63
|
rescue => e
|
45
64
|
Logging.error(e.message)
|
46
65
|
end
|
47
66
|
end
|
48
67
|
|
68
|
+
def get_or_create_subnet(network_id, name)
|
69
|
+
begin
|
70
|
+
subnet = get_subnet(name)
|
71
|
+
if subnet == nil
|
72
|
+
subnet = create_subnet(network_id, name)
|
73
|
+
end
|
74
|
+
subnet
|
75
|
+
rescue => e
|
76
|
+
Logging.error(e.message)
|
77
|
+
end
|
78
|
+
end
|
79
|
+
|
49
80
|
def create_subnet(network_id, name)
|
50
81
|
begin
|
51
82
|
Connection.network.subnets.create(
|
data/lib/repositories.rb
CHANGED
@@ -49,5 +49,23 @@ module Repositories
|
|
49
49
|
Logging.error(e.message)
|
50
50
|
end
|
51
51
|
Dir.chdir(current_dir)
|
52
|
+
end
|
53
|
+
def create_infra
|
54
|
+
home = File.expand_path('~')
|
55
|
+
path = home + '/.forj/'
|
56
|
+
infra = path + 'infra/'
|
57
|
+
|
58
|
+
if File.directory?(infra)
|
59
|
+
FileUtils.rm_r(infra)
|
52
60
|
end
|
61
|
+
Dir.mkdir(infra)
|
62
|
+
|
63
|
+
command = 'cp -rp ~/.forj/maestro/templates/infra/cloud-init ~/.forj/infra/'
|
64
|
+
Kernel.system(command)
|
65
|
+
|
66
|
+
Dir.chdir('build_tmpl')
|
67
|
+
|
68
|
+
fill_template = 'python build-env.py -p ~/.forj/infra --maestro-path ~/.forj/maestro'
|
69
|
+
Kernel.system(fill_template)
|
70
|
+
end
|
53
71
|
end
|
data/lib/security.rb
CHANGED
@@ -28,6 +28,15 @@ include Logging
|
|
28
28
|
#
|
29
29
|
module SecurityGroup
|
30
30
|
|
31
|
+
def get_or_create_security_group(name)
|
32
|
+
Logging.info('getting or creating security group for %s' % [name])
|
33
|
+
security_group = get_security_group(name)
|
34
|
+
if security_group == nil
|
35
|
+
security_group = create_security_group(name)
|
36
|
+
end
|
37
|
+
security_group
|
38
|
+
end
|
39
|
+
|
31
40
|
def create_security_group(name)
|
32
41
|
sec_group = nil
|
33
42
|
begin
|
@@ -48,6 +57,14 @@ module SecurityGroup
|
|
48
57
|
sec_group
|
49
58
|
end
|
50
59
|
|
60
|
+
def get_security_group(name)
|
61
|
+
begin
|
62
|
+
Connection.network.security_groups.all({:name => name})[0]
|
63
|
+
rescue => e
|
64
|
+
Logging.error(e.message)
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
51
68
|
def delete_security_group(security_group)
|
52
69
|
begin
|
53
70
|
sec_group = get_security_group(security_group)
|
@@ -82,14 +99,23 @@ module SecurityGroup
|
|
82
99
|
end
|
83
100
|
end
|
84
101
|
|
85
|
-
def
|
102
|
+
def get_security_group_rule(port)
|
86
103
|
begin
|
87
|
-
Connection.network.
|
104
|
+
Connection.network.security_group_rules.all({:port_range_min => port, :port_range_max => port})[0]
|
88
105
|
rescue => e
|
89
106
|
Logging.error(e.message)
|
90
107
|
end
|
91
108
|
end
|
92
109
|
|
110
|
+
def get_or_create_rule(security_group_id, protocol, port_min, port_max)
|
111
|
+
Logging.info('getting or creating rule %s' % [port_min])
|
112
|
+
rule = get_security_group_rule(port_min)
|
113
|
+
if rule == nil
|
114
|
+
rule = create_security_group_rule(security_group_id, protocol, port_min, port_max)
|
115
|
+
end
|
116
|
+
rule
|
117
|
+
end
|
118
|
+
|
93
119
|
def upload_existing_key(key_name, key_path)
|
94
120
|
command = 'hpcloud keypairs:import %s %s' % [key_name, key_path]
|
95
121
|
Kernel.system(command)
|
data/lib/setup.rb
CHANGED
@@ -15,6 +15,12 @@
|
|
15
15
|
# See the License for the specific language governing permissions and
|
16
16
|
# limitations under the License.
|
17
17
|
|
18
|
+
require 'rubygems'
|
19
|
+
require 'require_relative'
|
20
|
+
|
21
|
+
require_relative 'yaml_parse.rb'
|
22
|
+
include YamlParse
|
23
|
+
|
18
24
|
#
|
19
25
|
# Setup module call the hpcloud functions
|
20
26
|
#
|
@@ -22,6 +28,51 @@ module Setup
|
|
22
28
|
def setup
|
23
29
|
# delegate the initial configuration to hpcloud (unix_cli)
|
24
30
|
Kernel.system('hpcloud account:setup')
|
25
|
-
|
31
|
+
setup_credentials
|
32
|
+
save_cloud_fog
|
33
|
+
#Kernel.system('hpcloud keypairs:add nova')
|
26
34
|
end
|
27
35
|
end
|
36
|
+
|
37
|
+
def setup_credentials
|
38
|
+
puts 'Enter hpcloud username: '
|
39
|
+
hpcloud_os_user = $stdin.gets
|
40
|
+
puts 'Enter hpcloud password: '
|
41
|
+
hpcloud_os_key = $stdin.gets
|
42
|
+
|
43
|
+
home = File.expand_path('~')
|
44
|
+
creds = '%s/.cache/forj/creds' % [home]
|
45
|
+
File.open(creds, 'w') {|file|
|
46
|
+
file.write('HPCLOUD_OS_USER=%s' % [hpcloud_os_user])
|
47
|
+
file.write('HPCLOUD_OS_KEY=%s' % [hpcloud_os_key])
|
48
|
+
}
|
49
|
+
end
|
50
|
+
|
51
|
+
|
52
|
+
def save_cloud_fog
|
53
|
+
home = File.expand_path('~')
|
54
|
+
|
55
|
+
cloud_fog = '%s/.cache/forj/master.forj-13.5' % [home]
|
56
|
+
local_creds = '%s/.cache/forj/creds' % [home]
|
57
|
+
|
58
|
+
creds = '%s/.hpcloud/accounts/hp' % [home]
|
59
|
+
template = YAML.load_file(creds)
|
60
|
+
local_template = YAML.load_file(local_creds)
|
61
|
+
|
62
|
+
|
63
|
+
access_key = template[:credentials][:account_id]
|
64
|
+
secret_key = template[:credentials][:secret_key]
|
65
|
+
|
66
|
+
os_user = local_template['HPCLOUD_OS_USER']
|
67
|
+
os_key = local_template['HPCLOUD_OS_KEY']
|
68
|
+
|
69
|
+
File.open(cloud_fog, 'w') {|file|
|
70
|
+
file.write('HPCLOUD_OS_USER=%s' % [os_user])
|
71
|
+
file.write('HPCLOUD_OS_KEY=%s' % [os_key])
|
72
|
+
file.write('DNS_KEY=%s' % [access_key])
|
73
|
+
file.write('DNS_SECRET=%s' % [secret_key])
|
74
|
+
}
|
75
|
+
|
76
|
+
command = 'cat %s | gzip -c | base64 -w0 > %s.g64' % [cloud_fog, cloud_fog]
|
77
|
+
Kernel.system(command)
|
78
|
+
end
|
data/lib/ssh.rb
CHANGED
@@ -18,11 +18,16 @@
|
|
18
18
|
require 'rubygems'
|
19
19
|
require 'require_relative'
|
20
20
|
|
21
|
+
require_relative 'log.rb'
|
22
|
+
include Logging
|
23
|
+
|
21
24
|
#
|
22
25
|
# ssh module
|
23
26
|
#
|
24
27
|
module Ssh
|
25
28
|
def connect(name, server)
|
29
|
+
msg = 'logging into %s : %s' % [name, server]
|
30
|
+
Logging.info(msg)
|
26
31
|
current_dir = Dir.pwd
|
27
32
|
Dir.chdir(current_dir + '/lib')
|
28
33
|
|
data/lib/ssh.sh
CHANGED
@@ -22,9 +22,10 @@ GRE="\e[92m"
|
|
22
22
|
OW=`date +%Y-%m-%d.%H%M%S`
|
23
23
|
logpath=~/.ssh/
|
24
24
|
DB=~/hosts
|
25
|
-
key_path=~/.ssh/
|
25
|
+
#key_path=~/.ssh/
|
26
|
+
#key_path=~/.hpcloud/keypairs/
|
26
27
|
init_config=~/ssh_init
|
27
|
-
key="nova"
|
28
|
+
key="nova.pem"
|
28
29
|
|
29
30
|
if [ ! -f $DB ]; then
|
30
31
|
cat > $DB <<'EOF'
|
data/spec/spec_helper.rb
CHANGED
@@ -5,7 +5,7 @@
|
|
5
5
|
#
|
6
6
|
# Given that it is always loaded, you are encouraged to keep this file as
|
7
7
|
# light-weight as possible. Requiring heavyweight dependencies from this file
|
8
|
-
# will add to the boot time of your test suite on EVERY test run, even for an
|
8
|
+
# will add to the boot time of your test.rb suite on EVERY test.rb run, even for an
|
9
9
|
# individual file that may not need all of that loaded. Instead, make a
|
10
10
|
# separate helper file that requires this one and then use it only in the specs
|
11
11
|
# that actually need it.
|
@@ -48,7 +48,7 @@ RSpec.configure do |config|
|
|
48
48
|
|
49
49
|
# Seed global randomization in this process using the `--seed` CLI option.
|
50
50
|
# Setting this allows you to use `--seed` to deterministically reproduce
|
51
|
-
# test failures related to randomization by passing the same `--seed` value
|
51
|
+
# test.rb failures related to randomization by passing the same `--seed` value
|
52
52
|
# as the one that triggered the failure.
|
53
53
|
Kernel.srand config.seed
|
54
54
|
|
@@ -62,7 +62,7 @@ RSpec.configure do |config|
|
|
62
62
|
expectations.syntax = :expect
|
63
63
|
end
|
64
64
|
|
65
|
-
# rspec-mocks config goes here. You can use an alternate test double
|
65
|
+
# rspec-mocks config goes here. You can use an alternate test.rb double
|
66
66
|
# library (such as bogus or mocha) by changing the `mock_with` option here.
|
67
67
|
config.mock_with :rspec do |mocks|
|
68
68
|
# Enable only the newer, non-monkey-patching expect syntax.
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: forj
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.31
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -13,7 +13,7 @@ date: 2014-06-12 00:00:00.000000000 Z
|
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: thor
|
16
|
-
requirement: &
|
16
|
+
requirement: &4634460 !ruby/object:Gem::Requirement
|
17
17
|
none: false
|
18
18
|
requirements:
|
19
19
|
- - ! '>='
|
@@ -21,10 +21,10 @@ dependencies:
|
|
21
21
|
version: 0.16.0
|
22
22
|
type: :runtime
|
23
23
|
prerelease: false
|
24
|
-
version_requirements: *
|
24
|
+
version_requirements: *4634460
|
25
25
|
- !ruby/object:Gem::Dependency
|
26
26
|
name: nokogiri
|
27
|
-
requirement: &
|
27
|
+
requirement: &4633120 !ruby/object:Gem::Requirement
|
28
28
|
none: false
|
29
29
|
requirements:
|
30
30
|
- - ~>
|
@@ -32,10 +32,10 @@ dependencies:
|
|
32
32
|
version: 1.5.11
|
33
33
|
type: :runtime
|
34
34
|
prerelease: false
|
35
|
-
version_requirements: *
|
35
|
+
version_requirements: *4633120
|
36
36
|
- !ruby/object:Gem::Dependency
|
37
37
|
name: fog
|
38
|
-
requirement: &
|
38
|
+
requirement: &4629760 !ruby/object:Gem::Requirement
|
39
39
|
none: false
|
40
40
|
requirements:
|
41
41
|
- - ~>
|
@@ -43,10 +43,10 @@ dependencies:
|
|
43
43
|
version: 1.19.0
|
44
44
|
type: :runtime
|
45
45
|
prerelease: false
|
46
|
-
version_requirements: *
|
46
|
+
version_requirements: *4629760
|
47
47
|
- !ruby/object:Gem::Dependency
|
48
48
|
name: hpcloud
|
49
|
-
requirement: &
|
49
|
+
requirement: &4629180 !ruby/object:Gem::Requirement
|
50
50
|
none: false
|
51
51
|
requirements:
|
52
52
|
- - ~>
|
@@ -54,10 +54,10 @@ dependencies:
|
|
54
54
|
version: 2.0.8
|
55
55
|
type: :runtime
|
56
56
|
prerelease: false
|
57
|
-
version_requirements: *
|
57
|
+
version_requirements: *4629180
|
58
58
|
- !ruby/object:Gem::Dependency
|
59
59
|
name: git
|
60
|
-
requirement: &
|
60
|
+
requirement: &4628460 !ruby/object:Gem::Requirement
|
61
61
|
none: false
|
62
62
|
requirements:
|
63
63
|
- - ! '>='
|
@@ -65,10 +65,10 @@ dependencies:
|
|
65
65
|
version: 1.2.7
|
66
66
|
type: :runtime
|
67
67
|
prerelease: false
|
68
|
-
version_requirements: *
|
68
|
+
version_requirements: *4628460
|
69
69
|
- !ruby/object:Gem::Dependency
|
70
70
|
name: rbx-require-relative
|
71
|
-
requirement: &
|
71
|
+
requirement: &4627320 !ruby/object:Gem::Requirement
|
72
72
|
none: false
|
73
73
|
requirements:
|
74
74
|
- - ~>
|
@@ -76,7 +76,7 @@ dependencies:
|
|
76
76
|
version: 0.0.7
|
77
77
|
type: :runtime
|
78
78
|
prerelease: false
|
79
|
-
version_requirements: *
|
79
|
+
version_requirements: *4627320
|
80
80
|
description: forj command line
|
81
81
|
email:
|
82
82
|
- forj@forj.io
|
@@ -86,6 +86,7 @@ extensions: []
|
|
86
86
|
extra_rdoc_files: []
|
87
87
|
files:
|
88
88
|
- bin/forj
|
89
|
+
- lib/compute.rb
|
89
90
|
- lib/connection.rb
|
90
91
|
- lib/network.rb
|
91
92
|
- lib/security.rb
|
@@ -99,6 +100,7 @@ files:
|
|
99
100
|
- lib/ssh.sh
|
100
101
|
- lib/log.rb
|
101
102
|
- lib/helpers.rb
|
103
|
+
- lib/build_tmpl/build-env.py
|
102
104
|
- spec/boot_spec.rb
|
103
105
|
- spec/connection_spec.rb
|
104
106
|
- spec/down_spec.rb
|