aws_one_click_staging 0.0.0 → 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: e6bd6e2d8174efa8efa1ec17c2d1e12dccc215e0
4
- data.tar.gz: bf4f9dc0df6d3f5203b11571a135886dbd38728e
3
+ metadata.gz: 90ed89f6ad179598fb6989d7655c9524305589b7
4
+ data.tar.gz: 8a8c004ddeaf405de3670debbe1501cc70321889
5
5
  SHA512:
6
- metadata.gz: b84fa130a34f92acbc686f85def227427b4a0734a2e701c239106b0ff5fbcde3e01d1d496d2b383f7970c5da800d988debc21a738605bfc11d90a7c2e56680ff
7
- data.tar.gz: d08dbed9ca05b3c0a1fd36da0675316e985bc21772c4c90a8211ee610d44d14be018d3a25911f98a5331809dab4a86e32bdc54946a994da08c9c9b34436db31a
6
+ metadata.gz: 26af7c6c981ed74c0708f87b898fb2dab81a30111e814cf88b1e1ed9b8655be48533d54fce5327c833f25fccdf43bcc1969a68aa3c9f1af87a6dc1d8f1ca26ee
7
+ data.tar.gz: 6019696f745680f4057122db72c8d99cd6193a1cb0137449773de011668ad3dccf738769a4a0d142e5150c8e821ab50c6b686c65c40dbd863220c379b3dc865c
data/.gitignore CHANGED
@@ -7,3 +7,5 @@
7
7
  /pkg/
8
8
  /spec/reports/
9
9
  /tmp/
10
+
11
+ config/aws_actual_fffing_secrets.yml
data/README.md CHANGED
@@ -16,13 +16,13 @@ Next you'll need to setup the config file:
16
16
 
17
17
  (~/.config/aws_one_click_staging.yml)
18
18
  ```
19
- aws_access_key_id: ''
20
- aws_secret_access_key: ''
19
+ aws_access_key_id: ""
20
+ aws_secret_access_key: ""
21
21
  aws_region: 'us-west-1'
22
- aws_bucket: ''
23
- db_host: ''
24
- db_port: '5432'
25
- db_password: ''
22
+ aws_master_username: ""
23
+ aws_master_user_password: ""
24
+ aws_production_bucket: "" # this bucket is read from
25
+ aws_staging_bucket: "" # this bucket is DELETED and written to!
26
26
  ```
27
27
 
28
28
 
@@ -31,7 +31,7 @@ db_password: ''
31
31
  Because amazon services are kind of a mess right now, it's best to run this from on an actual Amazon server you have shell access to (it downloads the bucket files and then re-uploads them, lol).
32
32
 
33
33
  ```
34
- aws_one_click_staging stage
34
+ aws_one_click_staging stage
35
35
  ```
36
36
 
37
37
  After a while, the operation will complete and it will say 'congrats' or something and output the RDS url and bucket name for the staging clone. Plug those values into your staging server and you should be good to go.
@@ -14,11 +14,13 @@ Gem::Specification.new do |spec|
14
14
  # spec.license = "MIT" # uncomment this line if MIT is the best license for your situation
15
15
 
