biosphere 0.0.11 → 0.0.12

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: 0459a0449bf2038aed5733a7c5797a16d05565c7
4
- data.tar.gz: 0ba58ee53dd1cced9c435ce00daa960997bb217a
3
+ metadata.gz: 347ecc8394215627d48fae451787d293607fdbad
4
+ data.tar.gz: 8f8e03cc288495d430e0477fa74b5eeb12a933fe
5
5
  SHA512:
6
- metadata.gz: 4d063d3d43599ac7b9ff2dd63541aeefa3e70362478cba3e12db3c08086aa880a63892fde8ddf1f450c913a446e7c94cb17818ed59d87d645e9e1e5010c80730
7
- data.tar.gz: fa7f3248955060ce0ac67539c0d5ac99b376f9bd8961936a167cee9c1b87142ff09686fbff0f85f7b23ce740d309f8beb223eb949cd8a6e7810b02362782afbb
6
+ metadata.gz: 8238bcfcc308dde2a1ee51d88cd6eed69f092f22cef45813b275219358811fd88c12e62c2063ddea6661c6a16c03085bb6b637a3765b896920ed4dbb37700f8c
7
+ data.tar.gz: a3d298603618dcd1163b7e46e8d9578873d471c0378b858be6afb343a8763f9db160e7ecd692e4cda45a703c9a7d0819ba3637d55bcb4d17f7ee15f86d99a58c
@@ -6,13 +6,21 @@ require 'ostruct'
6
6
  require 'pp'
7
7
  require "awesome_print"
8
8
  require 'colorize'
9
+ require 'biosphere/s3.rb'
9
10
 
10
11
  class BiosphereOpts
11
12
 
13
+ def self.normalize_path(path)
14
+ if path[-1] != '/'
15
+ path += '/'
16
+ end
17
+ return path
18
+ end
19
+
12
20
  def self.parse(args)
13
21
 
14
22
  options = OpenStruct.new
15
- options.build = "build"
23
+ options.build_dir = "build"
16
24
  options.src = "./"
17
25
  options.version = ::Biosphere::Version
18
26
 
@@ -23,8 +31,11 @@ class BiosphereOpts
23
31
 
24
32
  opts.separator ""
25
33
  opts.separator "Commands:"
34
+ opts.separator "\tbuild\tWrite tf files as json into build directory"
26
35
  opts.separator "\tplan\tRun the planning phase"
27
- opts.separator "\tjson\tWrite tf files as json into build directory"
36
+ opts.separator "\tcommit\tCommit changes and update the infrastructure"
37
+ opts.separator "\tlock\tAcquire lock for remote state"
38
+ opts.separator "\tunlock\tRelease lock for remote state"
28
39
  opts.separator "\taction [action]\tCall an action defined in the application .rb files"
29
40
  opts.separator ""
30
41
 
@@ -34,12 +45,11 @@ class BiosphereOpts
34
45
  end
35
46
 
36
47
  opts.on("--src PATH", "Directory where the application .rb files are") do |path|
37
- options.src = path
48
+ options.src = normalize_path(path)
38
49
  end
39
50
 
40
-
41
- opts.on("--build PATH", "Directory where to build json files") do |path|
42
- options.build = path
51
+ opts.on("--build-dir PATH", "Directory where to build json files") do |path|
52
+ options.build_dir = normalize_path(path)
43
53
  end
44
54
 
45
55
  end
@@ -62,7 +72,7 @@ if ARGV.length == 0
62
72
  end
63
73
 
64
74
  if !File.directory?(options.src)
65
- STDERR.puts "Directory #{options.build} is not a directory or it doesn't exists."
75
+ STDERR.puts "Directory #{options.build_dir} is not a directory or it doesn't exists."
66
76
  exit -1
67
77
  end
68
78
 
@@ -76,40 +86,47 @@ if options.src
76
86
  STDERR.puts "No files found. Are you in the right directory where your biosphere .rb files are?"
77
87
  exit -1
78
88
  end
79
- end
80
89
 
81
- if options.build
82
- if !File.directory?(options.build)
83
- STDERR.puts "Creating build directory #{options.build} because it was missing"
84
- Dir.mkdir(options.build)
90
+ if suite.node[:settings][:s3_bucket].nil? || suite.node[:settings][:s3_bucket].empty? || suite.node[:settings][:cluster_name].nil? || suite.node[:settings][:cluster_name].empty?
91
+ puts "\nNo S3 bucket or cluster name defined in configuration, can't continue"
92
+ exit 1
85
93
  end
