forj 0.0.48 → 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 889541f2f3a27b5291850a04d26e706d82fae15c
4
- data.tar.gz: 45c2194d9130f2b7776fe6d5e0d24bb873f6c0a8
3
+ metadata.gz: 1fe45b075653728015aec4bace3b604d214c94e4
4
+ data.tar.gz: f00361d094599e50b214c8fecdb17e95b04c56a5
5
5
  SHA512:
6
- metadata.gz: 6e83e7256e96eb4dab205210c2e0e12f40eaf06ba6d790f48dc2359571b2566b2013d6b4da78ed8c28494999b85d6ad872f426a222e363d84f6a890b8905abd3
7
- data.tar.gz: 5bbfe230e6199ddadfaae0a7fed6384878f80455533d22fc5eb142c4a5875a323b7d2081c01638e9f85ff37c27b2972d86f9976ac0cf46c42d5ed834c6fcbc23
6
+ metadata.gz: 3429c0634f5dea3a1174c47277e0e188905e52cc61ef6a7b66a3d507463a7373166e750a79bb9d0999ea1e0751fe1c542138c224ab99cd680cc91fc7e47ec95f
7
+ data.tar.gz: 7ba23851e38c291693c8d24b1abc09022cad244eb56b4e03731145c576181e8f94d792872023eee0451f0f0e1eba78624c1897c7c4bad2e21723a0ef91515f3c
data/Gemfile CHANGED
@@ -19,19 +19,20 @@ source 'https://rubygems.org'
19
19
  group(:development, :test) do
20
20
  gem 'rake'
21
21
  gem 'debugger'
22
+ gem 'byebug'
22
23
  gem 'rspec', "~> 3.1.0", :require => false
23
24
  end
24
25
 
25
26
  gem 'mime-types','1.25.1'
26
27
  gem 'excon','0.31.0'
27
- gem 'json','~>1.7.5'
28
+ gem 'json','1.7.5'
28
29
  gem 'nokogiri','1.5.11'
29
30
  gem 'fog', '1.19.0'
30
31
  gem 'git', '>=1.2.7'
31
32
  gem 'rainbow'
32
33
  gem 'rbx-require-relative', '~> 0.0.7'
33
34
  gem 'thor', '>=0.16.0'
34
- gem 'hpcloud', '~>2.0.8'
35
+ gem 'hpcloud', '~>2.0.9'
35
36
  gem 'highline','>=1.6.21'
36
37
  gem 'ansi','>=1.4.3'
37
38
  gem 'encryptor','>=1.3.0'
data/bin/forj CHANGED
@@ -25,6 +25,7 @@ $APP_PATH = File.dirname(__FILE__)
25
25
  $LIB_PATH = File.expand_path(File.join(File.dirname($APP_PATH),'lib'))
26
26
 
27
27
  $LOAD_PATH << $LIB_PATH
28
+ $LOAD_PATH << File.join($LIB_PATH, 'lib-forj', 'lib')
28
29
 
29
30
  require 'appinit.rb' # Load generic Application level function
30
31
 
@@ -38,20 +39,18 @@ require 'forj-config.rb' # Load class ForjConfig and Meta data class variables.
38
39
  require 'forj-account.rb' # Load class ForjAccount
39
40
  require 'connection.rb' # Load class ForjConnection
40
41
 
41
- require 'boot.rb'
42
42
  require 'down.rb'
43
- require 'setup.rb'
44
43
  require 'ssh.rb'
45
44
 
46
- include Boot
47
45
  include Down
48
- include Setup
49
46
  include Ssh
50
47
  require 'forj-settings.rb' # Settings features
51
48
 
52
49
  #require 'debugger' # Use to debug with Ruby < 2.0
53
50
  #require 'byebug' # Use to debug with Ruby >= 2.0
51
+ require 'lib-forj.rb'
54
52
 
53
+ $LIB_FORJ_DEBUG = 1 # less verbose
55
54
 