16
16
  spec.files = `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
17
- spec.bindir = "exe"
17
+ spec.bindir = "bin"
18
18
  spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
19
19
  spec.require_paths = ["lib"]
20
20
 
21
+ spec.add_dependency 'aws-sdk', '~> 2'
21
22
  spec.add_dependency "aws-sdk-v1"
23
+ spec.add_dependency "thor"
22
24
 
23
25
  spec.add_development_dependency "bundler", "~> 1.10"
24
26
  spec.add_development_dependency "rake", "~> 10.0"
@@ -1,3 +1,28 @@
1
1
  #!/usr/bin/env ruby
2
2
 
3
+ require 'thor'
3
4
  require "aws_one_click_staging"
5
+
6
+ class AwsOneClickStagingRunner < Thor
7
+
8
+ default_task :start
9
+
10
+ desc "list", "Shows help"
11
+ def list
12
+ AwsOneClickStaging.list
13
+ end
14
+
15
+ desc "stage", "Makes a copy of the RDS database and the staging server's S3 bucket. This takes a while."
16
+ def stage
17
+ AwsOneClickStaging.stage(421)
18
+ end
19
+
20
+ desc "version", "Prints gem's version"
21
+ def version
22
+ AwsOneClickStaging::VERSION
23
+ end
24
+ map %w(-v --version) => :version
25
+
26
+ end
27
+
28
+ AwsOneClickStagingRunner.start
@@ -0,0 +1,9 @@
1
+ # edit these values to match that of your production machine
2
+ # which will be cloned from
3
+ aws_access_key_id: ""
4
+ aws_secret_access_key: ""
5
+ aws_region: 'us-west-1'
6
+ aws_master_username: ""
7
+ aws_master_user_password: ""
8
+ aws_production_bucket: "" # this bucket is read from
9
+ aws_staging_bucket: "" # this bucket is DELETED and written to!
@@ -1,5 +1,18 @@
1
+ require 'aws_one_click_staging/bucket_sync_service'
2
+ require "aws_one_click_staging/aws_warrior"
1
3
  require "aws_one_click_staging/version"
2
4
 
5
+ SOURCE_ROOT = File.expand_path("#{File.dirname(__FILE__)}/..")
6
+
3
7
  module AwsOneClickStaging
4
- # Your code goes here...
8
+
9
+ def self.stage
10
+ warrior = AwsWarrior.new
11
+ end
12
+
13
+ def self.list
14
+ warrior = AwsWarrior.new # this makes a config file if needed
15
+ puts "This is aws_one_click_staging, use stage to set things up"
16
+ end
17
+
5
18
  end
@@ -0,0 +1,139 @@
1
+ require 'fileutils'
2
+ require 'aws-sdk'
3
+ require 'yaml'
4
+
5
+ module AwsOneClickStaging
6
+
7
+ class AwsWarrior
8
+
9
+ def initialize
10
+ # read config file
11
+ @config_dir = "#{ENV['HOME']}/.config"
12
+ @config_file = File.expand_path("#{@config_dir}/aws_one_click_staging.yml")
13
+ @config = YAML.load(read_config_file)
14
+ end
15
+
16
+ def clone_rds
17
+ setup_aws_credentials
18
+
19
+ @db_instance_id_production = "actioncenter-staging"
20
+ @db_instance_id_staging = "actioncenter-staging-test"
21
+ @db_snapshot_id = "actioncenter-snapshot-for-staging"
22
+
23
+ @c = Aws::RDS::Client.new
24
+
25
+ delete_snapshot_for_staging!
26
+ create_new_snapshot_for_staging!
27
+
28
+ delete_staging_db_instance!
29
+ spawn_new_staging_db_instance!
30
+ end
31
+
32
+ def clone_s3_bucket
33
+ setup_aws_credentials
34
+
35
+ from_creds = { aws_access_key_id: @access_key_id,
36
+ aws_secret_access_key: @secret_access_key,
37
+ bucket: @aws_production_bucket}
38
+ to_creds = { aws_access_key_id: @access_key_id,
39
+ aws_secret_access_key: @secret_access_key,
40
+ bucket: @aws_staging_bucket}
41
+
42
+ bs = BucketSyncService.new(from_creds, to_creds)
43
+
44
+ bs.perform
45
+ end
46
+
47
+
48
+ private
49
+
50
+ def setup_aws_credentials
51
+ @config[""]
52
+ aws_region = @config["aws_region"]
53
+ @access_key_id = @config["aws_access_key_id"]
54
+ @secret_access_key = @config["aws_secret_access_key"]
55
+ @master_username = @config["aws_master_username"]
56
+ @master_user_password = @config["aws_master_user_password"]
57
+ @aws_production_bucket = @config["aws_production_bucket"]
58
+ @aws_staging_bucket = @config["aws_staging_bucket"]
59
+
60
+ Aws.config.update({ region: aws_region,
61
+ credentials: Aws::Credentials.new(@access_key_id, @secret_access_key) })
62
+ end
63
+
64
+ def delete_snapshot_for_staging!
65
+ puts "deleting old staging db snapshot"
66
+ response = @c.delete_db_snapshot(db_snapshot_identifier: @db_snapshot_id)
67
+
68
+ sleep 1 while response.percent_progress != 100
69
+ true
70
+ rescue
71
+ false
72
+ end
73
+
74
+ def create_new_snapshot_for_staging!
75
+ puts "creating new snapshot... this takes like 70 seconds..."
76
+ response = @c.create_db_snapshot({db_instance_identifier: @db_instance_id_production,
77
+ db_snapshot_identifier: @db_snapshot_id })
78
+
79
+ sleep 10 while get_fresh_db_snapshot_state.status != "available"
80
+ true
81
+ rescue
82
+ false
83
+ end
84
+
85
+
86
+ def delete_staging_db_instance!
87
+ response = @c.delete_db_instance(db_instance_identifier: @db_instance_id_staging)
88
+
89
+ sleep 2 while response.percent_progress != 100
90
+ rescue
91
+ false
92
+ end
93
+
94
+ def spawn_new_staging_db_instance!
95
+ response = @c.create_db_instance(db_instance_identifier: @db_instance_id_staging,
96
+ db_instance_class: "db.t1.micro",
97
+ engine: "postgres",
98
+ master_username: @master_username,
99
+ master_user_password: @master_user_password,
100
+ allocated_storage: "10")
101
+
102
+ sleep 10 while get_fresh_db_instance_state.db_instance_status != "available"
103
+ end
104
+
105
+
106
+ # we use this methods cause amazon lawl-pain
107
+ def get_fresh_db_snapshot_state
108
+ @c.describe_db_snapshots(db_snapshot_identifier: @db_snapshot_id).db_snapshots.first
109
+ end
110
+
111
+ def get_fresh_db_instance_state
112
+ @c.describe_db_instances(db_instance_identifier: @db_instance_id_staging).db_instances.first
113
+ end
114
+
115
+
116
+ def read_config_file
117
+ return if create_config_file_if_needed!
118
+ config = File.read(@config_file)
119
+ end
120
+
121
+ def create_config_file_if_needed!
122
+ return false if File.exists?(@config_file)
123
+ msg = ""
124
+ msg += "Config file not found, creating...\n\n"
125
+
126
+ # copy example config file to config file path
127
+ FileUtils.mkdir_p @config_dir
128
+ FileUtils.cp("#{SOURCE_ROOT}/config/aws_one_click_staging.yml", @config_file)
129
+
130
+ msg += "An empty config file was created for you in #{@config_file}\n"
131
+ msg += "Please populate it with the correct information and run this \n"
132
+ msg += "command again. \n"
133
+
134
+ true
135
+ end
136
+
137
+ end
138
+
139
+ end
@@ -0,0 +1,85 @@
1
+ # props to bantic
2
+ # https://gist.github.com/bantic/4080793
3
+ require 'aws/s3' # gem name is 'aws-sdk'
4
+
5
+ class BucketSyncService
6
+ attr_reader :from_bucket, :to_bucket, :logger
7
+ attr_accessor :debug
8
+
9
+ DEFAULT_ACL = :public_read
10
+
11
+ # from_credentials and to_credentials are both hashes with these keys:
12
+ # * :aws_access_key_id
13
+ # * :aws_secret_access_key
14
+ # * :bucket
15
+ def initialize(from_credentials, to_credentials)
16
+ @from_bucket = bucket_from_credentials(from_credentials)
17
+ @to_bucket = bucket_from_credentials(to_credentials)
18
+ end
19
+
20
+ def perform(output=STDOUT)
21
+ object_counts = {sync:0, skip:0}
22
+ create_logger(output)
23
+
24
+ logger.info "Starting sync."
25
+ from_bucket.objects.each do |object|
26
+ if object_needs_syncing?(object)
27
+ sync(object)
28
+ object_counts[:sync] += 1
29
+ else
30
+ logger.debug "Skipped #{pp object}"
31
+ object_counts[:skip] += 1
32
+ end
33
+ end
34
+ logger.info "Done. Synced #{object_counts[:sync]}, " +
35
+ "skipped #{object_counts[:skip]}."
36
+ end
37
+
38
+ private
39
+
40
+ def create_logger(output)
41
+ @logger = Logger.new(output).tap do |l|
42
+ l.level = debug ? Logger::DEBUG : Logger::INFO
43
+ end
44
+ end
45
+
46
+ def sync(object)
47
+ logger.debug "Syncing #{pp object}"
48
+ object.copy_to( to_bucket.objects[object.key], acl:DEFAULT_ACL)
49
+ end
50
+
51
+ def pp(object)
52
+ content_length_in_kb = object.content_length / 1024
53
+ "#{object.key} #{content_length_in_kb}k " +
54
+ "#{object.last_modified.strftime("%b %d %Y %H:%M")}"
55
+ end
56
+
57
+ def object_needs_syncing?(object)
58
+ to_object = to_bucket.objects[object.key]
59
+ return true if !to_object.exists?
60
+
61
+ return to_object.etag != object.etag
62
+ end
63
+
64
+ def bucket_from_credentials(credentials)
65
+ s3 = AWS::S3.new(access_key_id: credentials[:aws_access_key_id],
66
+ secret_access_key: credentials[:aws_secret_access_key])
67
+
68
+ bucket = s3.buckets[ credentials[:bucket] ]
69
+ if !bucket.exists?
70
+ bucket = s3.buckets.create( credentials[:bucket] )
71
+ end
72
+ bucket
73
+ end
74
+ end
75
+
76
+
77
+
78
+ =begin
79
+ Example usage:
80
+ from_creds = {aws_access_key_id:"XXX", aws_secret_access_key:"YYY", bucket:"first-bucket"}
81
+ to_creds = {aws_access_key_id:"ZZZ", aws_secret_access_key:"AAA", bucket:"second-bucket"}
82
+ syncer = BucketSyncService.new(from_creds, to_creds)
83
+ syncer.debug = true # log each object
84
+ syncer.perform
85
+ =end
@@ -1,3 +1,3 @@
1
1
  module AwsOneClickStaging
2
- VERSION = "0.0.0"
2
+ VERSION = "0.0.1"
3
3
  end
metadata CHANGED
@@ -1,15 +1,29 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: aws_one_click_staging
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.0
4
+ version: 0.0.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - TheNotary
8
8
  autorequire:
9
- bindir: exe
9
+ bindir: bin
10
10
  cert_chain: []
11
- date: 2015-11-23 00:00:00.000000000 Z
11
+ date: 2015-11-26 00:00:00.000000000 Z
12
12
  dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: aws-sdk
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '2'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '2'
13
27
  - !ruby/object:Gem::Dependency
14
28
  name: aws-sdk-v1
15
29
  requirement: !ruby/object:Gem::Requirement
@@ -24,6 +38,20 @@ dependencies:
24
38
  - - ">="
25
39
  - !ruby/object:Gem::Version
26
40
  version: '0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: thor
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - ">="
46
+ - !ruby/object:Gem::Version
47
+ version: '0'
48
+ type: :runtime
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - ">="
53
+ - !ruby/object:Gem::Version
54
+ version: '0'
27
55
  - !ruby/object:Gem::Dependency
28
56
  name: bundler
29
57
  requirement: !ruby/object:Gem::Requirement
@@ -96,9 +124,11 @@ files:
96
124
  - Rakefile
97
125
  - aws_one_click_staging.gemspec
98
126
  - bin/aws_one_click_staging
99
- - bin/console
100
127
  - changelog
128
+ - config/aws_one_click_staging.yml
101
129
  - lib/aws_one_click_staging.rb
130
+ - lib/aws_one_click_staging/aws_warrior.rb
131
+ - lib/aws_one_click_staging/bucket_sync_service.rb
102
132
  - lib/aws_one_click_staging/version.rb
103
133
  - rspec
104
134
  homepage: https://github.com/TheNotary/aws_one_click_staging
@@ -1,14 +0,0 @@
1
- #!/usr/bin/env ruby
2
-
3
- require "bundler/setup"
4
- require "aws_one_click_staging"
5
-
6
- # You can add fixtures and/or initialization code here to make experimenting
7
- # with your gem easier. You can also use a different console, if you like.
8
-
9
- # (If you use this, don't forget to add pry to your Gemfile!)
10
- # require "pry"
11
- # Pry.start
12
-
13
- require "irb"
14
- IRB.start