simnos 0.1.1.beta1 → 0.1.1.beta2

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: f7852e8296f11712e300ceff4199a87244afa228
4
- data.tar.gz: 60783438422b07f0bbed97fa714c09fca1dc0c68
3
+ metadata.gz: 331d3fe90ec21685f9fa4a969c2e3d77436d88c3
4
+ data.tar.gz: e9053c2ad17c3d06fceef1097eed7066e8fc94ab
5
5
  SHA512:
6
- metadata.gz: 6c867759e0989739c9400ff6d9cf3fe255ffe05a43e1b84894c0c5ba78b46d442839faaf4d2b26a598bcc992f17bc77ac617fa888f8b7cc9c0f9d5207e65068a
7
- data.tar.gz: c3322803fb225d76b0753af9818698e579654147f9eda3b1f6386c93cc37de3e6446ff7122a41920a658d9d430f3c10d49f2ba7b961648b157310ed022eeb78c
6
+ metadata.gz: 61869e91186323165f8ea9cba28e1a79c503b25f10dec59167fea025abca8b9735bc14b5d843151e947f983abb2a20fa399e968fcf7fa01b63652c25bcaa34c5
7
+ data.tar.gz: a3aec65e414b5cab557b9d2ca491ee84e3188f1b8f93c913aa4ba49ef2681b12d7b524b2b970e49510126173c0c7be5d2eb7951eca0340f82d39f5791f36f2e0
data/README.md CHANGED
@@ -46,6 +46,10 @@ Usage: simnos [options]
46
46
  no color
47
47
  --with-subscriptions
48
48
  manage subscriptions
49
+ --recreate-subscriptions
50
+ recreate subscriptions
51
+ --secret-provider NAME
52
+ use secret value expansion
49
53
  -i, --include-names NAMES include SNS names
50
54
  -x, --exclude-names NAMES exclude SNS names by regex
51
55
  ```
@@ -114,6 +118,25 @@ sns "ap-northeast-1" do
114
118
  end
115
119
  ```
116
120
 
121
+ ## Secret provider
122
+
123
+ If you don't want to commit your Basic authentication password, you can use SecretProvider.
124
+ Use --secret-provider option to select provider.(e.g. --secret-provider=vault)
125
+ Expression inside `${...}` is passed to provider.
126
+
127
+ ```
128
+ subscriptions do
129
+ subscription protocol: "https", endpoint: "https://user:${password}your.awesome.site/"
130
+ end
131
+ ```
132
+
133
+ ## Subscriptions
134
+
135
+ There is no way to UPDATE subscription.
136
+ So if you want to recreate subscrptions, use --recreate-subscriptions option.
137
+ It is highly recommended to also path --include-names or exclude-names to select topics.
138
+ Because of Basic authentication password is not returned from API, recreation is needed to change password.
139
+
117
140
  ## Similar tools
118
141
 
