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,23 @@
1
+ require 'chef/knife/rds_base'
2
+
3
+ class Chef
4
+ class Knife
5
+ class RdsCreate < Knife
6
+
7
+ '''
8
+ Create RDS instances.
9
+ '''
10
+
11
+ include Knife::RdsBase
12
+
13
+ banner 'knife rds create (args)'
14
+
15
+ def run
16
+ authenticate!
17
+ puts "Nothign created yet, sorry!"
18
+ end
19
+
20
+
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,29 @@
1
+ require 'chef/knife/rds_base'
2
+
3
+ class Chef
4
+ class Knife
5
+ class RdsInstanceDelete < Knife
6
+
7
+ include Knife::RdsBase
8
+
9
+ banner 'knife rds instance delete INSTANCE_NAME'
10
+
11
+ def run
12
+
13
+ assert_name_args_at_least!(1, "Database identifier required.")
14
+
15
+ authenticate!
16
+
17
+ confirm("Are you sure you want to delete #{db_instance_id}")
18
+
19
+ rds.client.delete_db_instance({db_instance_identifier: db_instance_id, skip_final_snapshot: true})
20
+
21
+ end
22
+
23
+ def db_instance_id
24
+ name_args.first
25
+ end
26
+
27
+ end
28
+ end
29
+ end
@@ -0,0 +1,145 @@
1
+ require 'chef/knife/rds_base'
2
+
3
+ class Chef
4
+ class Knife
5
+ class RdsInstanceFromDataBag < Knife
6
+
7
+ include Knife::RdsBase
8
+ include Knife::RdsBaseDataBag
9
+
10
+ option :data_bag_name,
11
+ :long => '--data-bag-name DATA_BAG_NAME',
12
+ :description => 'Name of databag containing RDS instances',
13
+ :default => 'rds_instances'
14
+
15
+ require_in_data_bag :engine, :master_username, :master_user_password, :allocated_storage, :db_instance_class
16
+
17
+ define_params *[
18
+ :preferred_backup_window, :engine, :master_username, :master_user_password, :db_instance_class,
19
+ :backup_retention_period, :allocated_storage, :db_security_groups, :multi_az, :auto_minor_version_upgrade,
20
+ :db_parameter_group_name, :preferred_maintenance_window, :availability_zone, :iops, :port
21
+ ]
22
+
23
+ banner 'knife rds instance from data bag INSTANCE'
24
+
25
+ IGNORE_DIFF = [:master_user_password]
26
+
27
+ def run
28
+
29
+ assert_name_args_at_least!(1, "DB Instance identifier required")
30
+
31
+ assert_data_bag_item_valid!
32
+
33
+ authenticate!
34
+
35
+ if db_instance.nil?
36
+ ui.info("The instance #{db_instance_id} does not exit.")
37
+ confirm("Would you like to create it")
38
+ create_db_instance!
39
+ ui.info("Creating RDS instance #{db_instance_id}")
40
+ else
41
+ interrupt_unless_available!
42
+ ui.info("The instance #{db_instance_id} already exists")
43
+ confirm("Update with data bag values")
44
+ diff = generate_diff_with_data_bag
45
+ unless diff.empty?
46
+ confirm("Apply changes")
47
+ modify_db_instance!(diff)
48
+ else
49
+ ui.info("Your data bag does not contain any differences to instance.")
50
+ end
51
+ end
52
+
53
+ end
54
+
55
+ # Halt task is instance is not available
56
+ def interrupt_unless_available!
57
+ if ['creating', 'deleting'].include?(db_instance[:db_instance_status])
58
+ ui.warn("The instance is currently in the #{db_instance[:db_instance_status]} stage. Please wait until its finished.")
59
+ exit 0
60
+ end
61
+ end
62
+
63
+ def skip_parameter?(parameter)
64
+ IGNORE_DIFF.include?(parameter)
65
+ end
66
+ def generate_diff_with_data_bag
67
+ diff = {}
68
+ ui.info "Comparing #{data_bag_item_name} with data bag settings..."
69
+ defined_params.each do |k, v|
70
+ if skip_parameter?(k)
71
+ ui.info("Will not update #{k}...")
72
+ next
73
+ end
74
+ if k == :db_parameter_group_name
75
+ # DB Parameter groups returned from AWS as hash. Needs to be handled separately
76
+ groups = db_instance[:db_parameter_groups].map { |g| g[:db_parameter_group_name] }
77
+ if groups.include?(v)
78
+ ui.info "DB Parameter groups unchanged."
79
+ else
80
+ diff[:db_parameter_group_name] = v
81
+ ui.info "* #{k} differs. data bag #{v} | instance #{groups}"
82
+ end
83
+ elsif k == :db_security_groups
84
+ groups = db_instance[:db_security_groups].map { |g| g[:db_security_group_name] }
85
+ if (groups - v).empty? && (v - groups).empty?
86
+ ui.info "DB Security groups unchanged"
87
+ else
88
+ ui.info "* #{k} differs. data bag #{v} | instance #{groups.join(', ')}"
89
+ diff[:db_security_groups] = v
90
+ end
91
+ else
92
+ if v != db_instance[k]
93
+ diff[k] = v
94
+ ui.info "* #{k} differs. data bag: #{v} | instance: #{db_instance[k]}"
95
+ end
96
+ end
97
+ end
98
+ diff
99
+ end
100
+
101
+ def modify_db_instance!(diff = {})
102
+ params = {db_instance_identifier: db_instance_id}.merge(diff)
103
+ rds.client.modify_db_instance(params)
104
+ end
105
+
106
+ # Build API call using Data bag methods
107
+ def create_db_instance!
108
+ rds.client.create_db_instance(create_params)
109
+ end
110
+
111
+ def create_params
112
+ { db_instance_identifier: db_instance_id }
113
+ .merge(defined_params)
114
+ end
115
+
116
+ # Identifier for base data bag methods. Identifies the data bag item
117
+ #
118
+ # Returns stringbas
119
+ def data_bag_item_name
120
+ db_instance_id
121
+ end
122
+
123
+ # Database instance identifier
124
+ #
125
+ # Returns string
126
+ def db_instance_id
127
+ name_args.first
128
+ end
129
+
130
+ def db_instance
131
+ unless @db_instance
132
+ begin
133
+ @db_instance = rds.client.describe_db_instances(db_instance_identifier: db_instance_id)
134
+ @db_instance = @db_instance[:db_instances].first
135
+ rescue AWS::RDS::Errors::DBInstanceNotFound => e
136
+ @db_instance = nil
137
+ end
138
+ end
139
+ @db_instance
140
+ end
141
+
142
+
143
+ end
144
+ end
145
+ end
@@ -0,0 +1,49 @@
1
+ require 'chef/knife/rds_base'
2
+
3
+ class Chef
4
+ class Knife
5
+ class RdsInstanceList < Knife
6
+
7
+ '''
8
+ List RDS instances.
9
+ '''
10
+
11
+ # Key = attribute of DBInstance. Value = label to display
12
+
13
+ INSTANCE_INFO = {
14
+ id: 'ID',
15
+ status: 'Status',
16
+ db_name: 'DB Name',
17
+ engine: 'Engine',
18
+ engine_version: 'Engine Version',
19
+ iops: 'IOPS',
20
+ master_username: 'Master Username',
21
+ multi_az: 'Multi-AZ?',
22
+ endpoint_address: 'Endpoint',
23
+ created_at: 'Created At',
24
+ size: 'Size (GB)',
25
+ availability_zone_name: 'AZ',
26
+ db_instance_class: 'Instance Type',
27
+
28
+ }
29
+
30
+ include Knife::RdsBase
31
+
32
+ banner 'knife rds instance list (args)'
33
+
34
+ def run
35
+ authenticate!
36
+ rds.db_instances.each { |instance| present_instance(instance) }
37
+ end
38
+
39
+ def present_instance(instance)
40
+ ui.info "-----"
41
+ INSTANCE_INFO.each do |k, v|
42
+ ui.info("#{v} - #{instance.send(k) || 'n/a'}")
43
+ end
44
+ ui.info '-----'
45
+ end
46
+
47
+ end
48
+ end
49
+ end
@@ -0,0 +1,80 @@
1
+ require 'chef/knife/rds_base'
2
+
3
+ class Chef
4
+ class Knife
5
+ class RdsInstanceRestoreFromDataBag < Knife
6
+
7
+ include Knife::RdsBase
8
+ include Knife::RdsBaseDataBag
9
+
10
+ option :data_bag_name,
11
+ :long => '--data-bag-name DATA_BAG_NAME',
12
+ :description => 'Name of databag containing RDS instances',
13
+ :default => 'rds_instances'
14
+
15
+ banner 'knife rds instance restore from data bag DB_INSTANCE_ID DB_SNAPSHOT_ID'
16
+
17
+ define_params *[
18
+ :port, :availability_zone, :multi_az, :auto_minor_version_upgrade,
19
+ :db_name, :license_model, :iops, :engine, :option_group_name, :parameter_group_name
20
+ ]
21
+
22
+ def run
23
+
24
+ assert_name_args_at_least!(2)
25
+
26
+ assert_data_bag_item_valid!
27
+
28
+ authenticate!
29
+
30
+ ui.info("You are trying to restore snapshot #{db_snapshot_id} into instance #{db_instance_id}")
31
+
32
+ unless db_instance.nil?
33
+ ui.info("Instance #{db_instance_id} already exists!")
34
+ exit 1
35
+ end
36
+
37
+ confirm("Restore Instance #{db_instance_id} from #{db_snapshot_id}")
38
+
39
+ restore_instance!
40
+
41
+ ui.info("Restore #{db_instance_id} from #{db_snapshot_id}")
42
+
43
+ end
44
+
45
+ def restore_instance!
46
+ rds.client.restore_db_instance_from_db_snapshot(restore_params)
47
+ end
48
+
49
+ def restore_params
50
+ { db_instance_identifier: db_instance_id, db_snapshot_identifier: db_snapshot_id }
51
+ .merge(defined_params)
52
+ end
53
+
54
+ def data_bag_item_name
55
+ db_instance_id
56
+ end
57
+
58
+ def db_instance_id
59
+ name_args.first
60
+ end
61
+
62
+ def db_snapshot_id
63
+ name_args.last
64
+ end
65
+
66
+ def db_instance
67
+ unless @db_instance
68
+ begin
69
+ @db_instance = rds.client.describe_db_instances(db_instance_identifier: db_instance_id)
70
+ @db_instance = @db_instance[:db_instances].first
71
+ rescue AWS::RDS::Errors::DBInstanceNotFound => e
72
+ @db_instance = nil
73
+ end
74
+ end
75
+ @db_instance
76
+ end
77
+
78
+ end
79
+ end
80
+ end
@@ -0,0 +1,159 @@
1
+ require 'chef/knife/rds_base'
2
+
3
+ class Chef
4
+ class Knife
5
+ class RdsPgFromDataBag < Knife
6
+
7
+ '''
8
+ Create or update a parameter group from data bag configuration.
9
+ The parameter group you are creating MUST have a data bag entry on your Chef server.
10
+ The parameter group will be updated if it exists, or created if it does not.
11
+ '''
12
+
13
+ include Knife::RdsBase
14
+ include Knife::RdsBaseDataBag
15
+
16
+ option :data_bag_name,
17
+ :long => '--data-bag-name DATA_BAG_NAME',
18
+ :description => 'Name of databag containing RDS instances',
19
+ :default => 'rds_parameter_groups'
20
+
21
+ option :apply_method,
22
+ :long => '--apply-method METHOD',
23
+ :description => 'Type of apply method (immediate or pending-reboot)',
24
+ :default => 'pending-reboot'
25
+
26
+ require_in_data_bag :id, :description, :db_parameter_group_family, :parameters
27
+
28
+ banner 'knife rds pg from data_bag PG_NAME (args)'
29
+
30
+ def run
31
+
32
+ assert_name_args_at_least!(1, "Parameter group name is required!")
33
+
34
+ assert_data_bag_item_valid!
35
+
36
+ assert_valid_apply_method!
37
+
38
+ authenticate!
39
+
40
+ # Check if exists parameter groups exists. If not, ask to create, and assign parameters
41
+ if db_parameter_group.nil?
42
+ ui.info("The parameter group #{db_parameter_group_name} does not exist.")
43
+ confirm("Would you like to create it")
44
+ create_db_parameter_group!
45
+ apply_method = 'immediate'
46
+ else
47
+ ui.info("The parameter group #{db_parameter_group_name} exists.")
48
+ confirm("Would you like to update #{db_parameter_group_name} with apply method #{config[:apply_method]}")
49
+ apply_method = config[:apply_method]
50
+ end
51
+
52
+ # Reset user parameters no longer present in data bag
53
+ # Values will be rolled back to default
54
+ reset_parameters_from_db_parameter_group!(apply_method)
55
+ # Assign the parameters to the parameter group
56
+ assign_parameters_to_db_parameter_group!(apply_method)
57
+
58
+ # Success
59
+ ui.info("Assigned parameters to #{db_parameter_group_name}")
60
+ exit 0
61
+
62
+ end
63
+
64
+ # Revoke custom db parameters from this group that are not present in data bag
65
+ # Check the parameters with soure = 'user' that exist on parameter group. If they are NOT in data bag, use reset API call
66
+ # to roll back to defaults
67
+ def reset_parameters_from_db_parameter_group!(apply_method)
68
+ # Params to reset
69
+ reset_params = []
70
+ # Get user sources
71
+ user_params = rds.client.describe_db_parameters(db_parameter_group_name: db_parameter_group_name, source: 'user')
72
+ user_params[:parameters].each do |p|
73
+ param_name = p[:parameter_name]
74
+ unless data_bag_item['parameters'].keys.include?(param_name)
75
+ ui.info "Revoking #{param_name}"
76
+ reset_params << { parameter_name: param_name, apply_method: apply_method }
77
+ if reset_params.length == 20
78
+ reset_parameters_with_params!(reset_params)
79
+ reset_params = []
80
+ end
81
+ else
82
+ ui.info "Keeping #{param_name}"
83
+ end
84
+ end
85
+ reset_parameters_with_params!(reset_params) unless reset_params.empty?
86
+ end
87
+
88
+ # Reset specified parameters in parameter group back to defaults
89
+ #
90
+ # params - Array of hashes of format {method: APPLY_METHOD, name: PARAMETER_NAME}
91
+ def reset_parameters_with_params!(params = [])
92
+ rds.client.reset_db_parameter_group(db_parameter_group_name: db_parameter_group_name, parameters: params)
93
+ end
94
+
95
+ # Assigns all of data bag parameters to the parameter group
96
+ # AWS API support a maximum of 20 parameters updated in one call
97
+ def assign_parameters_to_db_parameter_group!(apply_method = 'pending-reboot')
98
+ params = []
99
+ data_bag_item['parameters'].each do |k, v|
100
+ ui.info("Assigning #{k} with value #{v}")
101
+ params << {parameter_name: k, parameter_value: v.to_s, apply_method: apply_method}
102
+ if params.length == 20
103
+ modify_db_parameter_group_with_params!(params)
104
+ params = []
105
+ end
106
+ end
107
+ modify_db_parameter_group_with_params!(params) unless params.empty?
108
+ end
109
+
110
+ # Modify the parameters of an existing RDS Parameter Group
111
+ def modify_db_parameter_group_with_params!(params = [])
112
+ begin
113
+ rds.client.modify_db_parameter_group(db_parameter_group_name: db_parameter_group_name, parameters: params)
114
+ rescue AWS::RDS::Errors::InvalidParameterValue => e
115
+ ui.error "Unable to update this batch parameter values. Please check that your parameters are correct."
116
+ ui.error "#{params.collect { |p| p[:parameter_name] }.join(', ') } not updated."
117
+ ui.error "#{e.message}"
118
+ end
119
+ end
120
+
121
+ # Create a new RDS Parameter group using the provideda data bag
122
+ def create_db_parameter_group!
123
+ rds.client.create_db_parameter_group(
124
+ db_parameter_group_name: db_parameter_group_name,
125
+ db_parameter_group_family: data_bag_item['db_parameter_group_family'],
126
+ description: data_bag_item['description']
127
+ )
128
+ end
129
+
130
+ # The name of the database parameter group, extracted from name arguments
131
+ #
132
+ # Returns string
133
+ def db_parameter_group_name
134
+ name_args.first
135
+ end
136
+
137
+ # For use with base data bag module.
138
+ def data_bag_item_name
139
+ db_parameter_group_name
140
+ end
141
+
142
+ # Load the DB Parameter Group resource from AWS using the API
143
+ #
144
+ # Returns AWS::RDS::DBParameterGroup or nil
145
+ def db_parameter_group
146
+ unless @db_parameter_group
147
+ begin
148
+ @db_parameter_group = rds.client.describe_db_parameter_groups(db_parameter_group_name: db_parameter_group_name)
149
+ rescue AWS::RDS::Errors::DBParameterGroupNotFound
150
+ @db_parameter_group = nil
151
+ end
152
+ @db_parameter_group
153
+ end
154
+ end
155
+
156
+
157
+ end
158
+ end
159
+ end