pupistry 1.1.0 → 1.2.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: 8e3280a3e4dd9385278ae57d3ce8ac72ada37c0f
4
- data.tar.gz: 1625107171f0d871a16b35008fac3c5e4ba3db63
3
+ metadata.gz: 19803e351862b0c1f835d5a9091f94cd980adb1e
4
+ data.tar.gz: bd052ce0fe5a40568c75fa53ab157653f70afaa8
5
5
  SHA512:
6
- metadata.gz: 388aeb48985189832a1acd9f3e469cf07ec3a3eb784dee51fea8be3fae325dac439802727d8e7efcf124304e035ed9b53450051c0a2df3cdb4e35b7db5378b60
7
- data.tar.gz: c8c90250e40b22b82c9192a96dc3f1d572d84b6b4f01c7303be889ffaadee86ea266fa76c800f521338696ad7537875c83c6ab49a8a75a196e2c6db9d6de455d
6
+ metadata.gz: 4ca14cd1082df16d9b2ade7d5e6d839abbd681195d8fe118ef5fe601540900ef067fabd7582dd436fc951031a4e1674debc10299c7e751c42caddb593a112fb4
7
+ data.tar.gz: b25c20084c6243a78eefcdd5163db87aa47ecc8a5116405177a39d68d5d14001005e8a496b810c05e068af621360329f944f88d3d2df26e08746308c4693ebe2
data/README.md CHANGED
@@ -376,13 +376,44 @@ The bootstrap script goal is to get you from stock OS to running Pupistry and
376
376
  doing your first Puppet run. After that - it's up to you and your Puppet
377
377
  skills to make your node actually do something useful. :-)
378
378
 
379
+
380
+ ## 5. (optional) Baking an image with Packer
381
+
379
382
  Note that the node initialisation process is still susceptable to weaknesses
380
383
  such as a bug in a new version of Puppet or Pupistry, or changes to the OS
381
384
  packages. If this is a concern/issue for you and you want complete reliability,
382
385
  then use the user data to build a host pre-loaded with Puppet and Pupistry and
383
- then create an image of it using a tool like Packer. Doing this, you can make
384
- it possible to build all the way to Puppet execution with no dependencies on any
385
- third parties other than your VM provider and AWS S3.
386
+ then create an image of it using a tool like [Packer](www.packer.io). Doing
387
+ this, you can make it possible to build all the way to Puppet execution with no
388
+ dependencies on any third parties other than your VM provider and AWS S3.
389
+
390
+ Pupistry includes support for generating some Packer examples that you can
391
+ either use as-is or built upon to meet your own needs. You can list all the
392
+ available Packer templates with:
393
+
394
+ pupistry packer
395
+
396
+ You can select a template and generate a Packer file by specifying the template
397
+ and the output file on the command line:
398
+
399
+ pupistry packer --template aws_amazon-any --file packer.json
400
+
401
+ Once the file has been generated, you can build your packer environment with
402
+ the `packer build` command. Note that some templates will require additional
403
+ variables to be passed to them at run time, for example the AWS template
404
+ requires a VPC ID and subnet ID specific to your account.
405
+
406
+ packer build \
407
+ -var 'aws_vpc_id=vpc-example' \
408
+ -var 'aws_subnet_id=subnet-example' \
409
+ output.json
410
+
411
+ By default any Packer machines are built with the hostname of "packer" which
412
+ allows you to specifically target them with your manifests. If you don't do any
413
+ targetting, the default manifests will be applied.
414
+
415
+ Templates tend to have other customisable variables, check the available
416
+ options and their defaults with `packer inspect output.json`.
386
417
 
387
418
 
388
419
  # Tutorials
data/exe/pupistry CHANGED
@@ -215,6 +215,44 @@ class CLI < Thor
215
215
  end
216
216
  end
217
217
 