119
142
  * [Codenize.tools](http://codenize.tools/)
@@ -44,6 +44,8 @@ module Simnos
44
44
  opts.on('-s', '--split', 'split export DSL file to 1 per topic') { @options[:split] = true }
45
45
  opts.on('', '--no-color', 'no color') { @options[:color] = false }
46
46
  opts.on('', '--with-subscriptions', 'manage subscriptions') { @options[:with_subscriptions] = true }
47
+ opts.on('', '--recreate-subscriptions', 'recreate subscriptions') { @options[:recreate_subscriptions] = true }
48
+ opts.on('', '--secret-provider NAME', 'use secret value expansion') { |v| @options[:secret_provider] = v }
47
49
  opts.on('-i', '--include-names NAMES', 'include SNS names', Array) { |v| @options[:includes] = v }
48
50
  opts.on('-x', '--exclude-names NAMES', 'exclude SNS names by regex', Array) do |v|
49
51
  @options[:excludes] = v.map! do |name|
@@ -3,6 +3,7 @@ require 'simnos/client_wrapper'
3
3
  require 'simnos/converter'
4
4
  require 'simnos/dsl'
5
5
  require 'simnos/filterable'
6
+ require 'simnos/secret_expander'
6
7
 
7
8
  module Simnos
8
9
  class Client
@@ -15,6 +16,7 @@ module Simnos
15
16
  def initialize(filepath, options = {})
16
17
  @filepath = filepath
17
18
  @options = options
19
+ @options[:secret_expander] = SecretExpander.new(@options[:secret_provider]) if @options[:secret_provider]
18
20
  end
19
21
 
20
22
  def apply
@@ -70,29 +72,41 @@ module Simnos
70
72
 
71
73
  private
72
74
 
75
+ def delete_subscriptions(aws_topic, aws_sub_by_key)
76
+ aws_sub_by_key.each do |key, aws_sub|
77
+ Simnos.logger.info("Delete Topic(#{aws_topic[:topic].topic_arn.split(':').last}) Subscription. protocol: #{key[0].inspect}, endpoint: #{key[1].inspect}.#{@options[:dry_run] ? ' [dry-run]' : ''}")
78
+ if aws_sub.subscription_arn.split(':').length < 6
79
+ Simnos.logger.warn("Can not delete Subscription `#{aws_sub.subscription_arn}`")
80
+ next
81
+ end
82
+ next if @options[:dry_run]
83
+
84
+ client.unsubscribe(subscription_arn: aws_sub.subscription_arn)
85
+ end
86
+ end
87
+
73
88
  def traverse_subscriptions(aws_topic, dsl_subscriptions, aws_subscriptions)
74
- dsl_sub_by_key = dsl_subscriptions.each_with_object({}) { |dsl_sub, h| h[[dsl_sub.protocol, dsl_sub.endpoint]] = dsl_sub }
89
+ dsl_sub_by_key = dsl_subscriptions.each_with_object({}) { |dsl_sub, h| h[[dsl_sub.protocol, dsl_sub.masked_endpoint]] = dsl_sub }
75
90
  aws_sub_by_key = aws_subscriptions.each_with_object({}) { |aws_sub, h| h[[aws_sub.protocol, aws_sub.endpoint]] = aws_sub }
91
+
92
+ if @options[:recreate_subscriptions]
93
+ Simnos.logger.info("Subscription recreation flag is on.#{@options[:dry_run] ? ' [dry-run]' : ''}")
94
+ delete_subscriptions(aws_topic, aws_sub_by_key)
95
+ aws_sub_by_key = {}
96
+ end
97
+
76
98
  # create
77
99
  dsl_sub_by_key.reject { |key, _| aws_sub_by_key[key] }.each do |key, dsl_sub|
78
100
  dsl_sub.aws_topic(aws_topic).create
79
101
  end
80
102
 
103
+ # there is no way to update subscriptions
81
104
  dsl_sub_by_key.each do |key, dsl_sub|
82
105
  aws_sub_by_key.delete(key)
83
106
  end
84
107
 
85
108
  # delete
86
- aws_sub_by_key.each do |key, aws_sub|
87
- Simnos.logger.info("Delete Topic(#{aws_topic[:topic].topic_arn.split(':').last}) Subscription. protocol: #{key[0].inspect}, endpoint: #{key[1].inspect}.#{@options[:dry_run] ? ' [dry-run]' : ''}")
88
- if aws_sub.subscription_arn.split(':').length < 6
89
- Simnos.logger.warn("Can not delete Subscription `#{aws_sub.subscription_arn}`")
90
- next
91
- end
92
- next if @options[:dry_run]
93
-
94
- client.unsubscribe(subscription_arn: aws_sub.subscription_arn)
95
- end
109
+ delete_subscriptions(aws_topic, aws_sub_by_key)
96
110
  end
97
111
 
98
112
  def traverse_topics(dsl_topics_all, aws_topics_by_name)
@@ -6,7 +6,7 @@ module Simnos
6
6
  include Simnos::TemplateHelper
7
7
 
8
8
  def create
9
- Simnos.logger.info("Create Topic(#{@aws_topic[:topic].topic_arn.split(':').last}) Subscription. protocol: #{protocol.inspect}, endpoint: #{endpoint.inspect}#{@options[:dry_run] ? ' [dry-run]' : ''}")
9
+ Simnos.logger.info("Create Topic(#{@aws_topic[:topic].topic_arn.split(':').last}) Subscription. protocol: #{protocol.inspect}, endpoint: #{masked_endpoint.inspect}#{@options[:dry_run] ? ' [dry-run]' : ''}")
10
10
  return if @options[:dry_run]
11
11
 
12
12
  client.subscribe(
@@ -29,7 +29,28 @@ module Simnos
29
29
  @endpoint = endpoint
30
30
  end
31
31
 
32
- attr_reader :topic, :protocol, :endpoint
32
+ attr_reader :topic, :protocol
33
+
34
+ # We have to mask endpoint because SNS returns masked endpoint from API
35
+ def masked_endpoint
36
+ if URI.extract(@endpoint, ['http', 'https']).empty?
37
+ return endpoint
38
+ end
39
+ uri = URI.parse(endpoint)
40
+ if md = uri.userinfo&.match(/(.*):(.*)/)
41
+ uri.userinfo = "#{md[1]}:****"
42
+ end
43
+ uri.to_s
44
+ end
45
+
46
+ def endpoint
47
+ secret_expander = @options[:secret_expander]
48
+ if secret_expander
49
+ secret_expander.expand(@endpoint)
50
+ else
51
+ @endpoint
52
+ end
53
+ end
33
54
 
34
55
  private
35
56
 
@@ -0,0 +1,75 @@
1
+ require 'strscan'
2
+
3
+ module Simnos
4
+ class ExpansionError < StandardError
5
+ end
6
+
7
+ class SecretExpander
8
+ Literal = Struct.new(:literal)
9
+ Variable = Struct.new(:name)
10
+
11
+ def initialize(provider_name)
12
+ @provider = load_provider(provider_name)
13
+ @asked_variables = {}
14
+ end
15
+
16
+ def expand(str)
17
+ tokens = parse(str)
18
+ variables = Set.new
19
+ tokens.each do |token|
20
+ if token.is_a?(Variable)
21
+ unless @asked_variables.include?(token.name)
22
+ variables << token.name
23
+ end
24
+ end
25
+ end
26
+
27
+ unless variables.empty?
28
+ @provider.ask(variables).each do |k, v|
29
+ @asked_variables[k] = v
30
+ end
31
+ end
32
+
33
+ tokens.map do |token|
34
+ case token
35
+ when Literal
36
+ token.literal
37
+ when Variable
38
+ @asked_variables.fetch(token.name)
39
+ else
40
+ raise ExpansionError.new("Unknown token type: #{token.class}")
41
+ end
42
+ end.join
43
+ end
44
+
45
+ private
46
+
47
+ def parse(value)
48
+ s = StringScanner.new(value)
49
+ tokens = []
50
+ pos = 0
51
+ while s.scan_until(/\$\{(.*?)\}/)
52
+ pre = s.string.byteslice(pos...(s.pos - s.matched.size))
53
+ var = s[1]
54
+ unless pre.empty?
55
+ tokens << Literal.new(pre)
56
+ end
57
+ if var.empty?
58
+ raise ExpansionError.new('Empty interpolation is not allowed')
59
+ else
60
+ tokens << Variable.new(var)
61
+ end
62
+ pos = s.pos
63
+ end
64
+ unless s.rest.empty?
65
+ tokens << Literal.new(s.rest)
66
+ end
67
+ tokens
68
+ end
69
+
70
+ def load_provider(name)
71
+ require "simnos/secret_providers/#{name}"
72
+ Simnos::SecretProviders.const_get(name.split('_').map(&:capitalize).join('')).new
73
+ end
74
+ end
75
+ end
@@ -1,3 +1,3 @@
1
1
  module Simnos
2
- VERSION = "0.1.1.beta1"
2
+ VERSION = "0.1.1.beta2"
3
3
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: simnos
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.1.beta1
4
+ version: 0.1.1.beta2
5
5
  platform: ruby
6
6
  authors:
7
7
  - wata
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2017-10-03 00:00:00.000000000 Z
11
+ date: 2017-10-26 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: aws-sdk
@@ -166,6 +166,7 @@ files:
166
166
  - lib/simnos/dsl/topic.rb
167
167
  - lib/simnos/filterable.rb
168
168
  - lib/simnos/output_topic.erb
169
+ - lib/simnos/secret_expander.rb
169
170
  - lib/simnos/template_helper.rb
170
171
  - lib/simnos/utils.rb
171
172
  - lib/simnos/version.rb