lucid-cumulus 0.11.2 → 0.11.3

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.
@@ -0,0 +1,49 @@
1
+ module Cumulus
2
+ module IAM
3
+ require "common/Commands"
4
+ class Commands < Cumulus::Common::Commands
5
+
6
+ def self.command_details
7
+ format_message([
8
+ "groups - Manage IAM groups and users associated with those groups",
9
+ ["diff", "get a list of groups that have different definitions locally than in AWS (supplying the name of the group will diff only that group)"],
10
+ ["list", "list the groups defined in configuration"],
11
+ ["migrate", "create group configuration files that match the definitions in AWS"],
12
+ ["sync", "sync the local group definition with AWS (supplying the name of the group will sync only that group). Also adds and removes users from groups"],
13
+ "roles - Manage IAM roles",
14
+ ["diff", "get a list of roles that have different definitions locally than in AWS (supplying the name of the role will diff only that role)"],
15
+ ["list", "list the roles defined in configuration"],
16
+ ["migrate", "create role configuration files that match the definitions in AWS"],
17
+ ["sync", "sync the local role definition with AWS (supplying the name of the role will sync only that role)"],
18
+ "users - Manage IAM users",
19
+ ["diff", "get a list of users that have different definitions locally than in AWS (supplying the name of the user will diff only that user)"],
20
+ ["list", "list the users defined in configuration"],
21
+ ["migrate", "create user configuration files that match the definitions in AWS"],
22
+ ["sync", "sync the local user definition with AWS (supplying the name of the user will sync only that user)"],
23
+ ], indent: 1)
24
+ end
25
+
26
+ def self.valid_options
27
+ [["groups", "roles", "users"], ["diff", "list", "migrate", "sync"]]
28
+ end
29
+
30
+ def self.manager
31
+ require "iam/manager/Manager"
32
+ Cumulus::IAM::Manager.new
33
+ end
34
+
35
+ def self.execute(arguments)
36
+ resource = super(arguments)
37
+
38
+ if arguments[1] == "diff" and arguments.size == 3
39
+ resource.diff_one(arguments[2])
40
+ elsif arguments[1] == "sync" and arguments.size == 3
41
+ resource.sync_one(arguments[2])
42
+ else
43
+ resource.method(arguments[1]).call
44
+ end
45
+ end
46
+
47
+ end
48
+ end
49
+ end
@@ -167,7 +167,15 @@ module Cumulus
167
167
  def diff(aws_resource)
168
168
  diffs = []
169
169
 
170
- aws_policies = Hash[aws_resource.policies.map { |p| [p.name, p] }]
170
+ aws_policies = Hash[aws_resource.policies.map do |policy|
171
+ sorted_policy = JSON.parse(URI.unescape(policy.policy_document))
172
+ sorted_policy["Statement"].each do |statement|
173
+ # Sort the statments before diffing to prevent false conflicts
174
+ statement["Action"].sort!
175
+ statement["Resource"].sort!
176
+ end
177
+ [policy.name, sorted_policy]
178
+ end]
171
179
  p = policy
172
180
  p.name = generated_policy_name
173
181
 
@@ -181,9 +189,8 @@ module Cumulus
181
189
  if name != generated_policy_name
182
190
  diffs << IamDiff.unmanaged_policy(name)
183
191
  else
184
- aws_statements = JSON.parse(URI.unescape(aws_policy.policy_document))["Statement"]
192
+ aws_statements = aws_policy["Statement"]
185
193
  local_statements = p.as_hash["Statement"]
186
-
187
194
  if aws_statements != local_statements
188
195
  diff = IamDiff.new(IamChange::POLICY, aws_statements, p)
189
196
  diff.policy_name = generated_policy_name
@@ -12,8 +12,8 @@ module Cumulus
12
12
  # json - the Hash containing the JSON configuration for this StatementConfig
13
13
  def initialize(json)
14
14
  @effect = json["Effect"]
15
- @action = json["Action"]
16
- @resource = json["Resource"]
15
+ @action = json["Action"].sort
16
+ @resource = json["Resource"].sort
17
17
  @condition = json["Condition"]
18
18
  end
19
19
 