218
+ desc 'packer', 'Generate a packer template for a particular provider with OS bootstrap script included'
219
+ method_option :template, type: :string, desc: 'The template you want to generate'
220
+ method_option :file, type: :string, desc: 'File to write the generated packer template into'
221
+ def packer
222
+ # Thor seems to force class options to be defined repeatedly? :-/
223
+ if options[:verbose]
224
+ $logger.level = Logger::DEBUG
225
+ else
226
+ $logger.level = Logger::INFO
227
+ end
228
+
229
+ if options[:config]
230
+ Pupistry::Config.load(options[:config])
231
+ else
232
+ Pupistry::Config.find_and_load
233
+ end
234
+
235
+ if options[:template]
236
+ $logger.info "Generating packer template #{options[:template]}"
237
+
238
+ templates = Pupistry::Packer.new
239
+ templates.build options[:template]
240
+
241
+ if options[:file]
242
+ templates.output_file options[:file]
243
+ else
244
+ templates.output_plain
245
+ end
246
+ else
247
+ templates = Pupistry::Packer.new
248
+ templates.list
249
+
250
+ puts '--'
251
+ puts 'Tip: Run `pupistry packer --template example` to generate a specific template'
252
+ end
253
+ end
254
+
255
+
218
256
  ## Other Commands
219
257
 
220
258
  desc 'setup', 'Write a template configuration file'
@@ -82,6 +82,12 @@ module Pupistry
82
82
  end
83
83
  end
84
84
 
85
+ def output_array
86
+ # Return the output as an array of lines. Useful by other internal
87
+ # methods such as Packer templates.
88
+ @contents.split(/\n/)
89
+ end
90
+
85
91
  def output_plain
86
92
  # Do nothing clever, just output the template data.
87
93
  puts '-- Bootstrap Start --'
@@ -0,0 +1,116 @@
1
+ # rubocop:disable Style/Documentation, Style/GlobalVars
2
+ require 'rubygems'
3
+ require 'erubis'
4
+
5
+ module Pupistry
6
+ # Pupistry::Packer
7
+
8
+ class Packer
9
+ attr_accessor :template_dir
10
+ attr_accessor :contents
11
+
12
+ def initialize
13
+ # We need to find where the templates are located - either it should be
14
+ # in the current working directory, or if we are an installed gem, we
15
+ # can try the gem's installed path.
16
+
17
+ if Dir.exist?('resources/packer/')
18
+ # Use local PWD version first if possible
19
+ @template_dir = Dir.pwd
20
+ else
21
+ # Check for GEM installed location
22
+ begin
23
+ @template_dir = Gem::Specification.find_by_name('pupistry').gem_dir
24
+ rescue Gem::LoadError
25
+ $logger.error "Unable to find packer templates directory, doesn't appear we are running from project dir nor as a Gem"
26
+ return false
27
+ end
28
+ end
29
+
30
+ @template_dir = @template_dir.chomp('/') + '/resources/packer/'
31
+
32
+ if Dir.exist?(@template_dir)
33
+ $logger.debug "Using directory #{@template_dir} for packer templates"
34
+ else
35
+ $logger.error "Unable to find packer templates dir at #{@template_dir}, unable to proceed."
36
+ return false
37
+ end
38
+ end
39
+
40
+ def list
41
+ # Simply glob the templates directory and list their names.
42
+ $logger.debug 'Finding all available templates'
43
+
44
+ Dir.glob("#{@template_dir}/*.erb").each do |file|
45
+ puts "- #{File.basename(file, '.json.erb')}"
46
+ end
47
+ end
48
+
49
+ def build(template)
50
+ # Build a template with the configured parameters already to go and save
51
+ # into the object, so it can be outputted in the desired format.
52
+
53
+ $logger.debug "Generating a packer template using #{template}"
54
+
55
+ unless File.exist?("#{@template_dir}/#{template}.json.erb")
56
+ $logger.error 'The requested template does not exist, unable to build'
57
+ return 0
58
+ end
59
+
60
+ # Extract the OS bootstrap name from the template filename, we can then
61
+ # generate the bootstrap commands to be inserted inline into the packer
62
+ # configuration.
63
+
64
+ matches = template.match(/^\S*_(\S*)$/)
65
+
66
+ if matches[1]
67
+ $logger.debug "Fetching bootstrap data for #{matches[1]}..."
68
+ else
69
+ $logger.error 'Unable to parse the packer filename properly'
70
+ return 0
71
+ end
72
+
73
+ bootstrap = Pupistry::Bootstrap.new
74
+ unless bootstrap.build matches[1]
75
+ $logger.error 'An unexpected error occured when building the bootstrap data to go inside Packer'
76
+ end
77
+
78
+ # Pass the values we care about to the template
79
+ template_values = {
80
+ bootstrap_commands: bootstrap.output_array
81
+ }
82
+
83
+ # Generate template using ERB
84
+ begin
85
+ @contents = Erubis::Eruby.new(File.read("#{@template_dir}/#{template}.json.erb")).result(template_values)
86
+ rescue StandardError => e
87
+ $logger.error 'An unexpected error occured when trying to generate the packer template'
88
+ raise e
89
+ end
90
+ end
91
+
92
+ def output_plain
93
+ # Do nothing clever, just output the template data.
94
+ puts '-- Packer Start --'
95
+ puts @contents
96
+ puts '-- Packer End --'
97
+ puts 'Tip: add --file output.json to write out the packer file directly and then run with `packer build output.json`'
98
+ end
99
+
100
+ def output_file(filename)
101
+ # Write the template to the specified file
102
+ begin
103
+ File.open(filename, 'w') do |f|
104
+ f.puts @contents
105
+ end
106
+ rescue StandardError => e
107
+ $logger.error "An unexpected erorr occured when attempting to write the template to #{filename}"
108
+ raise e
109
+ else
110
+ $logger.info "Wrote template into file #{filename} successfully."
111
+ end
112
+ end
113
+ end
114
+ end
115
+
116
+ # vim:shiftwidth=2:tabstop=2:softtabstop=2:expandtab:smartindent
@@ -1,3 +1,3 @@
1
1
  module Pupistry