94
+ s3 = S3.new(suite.node[:settings][:s3_bucket], suite.node[:settings][:cluster_name])
86
95
  end
87
96
 
97
+ if options.build_dir
98
+ if !File.directory?(options.build_dir)
99
+ STDERR.puts "Creating build directory #{options.build_dir} because it was missing"
100
+ Dir.mkdir(options.build_dir)
101
+ end
102
+ end
88
103
 
89
- if ARGV[0] == "json" && options.src
104
+ if ARGV[0] == "build" && options.src
90
105
  suite.evaluate_resources()
91
106
 
92
- if !File.directory?(options.build)
93
- STDERR.puts "Directory #{options.build} is not a directory or it doesn't exists."
107
+ if !File.directory?(options.build_dir)
108
+ STDERR.puts "Directory #{options.build_dir} is not a directory or it doesn't exists."
94
109
  exit -1
95
110
  end
96
111
 
97
112
  count = 0
98
- suite.write_json_to(options.build) do |file_name, destination, str, proxy|
113
+ suite.write_json_to(options.build_dir) do |file_name, destination, str, proxy|
99
114
  puts "Wrote #{str.length} bytes from #{file_name} to #{destination} (#{proxy.export["resource"].length} resources)"
100
115
  count = count + 1
101
116
  end
102
117
 
103
- puts "Wrote #{count} files into #{options.build}"
118
+ puts "Wrote #{count} files into #{options.build_dir}"
104
119
  suite.save_node()
105
120
 
106
121
  elsif ARGV[0] == "plan" && options.src
107
122
  suite.evaluate_plans()
108
123
  ap suite.node, :indent=>-4
124
+
109
125
  elsif ARGV[0] == "action" && options.src
126
+ s3.retrieve("#{options.build_dir}terraform.tfstate")
127
+ s3.retrieve("#{options.build_dir}state.node")
110
128
  context = Biosphere::ActionContext.new()
111
-
112
- context.build_directory = options.build
129
+ context.build_directory = options.build_dir
113
130
 
114
131
  if suite.call_action(ARGV[1], context)
115
132
  STDERR.puts "Executing action #{ARGV[1]}"
@@ -118,6 +135,37 @@ elsif ARGV[0] == "action" && options.src
118
135
  end
119
136
 
120
137
  suite.save_node()
