lucid-cumulus 0.11.2 → 0.11.3

Sign up to get free protection for your applications and to get access to all the features.
@@ -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