2
- VERSION = '1.1.0'
2
+ VERSION = '1.2.0'
3
3
  end
data/lib/pupistry.rb CHANGED
@@ -4,6 +4,7 @@ require 'pupistry/artifact'
4
4
  require 'pupistry/bootstrap'
5
5
  require 'pupistry/config'
6
6
  require 'pupistry/gpg'
7
+ require 'pupistry/packer'
7
8
  require 'pupistry/storage_aws'
8
9
 
9
10
  # vim:shiftwidth=2:tabstop=2:softtabstop=2:expandtab:smartindent
@@ -12,6 +12,8 @@
12
12
  # * We can't rely on Bash, since it's not available in FreeBSD by default.
13
13
  #
14
14
 
15
+ setenv PATH /sbin:/bin:/usr/sbin:/usr/bin:/usr/local/sbin:/usr/local/bin
16
+
15
17
  env ASSUME_ALWAYS_YES=YES pkg bootstrap
16
18
  env ASSUME_ALWAYS_YES=YES pkg upgrade --yes
17
19
  env ASSUME_ALWAYS_YES=YES pkg install --yes ruby devel/ruby-gems puppet gnupg
@@ -37,5 +39,5 @@ agent:
37
39
  EOF
38
40
  chmod 700 /usr/local/etc/pupistry
39
41
  chmod 700 /usr/local/etc/puppetlabs/code/environments
40
- pupistry apply --verbose
42
+ /usr/local/bin/pupistry apply --verbose
41
43
 