138
+
139
+ elsif ARGV[0] == "commit" && options.src
140
+ s3.set_lock()
141
+ s3.retrieve("#{options.build_dir}terraform.tfstate")
142
+ s3.retrieve("#{options.build_dir}state.node")
143
+ tf_plan = %x( terraform plan -state=#{options.build_dir}terraform.tfstate #{options.build_dir} )
144
+ puts "\n" + tf_plan
145
+ answer = ""
146
+ while answer.empty? || (answer != "y" && answer != "n")
147
+ print "\nDoes the plan look reasonable? (Answering yes will apply the changes) y/n: "
148
+ answer = STDIN.gets.chomp
149
+ end
150
+
151
+ if answer == "n"
152
+ puts "\nOk, will not proceed with commit"
153
+ elsif answer == "y"
154
+ puts "\nApplying the changes (this may take several minutes)"
155
+ tf_apply = %x( terraform apply -state=#{options.build_dir}terraform.tfstate #{options.build_dir})
156
+ puts "\n" + tf_apply
157
+ s3.save("#{options.build_dir}terraform.tfstate")
158
+ s3.save("#{options.src}state.node")
159
+ end
160
+
161
+ s3.release_lock()
162
+
163
+ elsif ARGV[0] == "lock"
164
+ s3.set_lock()
165
+
166
+ elsif ARGV[0] == "unlock"
167
+ s3.release_lock()
168
+
121
169
  else
122
170
  STDERR.puts "\nERROR: Unknown command #{ARGV[0]}. Maybe you wanted to do: \"biosphere action #{ARGV[0]}\"?"
123
171
  exit -1
@@ -66,6 +66,7 @@ class Biosphere
66
66
  end
67
67
 
68
68
  ns_prefix = client.build_namespace_prefix(resource[:metadata][:namespace])
69
+ ns_prefix = ns_prefix.empty? ? "namespaces/default/" : ns_prefix
69
70
  ret = client.rest_client[ns_prefix + resource_name].post(resource.to_h.to_json, { 'Content-Type' => 'application/json' }.merge(client.instance_variable_get("@headers")))
70
71
  return {
71
72
  action: :post,
@@ -0,0 +1,82 @@
1
+ require 'aws-sdk'
2
+
3
+ class S3
4
+ def initialize(bucket, main_key)
5
+ @client = Aws::S3::Client.new
6
+ @bucket_name = bucket
7
+ @main_key = main_key
8
+ end
9
+
10
+ def save(path_to_file)
11
+ puts "\nSaving #{path_to_file} to S3"
12
+ filename = path_to_file.split('/')[-1]
13
+ begin
14
+ File.open(path_to_file, 'rb') do |file|
15
+ @client.put_object({
16
+ :bucket => @bucket_name,
17
+ :key => "#{@main_key}/#{filename}",
18
+ :body => file
19
+ })
20
+ end
21
+ rescue
22
+ puts "\nError occurred while saving the remote state, can't continue"
23
+ puts "Error: #{$!}"
24
+ exit 1
25
+ end
26
+ end
27
+
28
+ def retrieve(path_to_file)
29
+ filename = path_to_file.split('/')[-1]
30
+ puts "\nFetching #{filename} from S3"
31
+ begin
32
+ resp = @client.get_object({
33
+ :bucket => @bucket_name,
34
+ :key => "#{@main_key}/#{filename}"
35
+ })
36
+ File.open(path_to_file, 'w') do |f|
37
+ f.puts(resp.body.read)
38
+ end
39
+ rescue Aws::S3::Errors::NoSuchKey
40
+ puts "\nCouldn't find remote file #{filename} from S3."
41
+ rescue
42
+ puts "\nError occurred while fetching the remote state, can't continue."
43
+ puts "Error: #{$!}"
44
+ exit 1
45
+ end
46
+ end
47
+
48
+ def set_lock()
49
+ begin
50
+ resp = @client.get_object({
51
+ :bucket => @bucket_name,
52
+ :key => "#{@main_key}/biosphere.lock"
53
+ })
54
+ puts "\nThe remote state is locked since #{resp.last_modified}\nCan't continue."
55
+ exit 1
56
+ rescue Aws::S3::Errors::NoSuchKey
57
+ puts "\nRemote state was not locked, adding the lockfile.\n"
58
+ @client.put_object({
59
+ :bucket => @bucket_name,
60
+ :key => "#{@main_key}/biosphere.lock"
61
+ })
62
+ rescue
63
+ puts "\There was an error while accessing the lock. Can't continue.'"
64
+ puts "Error: #{$!}"
65
+ exit 1
66
+ end
67
+ end
68
+
69
+ def release_lock()
70
+ begin
71
+ @client.delete_object({
72
+ :bucket => @bucket_name,
73
+ :key => "#{@main_key}/biosphere.lock"
74
+ })
75
+ rescue
76
+ puts "\nCouldn't release the lock!"
77
+ puts "Error: #{$!}"
78
+ exit 1
79
+ end
80
+ puts "\nLock released successfully"
81
+ end
82
+ end
@@ -1,3 +1,3 @@
1
1
  class Biosphere
2
- Version = "0.0.11"
2
+ Version = "0.0.12"
3
3
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: biosphere
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.11
4
+ version: 0.0.12
5
5
  platform: ruby
6
6
  authors:
7
7
  - Juho Mäkinen
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2016-11-09 00:00:00.000000000 Z
11
+ date: 2017-02-20 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rspec
@@ -94,6 +94,20 @@ dependencies:
94
94
  - - '='
95
95
  - !ruby/object:Gem::Version
96
96
  version: 0.8.1
97
+ - !ruby/object:Gem::Dependency
98
+ name: aws-sdk
99
+ requirement: !ruby/object:Gem::Requirement
100
+ requirements:
101
+ - - "~>"
102
+ - !ruby/object:Gem::Version
103
+ version: '2'
104
+ type: :runtime
105
+ prerelease: false
106
+ version_requirements: !ruby/object:Gem::Requirement
107
+ requirements:
108
+ - - "~>"
109
+ - !ruby/object:Gem::Version
110
+ version: '2'
97
111
  description: "Terraform's HCL lacks quite many programming features like iterators,
98
112
  true variables, advanced string manipulation, functions etc.\n\n This Ruby tool
99
113
  provides an easy-to-use DSL to define Terraform compatible .json files which can
@@ -111,6 +125,7 @@ files:
111
125
  - lib/biosphere/kube.rb
112
126
  - lib/biosphere/mixing/from_file.rb
113
127
  - lib/biosphere/node.rb
128
+ - lib/biosphere/s3.rb
114
129
  - lib/biosphere/suite.rb
115
130
  - lib/biosphere/terraformproxy.rb
116
131
  - lib/biosphere/version.rb