56
55
 
57
56
  class ForjThor < Thor
@@ -59,6 +58,7 @@ class ForjThor < Thor
59
58
  class_option :debug, :aliases => '-d', :desc => 'Set debug mode'
60
59
  class_option :verbose, :aliases => '-v', :desc => 'Set verbose mode'
61
60
  class_option :config, :aliases => '-c', :desc => 'Path to a different forj config file. By default, use ~/.forj/config.yaml'
61
+ class_option :libforj_debug, :desc => "Set lib-forj debug level verbosity. 1 to 5. Default is one."
62
62
 
63
63
 
64
64
  desc "help [action]", "Describe available FORJ actions or one specific action"
@@ -144,6 +144,11 @@ Maestro/infra bootstrap debugging:"
144
144
  Logging.set_level(Logger::INFO) if options[:verbose]
145
145
  Logging.set_level(Logger::DEBUG) if options[:debug]
146
146
 
147
+ unless options[:libforj_debug].nil?
148
+ $LIB_FORJ_DEBUG = options[:libforj_debug].to_i
149
+ Logging.set_level(Logger::DEBUG)
150
+ end
151
+
147
152
  oConfig = ForjConfig.new(options[:config])
148
153
 
149
154
 
@@ -179,6 +184,7 @@ Maestro/infra bootstrap debugging:"
179
184
  oConfig.set(:branch , options[:branch])
180
185
  oConfig.set(:test_box, File.expand_path(options[:test_box])) if options[:test_box] and File.directory?(File.expand_path(options[:test_box]))
181
186
 
187
+ Logging.warning("test_box is currently disabled in this version. It will be re-activated in newer version.") if options[:test_box]
182
188
 
183
189
  if options[:key_path]
184
190
  mFound = options[:key_path].match(/^(.*)(\.pub)?$/)
@@ -192,8 +198,28 @@ Maestro/infra bootstrap debugging:"
192
198
  Logging.fatal(1, "'%s' is not a valid keypair files. At least the public key (.pub) is have to exist.")
193
199
  end
194
200
  end
201
+ aProcesses = []
202
+
203
+ # Defines how to manage Maestro and forges
204
+ # create a maestro box. Identify a forge instance, delete it,...
205
+ aProcesses << File.join($LIB_PATH, 'forj', 'ForjCore.rb')
206
+
207
+ # Defines how cli will control FORJ features
208
+ # boot/down/ssh/...
209
+ aProcesses << File.join($LIB_PATH, 'forj', 'ForjCli.rb')
210
+
211
+ oCloud = ForjCloud.new(oForjAccount, oConfig[:account_name], aProcesses)
195
212
 
196
- Boot.boot(blueprint, name, options[:build], options[:boothook], options[:box_name], oForjAccount)
213
+ oConfig[:instance_name] = name
214
+
215
+ if blueprint == 'maestro'
216
+ Logging.info("Starting boot process of '%s'. No blueprint requested." % oConfig[:instance_name])
217
+ else
218
+ oConfig[:blueprint] = blueprint
219
+ Logging.info("Starting boot process of '%s' with blueprint '%s'." % [oConfig[:instance_name], oConfig[:blueprint]])
220
+ end
221
+ oCloud.Create(:forge)
222
+ #Boot.boot(blueprint, name, options[:build], options[:boothook], options[:box_name], oForjAccount)
197
223
  end
198
224
 
199
225
  ################################# Show defaults
@@ -367,12 +393,9 @@ ex: forj ssh myforge review
367
393
  end
368
394
 
369
395
  ################################# SETUP
370
- method_option :keypair_name, :aliases => '-k', :desc => "config keypair_name : Keypair name attached as default to your FORJ account."
371
- method_option :keypair_path, :aliases => '-p', :desc => "config keypair_path : SSH key file (private or public) to attach as default to your FORJ account.
372
- It will attach any detected private/public key thanks to the file name
373
- (without extension/.pem = private, .pub = public)"
374
396
 
