knife-rds 0.0.1

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 @@
1
+ *.gem
data/Gemfile ADDED
@@ -0,0 +1,3 @@
1
+ source 'https://rubygems.org'
2
+
3
+ gemspec
@@ -0,0 +1,119 @@
1
+ PATH
2
+ remote: .
3
+ specs:
4
+ knife-rds (0.0.1)
5
+ aws-sdk
6
+ chef (>= 11.4.0)
7
+
8
+ GEM
9
+ remote: https://rubygems.org/
10
+ specs:
11
+ ast (1.1.0)
12
+ aws-sdk (1.36.0)
13
+ json (~> 1.4)
14
+ nokogiri (>= 1.4.4)
15
+ uuidtools (~> 2.1)
16
+ chef (11.10.4)
17
+ chef-zero (~> 1.7, >= 1.7.2)
18
+ diff-lcs (~> 1.2, >= 1.2.4)
19
+ erubis (~> 2.7)
20
+ highline (~> 1.6, >= 1.6.9)
21
+ json (>= 1.4.4, <= 1.8.1)
22
+ mime-types (~> 1.16)
23
+ mixlib-authentication (~> 1.3)
24
+ mixlib-cli (~> 1.4)
25
+ mixlib-config (~> 2.0)
26
+ mixlib-log (~> 1.3)
27
+ mixlib-shellout (~> 1.3)
28
+ net-ssh (~> 2.6)
29
+ net-ssh-multi (~> 1.1)
30
+ ohai (~> 6.0)
31
+ pry (~> 0.9)
32
+ puma (~> 1.6)
33
+ rest-client (>= 1.0.4, < 1.7.0)
34
+ yajl-ruby (~> 1.1)
35
+ chef-zero (1.7.3)
36
+ hashie (~> 2.0)
37
+ json
38
+ mixlib-log (~> 1.3)
39
+ moneta (< 0.7.0)
40
+ rack
41
+ coderay (1.1.0)
42
+ diff-lcs (1.2.5)
43
+ erubis (2.7.0)
44
+ fakeweb (1.3.0)
45
+ hashie (2.0.5)
46
+ highline (1.6.21)
47
+ ipaddress (0.8.0)
48
+ json (1.8.1)
49
+ method_source (0.8.2)
50
+ mime-types (1.25.1)
51
+ mini_portile (0.5.2)
52
+ mixlib-authentication (1.3.0)
53
+ mixlib-log
54
+ mixlib-cli (1.4.0)
55
+ mixlib-config (2.1.0)
56
+ mixlib-log (1.6.0)
57
+ mixlib-shellout (1.3.0)
58
+ moneta (0.6.0)
59
+ net-ssh (2.8.0)
60
+ net-ssh-gateway (1.2.0)
61
+ net-ssh (>= 2.6.5)
62
+ net-ssh-multi (1.2.0)
63
+ net-ssh (>= 2.6.5)
64
+ net-ssh-gateway (>= 1.2.0)
65
+ nokogiri (1.6.1)
66
+ mini_portile (~> 0.5.0)
67
+ ohai (6.20.0)
68
+ ipaddress
69
+ mixlib-cli
70
+ mixlib-config
71
+ mixlib-log
72
+ mixlib-shellout
73
+ systemu (~> 2.5.2)
74
+ yajl-ruby
75
+ parser (2.1.7)
76
+ ast (~> 1.1)
77
+ slop (~> 3.4, >= 3.4.5)
78
+ powerpack (0.0.9)
79
+ pry (0.9.12.6)
80
+ coderay (~> 1.0)
81
+ method_source (~> 0.8)
82
+ slop (~> 3.4)
83
+ puma (1.6.3)
84
+ rack (~> 1.2)
85
+ rack (1.5.2)
86
+ rainbow (2.0.0)
87
+ rake (10.1.1)
88
+ rest-client (1.6.7)
89
+ mime-types (>= 1.16)
90
+ rspec (2.14.1)
91
+ rspec-core (~> 2.14.0)
92
+ rspec-expectations (~> 2.14.0)
93
+ rspec-mocks (~> 2.14.0)
94
+ rspec-core (2.14.8)
95
+ rspec-expectations (2.14.5)
96
+ diff-lcs (>= 1.1.3, < 2.0)
97
+ rspec-mocks (2.14.6)
98
+ rubocop (0.19.1)
99
+ json (>= 1.7.7, < 2)
100
+ parser (~> 2.1.7)
101
+ powerpack (~> 0.0.6)
102
+ rainbow (>= 1.99.1, < 3.0)
103
+ ruby-progressbar (~> 1.4)
104
+ ruby-progressbar (1.4.2)
105
+ slop (3.4.7)
106
+ systemu (2.5.2)
107
+ uuidtools (2.1.4)
108
+ yajl-ruby (1.2.0)
109
+
110
+ PLATFORMS
111
+ ruby
112
+
113
+ DEPENDENCIES
114
+ fakeweb
115
+ knife-rds!
116
+ pry
117
+ rake (~> 10.1)
118
+ rspec (~> 2.14)
119
+ rubocop
data/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ The MIT License (MIT)
2
+
3
+ Copyright (c) 2014 Quandl
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,100 @@
1
+ # knife-rds
2
+
3
+ ## Overview
4
+
5
+ A knife plugin for managing AWS RDS instances.
6
+
7
+ ** WORK IN PROGRESS. **
8
+
9
+ This project is very early, and should be taken as a proof of concept.
10
+
11
+ ## Motivation
12
+
13
+ * Integration of AWS resources with Chef intrastructure.
14
+
15
+ * Store configuration for security and parameter groups in Chef.
16
+
17
+ ## Commands (pending)
18
+
19
+ All commands use *your* EC2 keys, as configured in your Knife configuration. Your ability to interact with RDS resources is limited by your account access.
20
+
21
+
22
+ ### Instances
23
+
24
+ #### List
25
+
26
+ ```bash
27
+ knife rds list
28
+ ```
29
+
30
+ List available RDS Instances.
31
+
32
+ #### Modify
33
+
34
+ ```bash
35
+ knife rds instance from data bag (ITEM)
36
+ ```
37
+ Create or update an RDS instance using attributes stored in a data bag.
38
+
39
+ ### Security Groups
40
+
41
+ #### List
42
+
43
+ ```bash
44
+ knife sg list
45
+ ```
46
+
47
+ List created RDS security groups. Show name and description.
48
+
49
+ #### Modify
50
+
51
+ ```bash
52
+ knife rds sg from data bag SECURITY_GROUP_NAME
53
+ ```
54
+ Creates and/or updates an RDS security group and syncs the authorization levels with those specified in the data bag.
55
+
56
+ The command expects the following keys:
57
+
58
+ * description: (String) The description of the data bag. (Only required when security group is *created*).
59
+ * ec2_security_groups: (Array) A list of string EC2 security group names to whitelist for this RDS security group.
60
+ * ip_addressses: (Array) A list of IP addresses that should have access to this security group.
61
+
62
+ All EC2 security groups and IP addresses that exist in the data bag will be granted access to this security group.
63
+
64
+ Any EC2 securiy groups or IP addresses that previously had authorization, but no longer appear in the data bag, will have their authorization revoked.
65
+
66
+ The expected data bag name is 'rds_parameter_groups', but this can be overriden.
67
+
68
+ ### Parameter Groups
69
+
70
+ ####List
71
+
72
+ ```bash
73
+ knife pg list
74
+ ```
75
+
76
+ List created RDS parameter groups.
77
+
78
+
79
+ #### Modify
80
+
81
+ ```bash
82
+ knife pg from data bag PARAMETER_GROUP_NAME
83
+ ```
84
+
85
+ Creates and/or updates an RDS parameter group. Syncs user defined settings from data bag to AWS.
86
+
87
+ The command expects the following keys:
88
+
89
+ * description: (String) Parameter group descriptive text. (Only required when parameter group is *created*).
90
+ * db_parameter_group_family: (String) The parameter group family you group should inherit from. (Only required when parameter group is *created*).
91
+ * parameters: (Hash) Key,value combinations of parameters to be overriden.
92
+
93
+ All *valid parameters* in the data bag will be applied (via the 'apply method') to the data bag.
94
+
95
+ All *user supplied parameters* that exist in the parameter group, but are not present in the data bag, will be revoked (via the 'apply method').
96
+
97
+
98
+
99
+
100
+
@@ -0,0 +1,20 @@
1
+ #!/usr/bin/env ruby
2
+ require 'chef'
3
+ require 'pry'
4
+
5
+ $LOAD_PATH.unshift(File.expand_path(File.dirname(__FILE__) + "/../lib"))
6
+
7
+ Chef::Config.from_file File.expand_path(ENV.fetch('KNIFE_CONFIG', '~/.chef/knife.rb'))
8
+
9
+ Dir.glob(File.dirname(__FILE__) + "/../lib/chef/knife/*.rb").each do |task|
10
+ p = Pathname.new(task)
11
+ require "chef/knife/#{p.basename}"
12
+ end
13
+
14
+ begin
15
+ AWS.config(aws_access_key_id: Chef::Config[:knife][:aws_access_key_id], aws_secret_access_key: Chef::Config[:knife][:aws_secret_access_key])
16
+ rescue => e
17
+ puts e.message
18
+ end
19
+
20
+ binding.pry
@@ -0,0 +1,28 @@
1
+ # -*- encoding: utf-8 -*-
2
+ $:.push File.expand_path('../lib', __FILE__)
3
+ require 'knife-rds/version'
4
+
5
+ Gem::Specification.new do |s|
6
+ s.name = 'knife-rds'
7
+ s.version = Knife::RDS::VERSION
8
+ s.authors = ['Jason Byck']
9
+ s.email = ['jbyck@quandl.com']
10
+ s.homepage = 'https://github.com/quandl/knife-rds'
11
+ s.summary = %q{Manage RDS}
12
+ s.description = s.summary
13
+
14
+ s.files = `git ls-files`.split("\n")
15
+ s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
16
+
17
+ s.add_dependency 'chef', '>= 11.4.0'
18
+ s.add_dependency 'aws-sdk'
19
+
20
+ s.add_development_dependency 'rspec', '~> 2.14'
21
+ s.add_development_dependency 'rake', '~> 10.1'
22
+ s.add_development_dependency 'fakeweb'
23
+ s.add_development_dependency 'pry'
24
+ s.add_development_dependency 'rubocop'
25
+
26
+ s.require_paths = ['lib']
27
+
28
+ end
@@ -0,0 +1,75 @@
1
+ require 'chef/knife'
2
+ require 'aws'
3
+
4
+ class Chef
5
+ class Knife
6
+ module RdsBase
7
+
8
+ '''
9
+ Base module to be used by All Knife::RDS commands
10
+ '''
11
+
12
+ def self.included(base)
13
+ base.class_eval do
14
+
15
+ option :aws_access_key_id,
16
+ :short => "-A ID",
17
+ :long => "--aws-access-key-id ID",
18
+ :description => "Your AWS Access Key ID",
19
+ :proc => Proc.new { |key| Chef::Config[:knife][:aws_access_key_id] = key }
20
+
21
+ option :aws_secret_access_key,
22
+ :short => "-K SECRET",
23
+ :long => "--aws-secret-access-key SECRET",
24
+ :description => "Your AWS API Secret Access Key",
25
+ :proc => Proc.new { |key| Chef::Config[:knife][:aws_secret_access_key] = key }
26
+
27
+ end
28
+ end
29
+
30
+ APPLY_METHODS = ['immediate', 'pending-reboot'] unless defined?(APPLY_METHODS)
31
+
32
+ def assert_name_args_at_least!(num, error = 'Incorrect number of name args.')
33
+ unless name_args.size >= num
34
+ ui.fatal(error)
35
+ show_usage
36
+ exit 1
37
+ end
38
+ end
39
+
40
+ # Ensure user is authenticated before proceededing
41
+ #
42
+ # Raises ArgumentError
43
+ def authenticate!(required = [:aws_access_key_id, :aws_secret_access_key])
44
+ errors = []
45
+ required.each do |k|
46
+ if Chef::Config[:knife][k].nil?
47
+ errors << "A valid #{k} is required."
48
+ end
49
+ end
50
+ unless errors.empty?
51
+ errors.each { |e| ui.error(e) }
52
+ exit 1
53
+ end
54
+ connect!
55
+ end
56
+
57
+ # Assert user supplied apply method is valid
58
+ def assert_valid_apply_method!
59
+ unless APPLY_METHODS.include?(config[:apply_method])
60
+ ui.fatal("Unknown type of apply method #{config[:apply_method]}")
61
+ exit 1
62
+ end
63
+ end
64
+
65
+ def rds
66
+ AWS::RDS.new
67
+ end
68
+
69
+ def connect!
70
+ AWS.config(aws_access_key_id: config[:aws_access_key_id], aws_secret_access_key: config[:aws_secret_access_key])
71
+ end
72
+
73
+ end
74
+ end
75
+ end
@@ -0,0 +1,145 @@
1
+ require 'chef/knife'
2
+ class Chef
3
+ class Knife
4
+ # Base module for interfacing with Data Bags
5
+ module RdsBaseDataBag
6
+ def self.included(base)
7
+ base.extend(ClassMethods)
8
+ end
9
+ # ClassMethods
10
+ module ClassMethods
11
+ @@required_data_bag_options ||= {}
12
+ @@data_bag_params ||= {}
13
+
14
+ # Safe string name for the task
15
+ def task_name
16
+ name.to_s.downcase.gsub(/:/, '')
17
+ end
18
+
19
+ def define_params(*params)
20
+ include_params_for(params, @@data_bag_params)
21
+ end
22
+
23
+ def require_in_data_bag(*params)
24
+ include_params_for(params, @@required_data_bag_options)
25
+ end
26
+
27
+ # Helper method for building attribute list for the task
28
+ #
29
+ # params - Array of parameter names
30
+ # attribute - Class variable
31
+ def include_params_for(params, attribute)
32
+ attribute[task_name] ||= []
33
+ Array(params).flatten.each do |param|
34
+ attribute[task_name] << param.to_s
35
+ end
36
+ end
37
+
38
+ # Return array of options that must exist in data bag
39
+ def required_data_bag_options
40
+ if @@required_data_bag_options[task_name].nil?
41
+ []
42
+ else
43
+ @@required_data_bag_options[task_name].uniq
44
+ end
45
+ end
46
+
47
+ # Helper method for returning the parameters defined for type
48
+ #
49
+ # type - String type of parameter (ex. :string or :integer)
50
+ #
51
+ # Returns array
52
+ def defined_params
53
+ if @@data_bag_params[task_name].nil?
54
+ []
55
+ else
56
+ @@data_bag_params[task_name].uniq
57
+ end
58
+ end
59
+
60
+ end
61
+
62
+ # Call the class method for the vale
63
+ def required_data_bag_options
64
+ self.class.required_data_bag_options
65
+ end
66
+
67
+ # Build a hash containing only the type (integer, string) parameters that exist in
68
+ # the data bag, coerced to their expected type
69
+ #
70
+ # type - Sym, name of type (:integer, :string)
71
+ #
72
+ # Returns hash
73
+ def defined_params
74
+ values = {}
75
+ self.class.defined_params.each do |k|
76
+ v = data_bag_item[k]
77
+ next if v.nil?
78
+ values[k.to_sym] = v
79
+ end
80
+ values
81
+ end
82
+
83
+ # Data bag assertion. Calls all boilerplate data bag assertions
84
+ def assert_data_bag_item_valid!
85
+ assert_data_bag_exists!
86
+ assert_data_bag_item_exists!
87
+ assert_required_data_bag_options_present!
88
+ end
89
+
90
+ # Report error and quit unless defined required parameters exits in data bag item
91
+ def assert_required_data_bag_options_present!
92
+ required_data_bag_options.each do |opt|
93
+ unless data_bag_item[opt]
94
+ ui.fatal("Missing option #{opt} for #{data_bag_item_name}")
95
+ exit 1
96
+ end
97
+ end
98
+ end
99
+
100
+ # Report error and quit unless data bag item exists
101
+ def assert_data_bag_item_exists!
102
+ if data_bag_item.nil?
103
+ db_item_name = "#{config[:data_bag_name]}/#{data_bag_item_name}"
104
+ ui.fatal("Cannot load data bag item #{db_item_name}")
105
+ exit 1
106
+ end
107
+ end
108
+
109
+ # Report error and quit unless data bag exists
110
+ def assert_data_bag_exists!
111
+ unless data_bag_exists?
112
+ ui.fatal("Data bag #{config[:data_bag_name]} must exist.")
113
+ exit 1
114
+ end
115
+ end
116
+
117
+ # Check if the configured RDS data bag exists on the Chef Server
118
+ #
119
+ # Returns boolean
120
+ def data_bag_exists?
121
+ begin
122
+ Chef::DataBag.load(config[:data_bag_name])
123
+ rescue Net::HTTPServerException
124
+ return false
125
+ end
126
+ true
127
+ end
128
+
129
+ # The data bag item. Uses the option name data_bag_item, and the parameter group name argument
130
+ # to load the data bag item from the server
131
+ #
132
+ # Returns Chef::DataBagItem or nil
133
+ def data_bag_item
134
+ unless @data_bag_item
135
+ begin
136
+ @data_bag_item = Chef::DataBagItem.load(config[:data_bag_name], data_bag_item_name)
137
+ rescue Net::HTTPServerException
138
+ @data_bag_item = nil
139
+ end
140
+ end
141
+ @data_bag_item
142
+ end
143
+ end
144
+ end
145
+ end