forj 0.0.48 → 1.0.0

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.
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