375
397
  desc 'setup [AccountName [Provider]] [options]', "Setup FORJ cloud account credentials and information."
398
+
376
399
  long_desc <<-LONGDESC
377
400
  This setup will configure a FORJ account used to connect to your cloud system.
378
401
  \x5It will ask for your cloud provider credentials and services.
@@ -389,14 +412,33 @@ Several data will be requested like:
389
412
  \x5- domain name to add to each boxes hostname
390
413
  LONGDESC
391
414
  def setup(sAccountName = 'hpcloud', sProvider = "hpcloud")
392
- Logging.set_level(Logger::INFO) if options[:verbose]
393
- Logging.set_level(Logger::DEBUG) if options[:debug]
394
- oConfig=ForjConfig.new(options[:config])
395
- oConfig.set(:provider, sProvider)
396
- oConfig.set(:account_name, sAccountName)
397
- oConfig.set(:keypair_path, options[:keypair_path]) if options[:keypair_path]
398
- oConfig.set(:keypair_name, options[:keypair_name]) if options[:keypair_name]
399
- Setup.setup(oConfig)
415
+ Logging.set_level(Logger::INFO) if options[:verbose]
416
+ Logging.set_level(Logger::DEBUG) if options[:debug]
417
+
418
+ unless options[:libforj_debug].nil?
419
+ $LIB_FORJ_DEBUG = options[:libforj_debug].to_i
420
+ Logging.set_level(Logger::DEBUG)
421
+ end
422
+
423
+ oConfig=ForjConfig.new(options[:config])
424
+ oConfig.set(:provider_name, sProvider)
425
+ oConfig.set(:account_name, sAccountName)
426
+
427
+ aProcesses = []
428
+
429
+ # Defines how to manage Maestro and forges
430
+ # create a maestro box. Identify a forge instance, delete it,...
431
+ aProcesses << File.join($LIB_PATH, 'forj', 'ForjCore.rb')
432
+
433
+ # Defines how cli will control FORJ features
434
+ # boot/down/ssh/...
435
+ aProcesses << File.join($LIB_PATH, 'forj', 'ForjCli.rb')
436
+
437
+ oCloud = ForjCloud.new(oConfig, sAccountName, aProcesses)
438
+
439
+ oCloud.Setup(:forge, sAccountName)
440
+ oCloud.config.ac_save()
441
+
400
442
  end
401
443
 
402
444
  end
data/lib/appinit.rb CHANGED
@@ -29,6 +29,7 @@ module AppInit
29
29
  $FORJ_DATA_PATH = File.expand_path(File.join('~', '.forj'))
30
30
  $FORJ_ACCOUNTS_PATH = File.join($FORJ_DATA_PATH, 'accounts')
31
31
  $FORJ_KEYPAIRS_PATH = File.join($FORJ_DATA_PATH, 'keypairs')
32
+ $FORJ_BUILD_PATH = File.join($FORJ_DATA_PATH, '.build')
32
33
  $FORJ_CREDS_PATH = File.expand_path(File.join('~', '.cache', 'forj'))
33
34
 
34
35
  # TODO: To move to an hpcloud object.
@@ -37,6 +38,7 @@ module AppInit
37
38
 
38
39
  AppInit.ensure_dir_exists($FORJ_DATA_PATH)
39
40
  AppInit.ensure_dir_exists($FORJ_ACCOUNTS_PATH)
41
+ AppInit.ensure_dir_exists($FORJ_BUILD_PATH)
40
42
  AppInit.ensure_dir_exists($FORJ_KEYPAIRS_PATH)
41
43
  FileUtils.chmod(0700, $FORJ_KEYPAIRS_PATH)
42
44
  AppInit.ensure_dir_exists($FORJ_CREDS_PATH)
