knife-rds 0.0.1

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