terrafying 0.0.1 → 1.1.4

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,126 +0,0 @@
1
- require 'terrafying/dynamodb'
2
- require 'terrafying/dynamodb/config'
3
-
4
- module Terrafying
5
- module DynamoDb
6
- class NamedLock
7
- def initialize(table_name, name)
8
- @table_name = table_name
9
- @name = name
10
- @client = Terrafying::DynamoDb.client
11
- end
12
-
13
- def status
14
- @client.ensure_table(table) do
15
- resp = @client.get_item({
16
- table_name: @table_name,
17
- key: {
18
- "name" => @name,
19
- },
20
- consistent_read: true,
21
- })
22
- if resp.item
23
- return {
24
- status: :locked,
25
- locked_at: resp.item["locked_at"],
26
- metadata: resp.item["metadata"]
27
- }
28
- else
29
- return {
30
- status: :unlocked
31
- }
32
- end
33
- end
34
- end
35
-
36
- def acquire
37
- @client.ensure_table(table) do
38
- begin
39
- lock_id = SecureRandom.uuid
40
- @client.update_item(acquire_request(lock_id))
41
- return lock_id
42
- rescue ::Aws::DynamoDB::Errors::ConditionalCheckFailedException
43
- raise "Unable to acquire lock: #{status.inspect}" # TODO
44
- end
45
- end
46
- end
47
-
48
- def steal
49
- @client.ensure_table(table) do
50
- begin
51
- lock_id = SecureRandom.uuid
52
- req = acquire_request(lock_id)
53
- req.delete(:condition_expression)
54
- @client.update_item(req)
55
- return lock_id
56
- rescue ::Aws::DynamoDB::Errors::ConditionalCheckFailedException
57
- raise "Unable to steal lock: #{status.inspect}" # TODO
58
- end
59
- end
60
- end
61
-
62
- def release(lock_id)
63
- @client.ensure_table(table) do
64
- begin
65
- @client.delete_item({
66
- table_name: @table_name,
67
- key: {
68
- "name" => @name,
69
- },
70
- return_values: "NONE",
71
- condition_expression: "lock_id = :lock_id",
72
- expression_attribute_values: {
73
- ":lock_id" => lock_id,
74
- },
75
- })
76
- nil
77
- rescue ::Aws::DynamoDB::Errors::ConditionalCheckFailedException
78
- raise "Unable to release lock: #{status.inspect}" # TODO
79
- end
80
- end
81
- end
82
-
83
- private
84
- def acquire_request(lock_id)
85
- {
86
- table_name: @table_name,
87
- key: {
88
- "name" => @name,
89
- },
90
- return_values: "NONE",
91
- update_expression: "SET lock_id = :lock_id, locked_at = :locked_at, metadata = :metadata",
92
- condition_expression: "attribute_not_exists(lock_id)",
93
- expression_attribute_values: {
94
- ":lock_id" => lock_id,
95
- ":locked_at" => Time.now.to_s,
96
- ":metadata" => {
97
- "owner" => "#{`git config user.name`.chomp} (#{`git config user.email`.chomp})",
98
- },
99
- },
100
- }
101
- end
102
-
103
- def table
104
- {
105
- table_name: @table_name,
106
- attribute_definitions: [
107
- {
108
- attribute_name: "name",
109
- attribute_type: "S",
110
- },
111
- ],
112
- key_schema: [
113
- {
114
- attribute_name: "name",
115
- key_type: "HASH",
116
- },
117
- ],
118
- provisioned_throughput: {
119
- read_capacity_units: 1,
120
- write_capacity_units: 1,
121
- }
122
- }
123
- end
124
- end
125
- end
126
- end
@@ -1,92 +0,0 @@
1
- require 'digest'
2
- require 'terrafying/dynamodb/config'
3
-
4
- module Terrafying
5
- module DynamoDb
6
- class StateStore
7
- def initialize(scope, opts = {})
8
- @scope = scope
9
- @client = Terrafying::DynamoDb.client
10
- @table_name = Terrafying::DynamoDb.config.state_table
11
- end
12
-
13
- def get
14
- @client.ensure_table(table) do
15
- resp = @client.query({
16
- table_name: @table_name,
17
- limit: 1,
18
- key_conditions: {
19
- "scope" => {
20
- attribute_value_list: [@scope],
21
- comparison_operator: "EQ",
22
- }
23
- },
24
- scan_index_forward: false,
25
- })
26
- case resp.items.count
27
- when 0 then return nil
28
- when 1 then return resp.items.first["state"]
29
- else raise 'More than one item found when retrieving state. This is a bug and should never happen.' if resp.items.count != 1
30
- end
31
- end
32
- end
33
-
34
- def put(state)
35
- @client.ensure_table(table) do
36
- sha256 = Digest::SHA256.hexdigest(state)
37
- json = JSON.parse(state)
38
- @client.update_item({
39
- table_name: @table_name,
40
- key: {
41
- "scope" => @scope,
42
- "serial" => json["serial"].to_i,
43
- },
44
- return_values: "NONE",
45
- update_expression: "SET sha256 = :sha256, #state = :state",
46
- condition_expression: "attribute_not_exists(serial) OR sha256 = :sha256",
47
- expression_attribute_names: {
48
- "#state" => "state",
49
- },
50
- expression_attribute_values: {
51
- ":sha256" => sha256,
52
- ":state" => state,
53
- }
54
- })
55
- end
56
- end
57
-
58
- def table
59
- {
60
- table_name: @table_name,
61
- attribute_definitions: [
62
- {
63
- attribute_name: "scope",
64
- attribute_type: "S",
65
- },
66
- {
67
- attribute_name: "serial",
68
- attribute_type: "N",
69
- }
70
- ],
71
- key_schema: [
72
- {
73
- attribute_name: "scope",
74
- key_type: "HASH",
75
- },
76
- {
77
- attribute_name: "serial",
78
- key_type: "RANGE",
79
- },
80
-
81
- ],
82
- provisioned_throughput: {
83
- read_capacity_units: 1,
84
- write_capacity_units: 1,
85
- }
86
- }
87
- end
88
- end
89
- end
90
- end
91
-
92
-
@@ -1,31 +0,0 @@
1
- require 'aws-sdk'
2
- require 'json'
3
- require 'securerandom'
4
-
5
- # oh rubby
6
- class ::Aws::DynamoDB::Client
7
- def ensure_table(table_spec, &block)
8
- retried = false
9
- begin
10
- yield block
11
- rescue ::Aws::DynamoDB::Errors::ResourceNotFoundException => e
12
- if not retried
13
- create_table(table_spec)
14
- retry
15
- else
16
- raise e
17
- end
18
- end
19
- end
20
- end
21
-
22
- module Terrafying
23
- module DynamoDb
24
- def self.client
25
- @@client ||= ::Aws::DynamoDB::Client.new({
26
- region: Terrafying::Context::REGION,
27
- #endpoint: 'http://localhost:8000',
28
- })
29
- end
30
- end
31
- end
@@ -1,166 +0,0 @@
1
- require 'json'
2
- require 'base64'
3
- require 'erb'
4
- require 'ostruct'
5
- require 'deep_merge'
6
- require 'terrafying/aws'
7
-
8
- module Terrafying
9
-
10
- class Ref
11
-
12
- def initialize(var)
13
- @var = var
14
- end
15
-
16
- def downcase
17
- Ref.new("lower(#{@var})")
18
- end
19
-
20
- def strip
21
- Ref.new("trimspace(#{@var})")
22
- end
23
-
24
- def to_s
25
- "${#{@var}}"
26
- end
27
-
28
- def to_str
29
- self.to_s
30
- end
31
-
32
- def <=>(other)
33
- self.to_s <=> other.to_s
34
- end
35
-
36
- def ==(other)
37
- self.to_s == other.to_s
38
- end
39
-
40
- end
41
-
42
- class Context
43
-
44
- REGION = ENV.fetch("AWS_REGION", "eu-west-1")
45
-
46
- PROVIDER_DEFAULTS = {
47
- aws: { region: REGION }
48
- }
49
-
50
- attr_reader :output
51
-
52
- def initialize
53
- @output = {
54
- "resource" => {}
55
- }
56
- @children = []
57
- end
58
-
59
- def aws
60
- @@aws ||= Terrafying::Aws::Ops.new REGION
61
- end
62
-
63
- def provider(name, spec)
64
- @output["provider"] ||= {}
65
- @output["provider"][name] = spec
66
- end
67
-
68
- def data(type, name, spec)
69
- @output["data"] ||= {}
70
- @output["data"][type.to_s] ||= {}
71
- @output["data"][type.to_s][name.to_s] = spec
72
- id_of(type, name)
73
- end
74
-
75
- def resource(type, name, attributes)
76
- @output["resource"][type.to_s] ||= {}
77
- @output["resource"][type.to_s][name.to_s] = attributes
78
- id_of(type, name)
79
- end
80
-
81
- def template(relative_path, params = {})
82
- dir = caller_locations[0].path
83
- filename = File.join(File.dirname(dir), relative_path)
84
- erb = ERB.new(IO.read(filename))
85
- erb.filename = filename
86
- erb.result(OpenStruct.new(params).instance_eval { binding })
87
- end
88
-
89
- def output_with_children
90
- @children.inject(@output) { |out, c| out.deep_merge(c.output_with_children) }
91
- end
92
-
93
- def id_of(type,name)
94
- output_of(type, name, "id")
95
- end
96
-
97
- def output_of(type, name, value)
98
- Ref.new("#{type}.#{name}.#{value}")
99
- end
100
-
101
- def pretty_generate
102
- JSON.pretty_generate(output_with_children)
103
- end
104
-
105
- def resource_names
106
- out = output_with_children
107
- ret = []
108
- for type in out["resource"].keys
109
- for id in out["resource"][type].keys
110
- ret << "#{type}.#{id}"
111
- end
112
- end
113
- ret
114
- end
115
-
116
- def resources
117
- out = output_with_children
118
- ret = []
119
- for type in out["resource"].keys
120
- for id in out["resource"][type].keys
121
- ret << "${#{type}.#{id}.id}"
122
- end
123
- end
124
- ret
125
- end
126
-
127
- def add!(*c)
128
- @children.push(*c)
129
- c[0]
130
- end
131
-
132
- def tf_safe(str)
133
- str.gsub(/[\.\s\/\?]/, "-")
134
- end
135
-
136
- end
137
-
138
- class RootContext < Context
139
-
140
- def initialize
141
- super
142
-
143
- output["provider"] = PROVIDER_DEFAULTS
144
- end
145
-
146
- def backend(name, spec)
147
- @output["terraform"] = {
148
- backend: {
149
- name => spec,
150
- },
151
- }
152
- end
153
-
154
- def generate(&block)
155
- instance_eval(&block)
156
- end
157
-
158
- def method_missing(fn, *args)
159
- resource(fn, args.shift.to_s, args.first)
160
- end
161
-
162
- end
163
-
164
- Generator = RootContext.new
165
-
166
- end
@@ -1,25 +0,0 @@
1
- require 'terrafying/dynamodb/named_lock'
2
-
3
- module Terrafying
4
- module Locks
5
- class NoOpLock
6
- def acquire
7
- ""
8
- end
9
- def steal
10
- ""
11
- end
12
- def release(lock_id)
13
- end
14
- end
15
-
16
- def self.noop
17
- NoOpLock.new
18
- end
19
-
20
- def self.dynamodb(scope)
21
- Terrafying::DynamoDb::NamedLock.new(Terrafying::DynamoDb.config.lock_table, scope)
22
- end
23
-
24
- end
25
- end
@@ -1,51 +0,0 @@
1
- require 'terrafying/dynamodb/state'
2
-
3
- module Terrafying
4
- module State
5
-
6
- STATE_FILENAME = "terraform.tfstate"
7
-
8
- def self.store(config)
9
- if LocalStateStore.has_local_state?(config)
10
- local(config)
11
- else
12
- remote(config)
13
- end
14
- end
15
-
16
- def self.local(config)
17
- LocalStateStore.new(config.path)
18
- end
19
-
20
- def self.remote(config)
21
- Terrafying::DynamoDb::StateStore.new(config.scope)
22
- end
23
-
24
- class LocalStateStore
25
- def initialize(path)
26
- @path = LocalStateStore.state_path(path)
27
- end
28
-
29
- def get
30
- IO.read(@path)
31
- end
32
-
33
- def put(state)
34
- IO.write(@path, state)
35
- end
36
-
37
- def delete
38
- File.delete(@path)
39
- end
40
-
41
- def self.has_local_state?(config)
42
- File.exists?(state_path(config.path))
43
- end
44
-
45
- private
46
- def self.state_path(path)
47
- File.join(File.dirname(path), STATE_FILENAME)
48
- end
49
- end
50
- end
51
- end
@@ -1,32 +0,0 @@
1
-
2
- require 'yaml'
3
-
4
- def data_url_from_string(str)
5
- b64_contents = Base64.strict_encode64(str)
6
- return "data:;base64,#{b64_contents}"
7
- end
8
-
9
- module Terrafying
10
-
11
- module Util
12
-
13
- def self.to_ignition(yaml)
14
- config = YAML.load(yaml)
15
-
16
- if config.has_key? "storage" and config["storage"].has_key? "files"
17
- files = config["storage"]["files"]
18
- config["storage"]["files"] = files.each { |file|
19
- if file["contents"].is_a? String
20
- file["contents"] = {
21
- source: data_url_from_string(file["contents"]),
22
- }
23
- end
24
- }
25
- end
26
-
27
- JSON.pretty_generate(config)
28
- end
29
-
30
- end
31
-
32
- end
@@ -1,4 +0,0 @@
1
- module Terrafying
2
- VERSION = "0.0.1" # will be inserted by Drone
3
- CLI_VERSION = "0.11.3"
4
- end