@@ -0,0 +1,145 @@
1
+ #!/bin/bash
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
+
18
+ APP_NAME="maestro"
19
+ APPPATH=.
20
+ BUILD_DIR="$1/.build"
21
+ MAESTRO_REPO="$2"
22
+ BOOTSTRAP_DIR="$3"
23
+ BOOTSTRAP_EXTRA="$4"
24
+ META_JSON="$5"
25
+ MIME_SCRIPT="$6"
26
+ USER_DATA="$7"
27
+
28
+ mkdir -p $BUILD_DIR
29
+
30
+ BOOTHOOK="$MAESTRO_REPO/build/bin/build-tools/boothook.sh"
31
+
32
+ function Info
33
+ {
34
+ echo "INFO: $1"
35
+ }
36
+
37
+ function Warning
38
+ {
39
+ echo "WARN: $1"
40
+ }
41
+
42
+ function bootstrap_build
43
+ {
44
+ Info "Preparing cloudinit mime."
45
+
46
+ cd $MAESTRO_REPO/build/$APP_NAME
47
+
48
+ # Maestro BootHook - Set hostname and workaround missing meta.js
49
+ Info "Boothook used: $BOOTHOOK"
50
+ sed 's!${metadata-json}!'"$META_JSON"'!g' $BOOTHOOK > $BUILD_DIR/boothook.sh
51
+ TOMIME="$BUILD_DIR/boothook.sh:text/cloud-boothook"
52
+
53
+ # Add cloudconfig.yaml - Inform cloud-init to no update hostname & install basic packages.
54
+ if [ -f cloudconfig.yaml ]
55
+ then
56
+ TOMIME="$TOMIME cloudconfig.yaml"
57
+ fi
58
+
59
+ # Maestro boot. Use maestro/{#}-*.sh to build a shell script added to the cloud-init mime file.
60
+ BOOT_BOX=$BUILD_DIR/boot_${APP_NAME}.sh
61
+
62
+ rm -f $BOOT_BOX
63
+
64
+ if [ "$BOOTSTRAP_DIR" != "" ]
65
+ then
66
+ if [ "$(find $BOOTSTRAP_DIR -maxdepth 1 \( -type f -o -type l \) -name \*.sh -exec basename {} \; | wc -l)" -eq 0 ]
67
+ then
68
+ Warning "'$BOOTSTRAP_DIR' contains no bootstrap files. Please check it."
69
+ else
70
+ Info "Completing Box basic cloud-init with '$BOOTSTRAP_DIR'"
71
+ fi
72
+ fi
73
+ if [ -d "$BOOTSTRAP_EXTRA" ]
74
+ then
75
+ Info "Completing Box basic cloud-init with '$BOOTSTRAP_EXTRA'"
76
+ fi
77
+
78
+ BOOT_FILES="$(find bootstrap $BOOTSTRAP_EXTRA $BOOTSTRAP_DIR -maxdepth 1 \( -type f -o -type l \) -name \*.sh -exec basename {} \; | sort -u)"
79
+
80
+ echo "Read boot script: "
81
+ for BOOT_FILE in $BOOT_FILES
82
+ do
83
+ for DIR in bootstrap $BOOTSTRAP_EXTRA $BOOTSTRAP_DIR
84
+ do
85
+ if [ ! -f $BOOT_BOX ]
86
+ then
87
+ printf "#!/bin/bash\n# This script was automatically generated by ${0}. Do not edit it.\n" > $BOOT_BOX
88
+ fi
89
+ if [ -r $DIR/$BOOT_FILE ]
90
+ then
91
+ printf "\n#############\n# bootstrap builder: include $DIR/$BOOT_FILE\n#############\n\n" >> $BOOT_BOX
92
+ cat $DIR/$BOOT_FILE >> $BOOT_BOX
93
+ echo "Included : $DIR/$BOOT_FILE"
94
+ fi
95
+ done
96
+ done
97
+ printf "\n"
98
+ if [ -r $BOOT_BOX ]
99
+ then
100
+ Info "$BOOT_BOX added to the mime."
101
+ TOMIME="$TOMIME $BOOT_BOX"
102
+ fi
103
+ if [ -d "$BOOTSTRAP_EXTRA" ]
104
+ then
105
+ rm -fr "$BOOTSTRAP_EXTRA"
106
+ fi
107
+
108
+ for FILE in $TOMIME
109
+ do
110
+ if [ "$(echo $FILE| grep ':')" = "" ]
111
+ then
112
+ TYPE=""
113
+ else
114
+ TYPE=$(echo $FILE| sed 's/^.*:/:/g')
115
+ fi
116
+ FILE=$(echo $FILE| sed 's/:.*//g')
117
+ if [ "$(echo $FILE | cut -c1)" = / ]
118
+ then # Metadata file built to use
119
+ REAL_FILE="$(echo "$BUILD_DIR/$(basename $FILE)")"
120
+ else # Source file to use
121
+ REAL_FILE="$(echo "$FILE")"
122
+ fi
123
+ if [ ! -f "$REAL_FILE" ]
124
+ then
125
+ printf "\ncloudinit.conf: $REAL_FILE not found.\n"
126
+ exit 1
127
+ fi
128
+ FILES="$FILES $REAL_FILE$TYPE"
129
+ printf "$FILE\e[32m$TYPE\e[0m "
130
+ done
131
+
132
+ $MIME_SCRIPT $FILES -o "$USER_DATA"
133
+ if [ $? -ne 0 ]
134
+ then
135
+ echo "cloudinit.conf: Error while building $BUILD_DIR/userdata.mime with 'write-mime-multipart.py'. Please check."
136
+ exit 1
137
+ fi
138
+ echo " > $USER_DATA"
139
+
140
+
141
+
142
+ }
143
+
144
+
145
+ bootstrap_build
@@ -0,0 +1,128 @@
1
+ #!/usr/bin/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
+ # largely taken from python examples
18
+ # http://docs.python.org/library/email-examples.html
19
+
20
+ import os
21
+ import sys
22
+
23
+
24
+ from email import encoders
25
+ from email.mime.base import MIMEBase
26
+ from email.mime.multipart import MIMEMultipart
27
+ from email.mime.text import MIMEText
28
+ from optparse import OptionParser
29
+ import gzip
30
+
31
+ from base64 import b64encode
32
+
33
+ COMMASPACE = ', '
34
+
35
+ starts_with_mappings = {
36
+ '#include': 'text/x-include-url',
37
+ '#!': 'text/x-shellscript',
38
+ '#cloud-config': 'text/cloud-config',
39
+ '#upstart-job': 'text/upstart-job',
40
+ '#part-handler': 'text/part-handler',
41
+ '#cloud-boothook': 'text/cloud-boothook'
42
+ }
43
+
44
+
45
+ def get_type(fname, deftype):
46
+ f = file(fname, "rb")
47
+ line = f.readline()
48
+ f.close()
49
+ rtype = deftype
50
+ for _str, mtype in starts_with_mappings.items():
51
+ if line.startswith(_str):
52
+ rtype = mtype
53
+ break
54
+ return rtype
55
+
56
+
57
+ def main():
58
+ outer = MIMEMultipart()
59
+
60
+ parser = OptionParser()
61
+
62
+ parser.add_option("-o", "--output", dest="output",
63
+ help="write output to FILE [default %default]",
64
+ metavar="FILE", default="-")
65
+ parser.add_option("-z", "--gzip", dest="compress", action="store_true",
66
+ help="compress output", default=False)
67
+ parser.add_option("-d", "--default", dest="deftype",
68
+ help="default mime type [default %default]",
69
+ default="text/plain")
70
+ parser.add_option("--delim", dest="delim",
71
+ help="delimiter [default %default]", default=":")
72
+ parser.add_option("-b", "--base64", dest="base64", action="store_true",
73
+ help="encode content base64", default=False)
74
+
75
+ (options, args) = parser.parse_args()
76
+
77
+ if (len(args)) < 1:
78
+ parser.error("Must give file list see '--help'")
79
+
80
+ for arg in args:
81
+ t = arg.split(options.delim, 1)
82
+ path = t[0]
83
+ if len(t) > 1:
84
+ mtype = t[1]
85
+ else:
86
+ mtype = get_type(path, options.deftype)
87
+
88
+ maintype, subtype = mtype.split('/', 1)
89
+ if maintype == 'text':
90
+ fp = open(path)
91
+ # Note: we should handle calculating the charset
92
+ msg = MIMEText(fp.read(), _subtype=subtype)
93
+ fp.close()
94
+ else:
95
+ fp = open(path, 'rb')
96
+ msg = MIMEBase(maintype, subtype)
97
+ msg.set_payload(fp.read())
98
+ fp.close()
99
+ # Encode the payload using Base64
100
+ encoders.encode_base64(msg)
101
+
102
+ # Set the filename parameter
103
+ msg.add_header('Content-Disposition', 'attachment',
104
+ filename=os.path.basename(path))
105
+
106
+ outer.attach(msg)
107
+
108
+ if options.output is "-":
109
+ ofile = sys.stdout
110
+ else:
111
+ ofile = file(options.output, "wb")
112
+
113
+ if options.base64:
114
+ output = b64encode(outer.as_string())
115
+ else:
116
+ output = outer.as_string()
117
+
118
+ if options.compress:
119
+ gfile = gzip.GzipFile(fileobj=ofile, filename=options.output)
120
+ gfile.write(output)
121
+ gfile.close()
122
+ else:
123
+ ofile.write(output)
124
+
125
+ ofile.close()
126
+
127
+ if __name__ == '__main__':
128
+ main()
data/lib/connection.rb CHANGED
@@ -17,8 +17,6 @@
17
17
 