@@ -0,0 +1,49 @@
1
+ # Packer Templates
2
+
3
+ This directory contains templates for use with Packer (https://www.packer.io/).
4
+
5
+ It can be very useful to use Packer with Pupistry, since it allows you to
6
+ create your own image with Puppet, Pupistry and updates already loaded which
7
+ is very useful when doing autoscaling and you need fast, consistent startup
8
+ times.
9
+
10
+ The packer templates provided will build an image which has Pupistry installed
11
+ and will apply any manifests that match hostname of "packer". This should give
12
+ you a good general purpose image, but if you want to autoscale a particular app
13
+ you may wish to build packer images using specific hostnames to match your
14
+ Puppet manifests
15
+
16
+ Additional packer templates for major platforms are always welcome. Please
17
+ submit a pull request for review and if acceptable, will be merged.
18
+
19
+
20
+ # Usage
21
+
22
+ Refer to the main application README.md file for usage information.
23
+
24
+
25
+ # Development Notes
26
+
27
+ The filenames of the templates must be in the format of
28
+ PLATFORM_OPERATINGSYSTEM.json.erb, this is intentional since OPERATINGSYSTEM
29
+ then matches one of the OSes in the bootstrap directory and we can
30
+ automatically populate the inline shell commands.
31
+
32
+ When debugging broken packer template runs, add -debug to the build command
33
+ to have control over stepping through the build process. This will give you
34
+ the ability to log into the instance before it gets terminated to do any
35
+ debugging on the system if needed.
36
+
37
+
38
+ # Examples
39
+
40
+ See the "aws_amazon-any.json.erb" template for an example on how the templates
41
+ should be written for AWS.
42
+
43
+
44
+ # Life Span
45
+
46
+ Any distribution that is EOL and no longer supported by either the distribution
47
+ or by Puppetlabs will be subject to removal to keep the bootstrap selection
48
+ modern and clean. Pull requests to clean up cruft are accepted.
49
+
@@ -0,0 +1,38 @@
1
+ {
2
+ "variables": {
3
+ "aws_access_key": "",
4
+ "aws_secret_key": "",
5
+ "aws_ami": "ami-fd9cecc7",
6
+ "aws_region": "ap-southeast-2",
7
+ "aws_ami_name": "pupistry aws_amazon-any {{isotime \"2006-01-02\"}}",
8
+ "aws_vpc_id": null,
9
+ "aws_subnet_id": null,
10
+ "hostname": "packer"
11
+ },
12
+ "builders": [{
13
+ "type": "amazon-ebs",
14
+ "access_key": "{{user `aws_access_key`}}",
15
+ "secret_key": "{{user `aws_secret_key`}}",
16
+ "region": "{{user `aws_region`}}",
17
+ "source_ami": "{{user `aws_ami`}}",
18
+ "instance_type": "t2.micro",
19
+ "ssh_username": "ec2-user",
20
+ "vpc_id": "{{user `aws_vpc_id`}}",
21
+ "subnet_id": "{{user `aws_subnet_id`}}",
22
+ "ami_name": "{{user `aws_ami_name`}}"
23
+ }],
24
+ "provisioners": [{
25
+ "type": "shell",
26
+ "inline": ["sudo hostname {{user `hostname`}}"]
27
+ },
28
+ {
29
+ "type": "shell",
30
+ "inline_shebang": "/bin/bash -x",
31
+ "execute_command": "chmod +x {{ .Path }}; {{ .Vars }} sudo '{{ .Path }}'",
32
+ "inline": <%= bootstrap_commands %>
33
+ },
34
+ {
35
+ "type": "shell",
36
+ "inline": ["sudo rm -rf /tmp/*"]
37
+ }]
38
+ }
@@ -0,0 +1,39 @@
1
+ {
2
+ "variables": {
3
+ "aws_access_key": "",
4
+ "aws_secret_key": "",
5
+ "aws_ami": "ami-193f5123",
6
+ "aws_region": "ap-southeast-2",
7
+ "aws_ami_name": "pupistry aws_freebsd-10 {{isotime \"2006-01-02\"}}",
8
+ "aws_vpc_id": null,
9
+ "aws_subnet_id": null,
10
+ "hostname": "packer"
11
+ },
12
+ "builders": [{
13
+ "type": "amazon-ebs",
14
+ "access_key": "{{user `aws_access_key`}}",
15
+ "secret_key": "{{user `aws_secret_key`}}",
16
+ "region": "{{user `aws_region`}}",
17
+ "source_ami": "{{user `aws_ami`}}",
18
+ "instance_type": "t2.micro",
19
+ "ssh_username": "ec2-user",
20
+ "ssh_timeout": "15m",
21
+ "vpc_id": "{{user `aws_vpc_id`}}",
22
+ "subnet_id": "{{user `aws_subnet_id`}}",
23
+ "ami_name": "{{user `aws_ami_name`}}"
24
+ }],
25
+ "provisioners": [{
26
+ "type": "shell",
27
+ "inline": ["su -m root -c 'hostname {{user `hostname`}}'"]
28
+ },
29
+ {
30
+ "type": "shell",
31
+ "inline_shebang": "/bin/tcsh",
32
+ "execute_command": "chmod +x {{ .Path }}; {{ .Vars }} su -m root -c '/bin/tcsh {{ .Path }}'",
33
+ "inline": <%= bootstrap_commands %>
34
+ },
35
+ {
36
+ "type": "shell",
37
+ "inline": ["su -m root -c 'rm -rf /tmp/*'"]
38
+ }]
39
+ }
@@ -0,0 +1,38 @@
1
+ {
2
+ "variables": {
3
+ "aws_access_key": "",
4
+ "aws_secret_key": "",
5
+ "aws_ami": "ami-19c8b123",
6
+ "aws_region": "ap-southeast-2",
7
+ "aws_ami_name": "pupistry aws_ubuntu-14.04 {{isotime \"2006-01-02\"}}",
8
+ "aws_vpc_id": null,
9
+ "aws_subnet_id": null,
10
+ "hostname": "packer"
11
+ },
12
+ "builders": [{
13
+ "type": "amazon-ebs",
14
+ "access_key": "{{user `aws_access_key`}}",
15
+ "secret_key": "{{user `aws_secret_key`}}",
16
+ "region": "{{user `aws_region`}}",
17
+ "source_ami": "{{user `aws_ami`}}",
18
+ "instance_type": "t2.micro",
19
+ "ssh_username": "ubuntu",
20
+ "vpc_id": "{{user `aws_vpc_id`}}",
21
+ "subnet_id": "{{user `aws_subnet_id`}}",
22
+ "ami_name": "{{user `aws_ami_name`}}"
23
+ }],
24
+ "provisioners": [{
25
+ "type": "shell",
26
+ "inline": ["sudo hostname {{user `hostname`}}"]
27
+ },
28
+ {
29
+ "type": "shell",
30
+ "inline_shebang": "/bin/bash -x",
31
+ "execute_command": "chmod +x {{ .Path }}; {{ .Vars }} sudo '{{ .Path }}'",
32
+ "inline": <%= bootstrap_commands %>
33
+ },
34
+ {
35
+ "type": "shell",
36
+ "inline": ["sudo rm -rf /tmp/*"]
37
+ }]
38
+ }
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: pupistry
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.1.0
4
+ version: 1.2.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Jethro Carr
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2015-05-31 00:00:00.000000000 Z
11
+ date: 2015-06-06 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
@@ -177,6 +177,7 @@ files:
177
177
  - lib/pupistry/bootstrap.rb
178
178
  - lib/pupistry/config.rb
179
179
  - lib/pupistry/gpg.rb
180
+ - lib/pupistry/packer.rb
180
181
  - lib/pupistry/storage_aws.rb
181
182
  - lib/pupistry/version.rb
182
183
  - lib/pupistry.rb
@@ -190,8 +191,10 @@ files:
190
191
  - resources/bootstrap/fedora-any.erb
191
192
  - resources/bootstrap/freebsd-10.erb
192
193
  - resources/bootstrap/ubuntu-14.04.erb
193
- - resources/packer/amazon_linux.json
194
- - resources/packer/test_user_data.txt
194
+ - resources/packer/aws_amazon-any.json.erb
195
+ - resources/packer/aws_freebsd-10.json.erb
196
+ - resources/packer/aws_ubuntu-14.04.json.erb
197
+ - resources/packer/PACKER_NOTES.md
195
198
  - README.md
196
199
  - settings.example.yaml
197
200
  homepage: https://github.com/jethrocarr/pupistry
@@ -1,17 +0,0 @@
1
- {
2
- "variables": {
3
- "aws_access_key": "",
4
- "aws_secret_key": ""
5
- },
6
- "builders": [{
7
- "type": "amazon-ebs",
8
- "access_key": "{{user `aws_access_key`}}",
9
- "secret_key": "{{user `aws_secret_key`}}",
10
- "region": "ap-southeast-2",
11
- "source_ami": "ami-fd9cecc7",
12
- "instance_type": "m3.medium",
13
- "ssh_username": "ec2-user",
14
- "ami_name": "pupistry default {{timestamp}}",
15
- "user_data": "test_user_data.txt"
16
- }]
17
- }
@@ -1,33 +0,0 @@
1
- -- Bootstrap Start --
2
- IyEvYmluL2Jhc2ggLXgKIyBUaGlzIGJvb3RzdHJhcCBpcyBzcGVjaWZjaWFs
3
- bHkgZm9yIEFtYXpvbidzIExpbnV4IEFNSXMsIGlmIHlvdSBhcmUgdXNpbmcK
4
- IyBvdGhlciBkaXN0cmlidXRpb25zIGxpa2UgVWJ1bnR1IG9yIENlbnRPUyBv
5
- biBBV1MsIHVzZSB0aG9zZSBib290c3RyYXAKIyB0ZW1wbGF0ZXMuCiMKIyBB
6
- bWF6b24gTGludXggaXMgYmFzZWQgb24gUkhFTCwgYnV0IGhhcyBhIGxvdCBt
7
- b3JlIHZhcmlhdGlvbnMgdGhhdCBvdGhlcgojIGNsb25lcyBsaWtlIENlbnRP
8
- Uywgc3VjaCBhcyBzaGlwcGluZyB3aXRoIG11bHRpcGxlIHZlcnNpb25zIG9m
9
- IFB1cHBldAojIGFuZCBSdWJ5IC0gd2hpY2ggaXMgdXNlZnVsLCBidXQgY2Fu
10
- IGFsc28gbWFrZSBsaWZlLi4uLiBpbnRlcmVzdGluZy4KKApleGVjIDE+ID4o
11
- bG9nZ2VyIC1zIC10IHVzZXItZGF0YSkgMj4mMQoKZXhwb3J0IFBBVEg9JFBB
12
- VEg6L3Vzci9sb2NhbC9iaW4KCnl1bSB1cGRhdGUgLS1hc3N1bWV5ZXMKeXVt
13
- IGluc3RhbGwgLS1hc3N1bWV5ZXMgcHVwcGV0MyBydWJ5LWRldmVsIHJ1Ynln
14
- ZW1zIGdjYyB6bGliLWRldmVsIGxpYnhtbDItZGV2ZWwgcGF0Y2ggZ251cGcy
15
- CgojIE5vdCBzdXJlIHdoeSB0aGlzIGRvZXNuJ3QgZ2V0IHB1bGxlZCBkb3du
16
- IHByb3Blcmx5LCBtYXliZSBpdCdzIGNvcmUgYW5kCiMgQW1hem9uIGRpZG4n
17
- dCBwYWNrYWdlIGl0IHByb3Blcmx5PyBOZWVkIGl0IGZvciBUaG9yIHdoaWNo
18
- IGlzIHVzZWQgYnkgUHVwaXN0cnkKZ2VtIGluc3RhbGwgaW8tY29uc29sZQoK
19
- Z2VtIGluc3RhbGwgcHVwaXN0cnkKbWtkaXIgLXAgL2V0Yy9wdXBpc3RyeQpt
20
- a2RpciAtcCAvZXRjL3B1cHBldGxhYnMvY29kZS9lbnZpcm9ubWVudHMKY2F0
21
- ID4gL2V0Yy9wdXBpc3RyeS9zZXR0aW5ncy55YW1sIDw8ICJFT0YiCmdlbmVy
22
- YWw6CiAgYXBwX2NhY2hlOiB+Ly5wdXBpc3RyeS9jYWNoZQogIHMzX2J1Y2tl
23
- dDogcHVwaXN0cnktcmVzb3VyY2VzCiAgczNfcHJlZml4OiAKICBncGdfZGlz
24
- YWJsZTogZmFsc2UKICBncGdfc2lnbmluZ19rZXk6IEE4MEFDQTZGCmFnZW50
25
- OgogIHB1cHBldGNvZGU6IC9ldGMvcHVwcGV0bGFicy9jb2RlL2Vudmlyb25t
26
- ZW50cwogIGFjY2Vzc19rZXlfaWQ6IEFLSUFKMlhKQ01TNFJBUDNCVFpBCiAg
27
- c2VjcmV0X2FjY2Vzc19rZXk6IHdoQWlFaCtZV1hzaUw4Y0NONitLSFovT1Zs
28
- M1VCK3ZZb0FHZEd4eDkKICByZWdpb246IGFwLXNvdXRoZWFzdC0yCiAgcHJv
29
- eHlfdXJpOiAKICBkYWVtb25fZnJlcXVlbmN5OiA2MAogIGRhZW1vbl9taW5p
30
- bWFsOiB0cnVlCkVPRgpjaG1vZCA3MDAgL2V0Yy9wdXBpc3RyeS9zZXR0aW5n
31
- cy55YW1sCmNobW9kIDcwMCAvZXRjL3B1cHBldGxhYnMvY29kZS9lbnZpcm9u
32
- bWVudHMKcHVwaXN0cnkgYXBwbHkgLS12ZXJib3NlCgopCg==
33
- -- Bootstrap End --