@@ -0,0 +1,20 @@
1
+ module Cumulus
2
+ module Kinesis
3
+ require "common/Commands"
4
+ class Commands < Cumulus::Common::Commands
5
+
6
+ def self.banner_message
7
+ format_message [
8
+ "kinesis: Manage Kinesis Streams",
9
+ "\tDiff and sync Kinesis configuration with AWS.",
10
+ ]
11
+ end
12
+
13
+ def self.manager
14
+ require "kinesis/manager/Manager"
15
+ Cumulus::Kinesis::Manager.new
16
+ end
17
+
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,20 @@
1
+ module Cumulus
2
+ module Route53
3
+ require "common/Commands"
4
+ class Commands < Cumulus::Common::Commands
5
+
6
+ def self.banner_message
7
+ format_message [
8
+ "route53: Manage Route53",
9
+ "\tDiff and sync Route53 configuration with AWS.",
10
+ ]
11
+ end
12
+
13
+ def self.manager
14
+ require "route53/manager/Manager"
15
+ Cumulus::Route53::Manager.new
16
+ end
17
+
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,20 @@
1
+ module Cumulus
2
+ module S3
3
+ require "common/Commands"
4
+ class Commands < Cumulus::Common::Commands
5
+
6
+ def self.manager
7
+ require "s3/manager/Manager"
8
+ Cumulus::S3::Manager.new
9
+ end
10
+
11
+ def self.banner_message
12
+ format_message [
13
+ "s3: Manage S3 Buckets",
14
+ "\tDiff and sync S3 bucket configuration with AWS.",
15
+ ]
16
+ end
17
+
18
+ end
19
+ end
20
+ end
@@ -1,6 +1,7 @@
1
1
  require "common/BaseLoader"
2
2
  require "conf/Configuration"
3
3
  require "s3/models/BucketConfig"
4
+ require "deepsort"
4
5
 
5
6
  require "aws-sdk"
6
7
 
@@ -58,7 +59,7 @@ module Cumulus
58
59
  name,
59
60
  @@policies_dir,
60
61
  vars,
61
- &proc { |n, json| json.to_json }
62
+ &proc { |n, json| json.deep_sort.to_json }
62
63
  )
63
64
  end
64
65
  end
@@ -0,0 +1,24 @@
1
+ module Cumulus
2
+ module SecurityGroups
3
+ require "common/Commands"
4
+ class Commands < Cumulus::Common::Commands
5
+
6
+ def self.manager_name
7
+ "security-groups"
8
+ end
9
+
10
+ def self.manager
11
+ require "security/manager/Manager"
12
+ Cumulus::SecurityGroups::Manager.new
13
+ end
14
+
15
+ def self.banner_message
16
+ format_message [
17
+ "security-groups: Manage EC2 Security Groups",
18
+ "\tDiff and sync EC2 security group configuration with AWS.",
19
+ ]
20
+ end
21
+
22
+ end
23
+ end
24
+ end
@@ -0,0 +1,34 @@
1
+ module Cumulus
2
+ module SQS
3
+ require "common/Commands"
4
+ class Commands < Cumulus::Common::Commands
5
+
6
+ def self.banner_message
7
+ format_message [
8
+ "SQS: Manage SQS",
9
+ "\tDiff and sync SQS configuration with AWS.",
10
+ ]
11
+ end
12
+
13
+ def self.command_details
14
+ format_message [
15
+ ["diff", "print out differences between local configuration and AWS (supplying the name of the queue will diff only that queue)"],
16
+ ["list", "list the locally defined queues"],
17
+ ["urls", "list the url for each locally defined queue"],
18
+ ["sync", "sync local queue definitions with AWS (supplying the name of the queue will sync only that queue)"],
19
+ ["migrate", "migrate AWS configuration to Cumulus"],
20
+ ]
21
+ end
22
+
23
+ def self.manager
24
+ require "sqs/manager/Manager"
25
+ Cumulus::SQS::Manager.new
26
+ end
27
+
28
+ def self.valid_options
29
+ [["diff", "list", "migrate", "sync", "urls"]]
30
+ end
31
+
32
+ end
33
+ end
34
+ end
data/lib/sqs/SQS.rb CHANGED
@@ -8,6 +8,12 @@ module Cumulus
8
8
  class << self
9
9
  @@client = Aws::SQS::Client.new(Configuration.instance.client)
10
10
 
11
+ # Public
12
+ # Returns the AWS client used in the module
13
+ def client
14
+ @@client
15
+ end
16
+
11
17
  # Public: Static method that will get the ARN of a Queue
12
18
  #
13
19
  # name - the name of the queue to get
@@ -10,21 +10,26 @@ module Cumulus
10
10
  module Loader
11
11
  include Common::BaseLoader
12
12
 
13
- @@queues_dir = Configuration.instance.sqs.queues_directory
14
- @@policies_dir = Configuration.instance.sqs.policies_directory
13
+ def self.queues_dir
14
+ Configuration.instance.sqs.queues_directory
15
+ end
16
+
17
+ def self.policies_dir
18
+ Configuration.instance.sqs.policies_directory
19
+ end
15
20
 
16
21
  # Public: Load all the queue configurations as QueueConfig objects
17
22
  #
18
23
  # Returns an array of QueueConfig
19
24
  def self.queues