18
18
  require 'rubygems'
19
19
  require 'fog'
20
- require 'yaml_parse.rb'
21
- include YamlParse
22
20
 
23
21
  #
24
22
  # Connection module
@@ -29,19 +27,19 @@ class SSLErrorMgt
29
27
  def initialize()
30
28
  @iRetry=0
31
29
  end
32
-
30
+
33
31
  def ErrorDetected(message,backtrace)
34
- if message.match('SSLv2/v3 read server hello A: unknown protocol')
32
+ if message.match('SSLv2/v3 read server hello A: unknown protocol')
35
33
  if @iRetry <5
36
34
  sleep(2)
37
35
  @iRetry+=1
38
36
  print "%s/5 try...\r" % @iRetry if $FORJ_LOGGER.level == 0
39
37
  return false
40
- else
38
+ else
41
39
  Logging.error('Too many retry. %s' % message)
42
40
  return true
43
41
  end
44
- else
42
+ else
45
43
  Logging.error("%s\n%s" % [message,backtrace.join("\n")])
46
44
  return true
47
45
  end
@@ -58,7 +56,7 @@ class ForjConnection
58
56
  def initialize(oConfig, bAutoConnect = true)
59
57
 
60
58
  Logging.fatal(1, 'Internal Error: Missing global $HPC_ACCOUNTS') if not $HPC_ACCOUNTS
61
-
59
+
62
60
  @oConfig = oConfig
63
61
  @sAccountName = @oConfig.get(:account_name)
64
62
  @provider='HP' # TODO: Support multiple provider. (Generic Provider object required)
@@ -97,7 +95,7 @@ class ForjConnection
97
95
  Logging.fatal(1, 'Compute: Unable to connect.', e)
98
96
  end
99
97
  end
100
-
98
+
101
99
  def network_connect
102
100
  # Trying to get Network object
103
101
  oSSLError=SSLErrorMgt.new # Retry object