20
- Common::BaseLoader::resources(@@queues_dir, &QueueConfig.method(:new))
25
+ Common::BaseLoader::resources(self.queues_dir, &QueueConfig.method(:new))
21
26
  end
22
27
 
23
28
  # Public: Load the specified policy as a JSON object
24
29
  #
25
30
  # Returns the JSON object for the policy
26
31
  def self.policy(policy_name)
27
- Common::BaseLoader::resource(policy_name, @@policies_dir) do |policy_name, policy|
32
+ Common::BaseLoader::resource(policy_name, self.policies_dir) do |policy_name, policy|
28
33
  policy
29
34
  end
30
35
  end
@@ -15,7 +15,6 @@ module Cumulus
15
15
  def initialize
16
16
  super()
17
17
  @create_asset = true
18
- @client = Aws::SQS::Client.new(Configuration.instance.client)
19
18
  end
20
19
 
21
20
  def resource_name
@@ -50,16 +49,16 @@ module Cumulus
50
49
  end
51
50
 
52
51
  def update(local, diffs)
53
- @client.set_queue_attributes({
52
+ SQS::client.set_queue_attributes({
54
53
  queue_url: SQS::queue_urls[local.name],
55
54
  attributes: {
56
- "DelaySeconds" => if diffs.any? { |d| d.type == QueueChange::DELAY } then local.delay end,
57
- "MaximumMessageSize" => if diffs.any? { |d| d.type == QueueChange::MESSAGE_SIZE } then local.max_message_size end,
58
- "MessageRetentionPeriod" => if diffs.any? { |d| d.type == QueueChange::MESSAGE_RETENTION } then local.message_retention end,
55
+ "DelaySeconds" => if diffs.any? { |d| d.type == QueueChange::DELAY } then local.delay.to_s end,
56
+ "MaximumMessageSize" => if diffs.any? { |d| d.type == QueueChange::MESSAGE_SIZE } then local.max_message_size.to_s end,
57
+ "MessageRetentionPeriod" => if diffs.any? { |d| d.type == QueueChange::MESSAGE_RETENTION } then local.message_retention.to_s end,
59
58
  "Policy" => if diffs.any? { |d| d.type == QueueChange::POLICY }
60
59
  if local.policy then JSON.generate(Loader.policy(local.policy)) else "" end
61
60
  end,
62
- "ReceiveMessageWaitTimeSeconds" => if diffs.any? { |d| d.type == QueueChange::RECEIVE_WAIT } then local.receive_wait_time end,
61
+ "ReceiveMessageWaitTimeSeconds" => if diffs.any? { |d| d.type == QueueChange::RECEIVE_WAIT } then local.receive_wait_time.to_s end,
63
62
  "VisibilityTimeout" => if diffs.any? { |d| d.type == QueueChange::VISIBILITY } then local.visibility_timeout end,
64
63
  "RedrivePolicy" => if diffs.any? { |d| d.type == QueueChange::DEAD }
65
64
  if local.dead_letter then JSON.generate(local.dead_letter.to_aws) else "" end
@@ -69,7 +68,7 @@ module Cumulus
69
68
  end
70
69
 
71
70
  def create(local)
72
- url = @client.create_queue({
71
+ url = SQS::client.create_queue({
73
72
  queue_name: local.name,
74
73
  attributes: {
75
74
  "DelaySeconds" => "#{local.delay}",
@@ -0,0 +1,43 @@
1
+ module Cumulus
2
+ module VPC
3
+ require "common/Commands"
4
+ class Commands < Cumulus::Common::Commands
5
+
6
+ def self.command_details
7
+ format_message [
8
+ ["diff", "print out differences between local configuration and AWS (supplying the name of the VPC will diff only that VPC)"],
9
+ ["list", "list the locally defined VPCs"],
10
+ ["sync", "sync local VPC definitions with AWS (supplying the name of the VPC will sync only that VPC)"],
11
+ ["migrate", "migrate AWS configuration to Cumulus"],
12
+ ["rename", "renames a cumulus asset and all references to it"],
13
+ ]
14
+ end
15
+
16
+ def self.manager
17
+ require "vpc/manager/Manager"
18
+ Cumulus::VPC::Manager.new
19
+ end
20
+
21
+ def self.valid_options
22
+ [["diff", "list", "migrate", "sync", "rename"]]
23
+ end
24
+
25
+ def self.execute(arguments)
26
+ if arguments[0] == "diff" and arguments.size == 2
27
+ manager.diff_one(arguments[1])
28
+ elsif arguments[0] == "sync" and arguments.size == 2
29
+ manager.sync_one(arguments[1])
30
+ elsif arguments[0] == "rename"
31
+ if arguments.size == 5
32
+ manager.rename(arguments[1], arguments[2], arguments[3])
33
+ else
34
+ puts "Usage: cumulus vpc rename [network-acl|policy|route-table|subnet|vpc] <old-asset-name> <new-asset-name>"
35
+ end
36
+ else
37
+ manager.method(arguments[0]).call
38
+ end
39
+ end
40
+
41
+ end
42
+ end
43
+ end
@@ -4,7 +4,7 @@ require "bundler"
4
4
 
5
5
  Gem::Specification.new do |s|
6
6
  s.name = "lucid-cumulus"
7
- s.version = "0.11.2"
7
+ s.version = "0.11.3"
8
8
  s.platform = Gem::Platform::RUBY
9
9
  s.authors = ["Keilan Jackson", "Mark Siebert"]
10
10
  s.email = "cumulus@lucidchart.com"
@@ -17,4 +17,5 @@ Gem::Specification.new do |s|
17
17
 
18
18
  s.add_runtime_dependency "aws-sdk", "2.2.30"
19
19
  s.add_runtime_dependency "parse-cron", "~> 0.1.4"
20
+ s.add_runtime_dependency "deepsort", "~> 0.1"
20
21
  end
data/rakefile.rb CHANGED
@@ -1,8 +1,13 @@
1
1
  require "bundler/gem_tasks"
2
+ require 'rspec/core/rake_task'
2
3
 
3
4
  task :default => :spec
4
5
 
5
6
  task :spec do
6
- puts "Running tests... \n"
7
- puts "Tests have not been written yet :("
7
+ Rake::Task['spec_sqs'].execute
8
+ end
9
+
10
+ RSpec::Core::RakeTask.new(:spec_sqs) do |task|
11
+ task.rspec_opts = ['-r ./spec/rspec_config.rb']
12
+ task.pattern = 'spec/sqs/*_spec.rb'
8
13
  end
@@ -0,0 +1,43 @@
1
+ module Cumulus
2
+ module Test
3
+ SpiedMethod = Struct.new(:arguments_list) do
4
+ def num_calls
5
+ arguments_list.size
6
+ end
7
+
8
+ def arguments
9
+ arguments_list[0]
10
+ end
11
+ end
12
+
13
+ class ClientSpy
14
+ attr_reader :method_calls
15
+
16
+ def initialize(client)
17
+ @method_calls = {}
18
+ metaclass = class << self; self; end
19
+ client.methods.each do |m|
20
+ method_name = m.to_sym
21
+ metaclass.send(:define_method, method_name) do |*args|
22
+ if !@method_calls.has_key? method_name
23
+ @method_calls[method_name] = SpiedMethod.new([])
24
+ end
25
+ @method_calls[method_name] = SpiedMethod.new(
26
+ @method_calls[method_name].arguments_list.push(args)
27
+ )
28
+ client.method(method_name).call(*args)
29
+ end
30
+ end
31
+ end
32
+
33
+ def clear_spy
34
+ @method_calls = {}
35
+ end
36
+
37
+ def spied_method(name)
38
+ @method_calls[name]
39
+ end
40
+
41
+ end
42
+ end
43
+ end
@@ -0,0 +1,61 @@
1
+ require "util/DeepMerge"
2
+
3
+ module Cumulus
4
+ module Test
5
+ module MockedConfiguration
6
+ def self.included(base)
7
+ base.instance_eval do
8
+ include Cumulus::Test::Util::DeepMerge
9
+
10
+ def stub(overrides = nil)
11
+ overridden = Util::DeepMerge.deep_merge(@@default_config, overrides)
12
+ init_from_hash(overridden, '/mocked', nil, nil, false)
13
+ end
14
+
15
+ stub
16
+ end
17
+ end
18
+
19
+ @@default_config = {
20
+ "stub_aws_responses" => true,
21
+ "colors-enabled" => false,
22
+ "iam" => {
23
+ "policies" => {
24
+ "prefix" => "",
25
+ "suffix" => "",
26
+ "version" => "",
27
+ },
28
+ },
29
+ "autoscaling" => {
30
+ "groups" => {
31
+ "override-launch-config-on-sync" => false,
32
+ },
33
+ },
34
+ "route53" => {
35
+ "print-all-ignored" => true,
36
+ },
37
+ "s3" => {
38
+ "print-progress" => true,
39
+ },
40
+ "security" => {
41
+ "outbound-default-all-allowed" => true,
42
+ "subnet-files" => [
43
+ "security-groups/subnets.json",
44
+ ],
45
+ },
46
+ "ec2" => {
47
+ "instances" => {
48
+ "ignore-unmanaged" => true,
49
+ "default-image-id" => nil,
50
+ "volume-mounting" => {
51
+ "base" => "/dev/xvd",
52
+ "start" => "f",
53
+ "end" => "z",
54
+ },
55
+ },
56
+ },
57
+ "region" => "us-east-1",
58
+ }
59
+ end
60
+ end
61
+ end