clusterfsck 0.1.5.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (38) hide show
  1. data/.gitignore +19 -0
  2. data/.rspec +2 -0
  3. data/.rvmrc +1 -0
  4. data/Gemfile +12 -0
  5. data/Guardfile +24 -0
  6. data/LICENSE.txt +22 -0
  7. data/README.md +121 -0
  8. data/Rakefile +10 -0
  9. data/bin/clusterfsck +60 -0
  10. data/clusterfsck.gemspec +34 -0
  11. data/lib/clusterfsck.rb +48 -0
  12. data/lib/clusterfsck/cli.rb +8 -0
  13. data/lib/clusterfsck/commands/cluster_fsck_env_argument_parser.rb +21 -0
  14. data/lib/clusterfsck/commands/create.rb +20 -0
  15. data/lib/clusterfsck/commands/edit.rb +30 -0
  16. data/lib/clusterfsck/commands/environments.rb +14 -0
  17. data/lib/clusterfsck/commands/list.rb +20 -0
  18. data/lib/clusterfsck/commands/override.rb +27 -0
  19. data/lib/clusterfsck/commands/setup.rb +11 -0
  20. data/lib/clusterfsck/configuration.rb +13 -0
  21. data/lib/clusterfsck/credential_grabber.rb +53 -0
  22. data/lib/clusterfsck/reader.rb +56 -0
  23. data/lib/clusterfsck/s3_methods.rb +52 -0
  24. data/lib/clusterfsck/setup.rb +51 -0
  25. data/lib/clusterfsck/version.rb +3 -0
  26. data/lib/clusterfsck/writer.rb +30 -0
  27. data/spec/lib/clusterfsck/commands/amicus_env_argument_parser_spec.rb +26 -0
  28. data/spec/lib/clusterfsck/commands/create_spec.rb +41 -0
  29. data/spec/lib/clusterfsck/commands/edit_spec.rb +49 -0
  30. data/spec/lib/clusterfsck/commands/override_spec.rb +26 -0
  31. data/spec/lib/clusterfsck/configuration_spec.rb +25 -0
  32. data/spec/lib/clusterfsck/credential_grabber_spec.rb +100 -0
  33. data/spec/lib/clusterfsck/reader_spec.rb +60 -0
  34. data/spec/lib/clusterfsck/s3_methods_spec.rb +39 -0
  35. data/spec/lib/clusterfsck/writer_spec.rb +84 -0
  36. data/spec/spec_helper.rb +24 -0
  37. data/spec/support/cluster_fsck_env_setter.rb +11 -0
  38. metadata +177 -0
@@ -0,0 +1,19 @@
1
+ *.gem
2
+ *.rbc
3
+ .bundle
4
+ .config
5
+ .yardoc
6
+ Gemfile.lock
7
+ InstalledFiles
8
+ _yardoc
9
+ coverage
10
+ lib/bundler/man
11
+ pkg
12
+ rdoc
13
+ spec/reports
14
+ test/tmp
15
+ test/version_tmp
16
+ tmp
17
+ .idea
18
+ .DS_Store
19
+
data/.rspec ADDED
@@ -0,0 +1,2 @@
1
+ --color
2
+ --format progress
data/.rvmrc ADDED
@@ -0,0 +1 @@
1
+ rvm 1.9.3@clusterfsck --create
data/Gemfile ADDED
@@ -0,0 +1,12 @@
1
+ source 'http://rubygems.org'
2
+
3
+ gemspec
4
+
5
+ group :test do
6
+ gem 'guard-rspec'
7
+ gem 'rb-fsevent', '~> 0.9.1'
8
+ gem 'rake'
9
+ gem 'fakes3'
10
+ gem 'pry'
11
+ gem 'ci_reporter', '~> 1.7.3'
12
+ end
@@ -0,0 +1,24 @@
1
+ # A sample Guardfile
2
+ # More info at https://github.com/guard/guard#readme
3
+
4
+ guard 'rspec' do
5
+ watch(%r{^spec/.+_spec\.rb$})
6
+ watch(%r{^lib/(.+)\.rb$}) { |m| "spec/lib/#{m[1]}_spec.rb" }
7
+ watch('spec/spec_helper.rb') { "spec" }
8
+
9
+ # Rails example
10
+ watch(%r{^app/(.+)\.rb$}) { |m| "spec/#{m[1]}_spec.rb" }
11
+ watch(%r{^app/(.*)(\.erb|\.haml)$}) { |m| "spec/#{m[1]}#{m[2]}_spec.rb" }
12
+ watch(%r{^app/controllers/(.+)_(controller)\.rb$}) { |m| ["spec/routing/#{m[1]}_routing_spec.rb", "spec/#{m[2]}s/#{m[1]}_#{m[2]}_spec.rb", "spec/acceptance/#{m[1]}_spec.rb"] }
13
+ watch(%r{^spec/support/(.+)\.rb$}) { "spec" }
14
+ watch('config/routes.rb') { "spec/routing" }
15
+ watch('app/controllers/application_controller.rb') { "spec/controllers" }
16
+
17
+ # Capybara features specs
18
+ watch(%r{^app/views/(.+)/.*\.(erb|haml)$}) { |m| "spec/features/#{m[1]}_spec.rb" }
19
+
20
+ # Turnip features and steps
21
+ watch(%r{^spec/acceptance/(.+)\.feature$})
22
+ watch(%r{^spec/acceptance/steps/(.+)_steps\.rb$}) { |m| Dir[File.join("**/#{m[1]}.feature")][0] || 'spec/acceptance' }
23
+ end
24
+
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2012 Topper Bowers
2
+
3
+ MIT License
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining
6
+ a copy of this software and associated documentation files (the
7
+ "Software"), to deal in the Software without restriction, including
8
+ without limitation the rights to use, copy, modify, merge, publish,
9
+ distribute, sublicense, and/or sell copies of the Software, and to
10
+ permit persons to whom the Software is furnished to do so, subject to
11
+ the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -0,0 +1,121 @@
1
+ # ClusterFsck
2
+
3
+ ClusterFsck manages configuration across any number of projects or servers by reading and writing simple YAML stored on Amazon S3. It also allows overriding these configs locally through files (e.g. so your tests don't need network).
4
+
5
+ (not tested on windows, patches accepted)
6
+
7
+ ## Installation
8
+
9
+ Add this line to your application's Gemfile:
10
+
11
+ gem 'clusterfsck'
12
+
13
+ And then execute:
14
+
15
+ $ bundle
16
+
17
+ Or install it yourself as:
18
+
19
+ $ gem install clusterfsck
20
+
21
+
22
+ ## Configuration & Setup
23
+
24
+ #### From the command line
25
+ Type `clusterfsck init` to initiate ClusterFsck's setup assistant, or manually create a YAML file called `.clusterfsck` in your user's home directory or the root of your project with a `cluster_fsck_bucket` key set to the name of the bucket you want to use to store configuration. ClusterFsck will also need your aws credentials. Store those in the .clusterfsck file or pass those in using environment variables. In production, we recommend you use [IAM role-based access](http://aws.typepad.com/aws/2012/06/iam-roles-for-ec2-instances-simplified-secure-access-to-aws-service-apis-from-ec2.html).
26
+
27
+ Now, you can run `clusterfsck new <config name>` to create your first clusterfsck managed configuration. It will automatically call the clusterfsck edit command for you. Future edits should be done with `clusterfsck edit <config name>`, using the editor defined in `$EDITOR`. It raises an error if no config name is provided. See Usage below for accessing the config from code.
28
+
29
+ Like Rails, clusterfsck defaults `CLUSTER_FSCK_ENV` to `development` but the environment can be set to any string. There is one 'special' environment `shared` that is where default configs are stored. If a config does not exist in the environment you request it, then clusterfsck will look in the shared environment and only if it does *not* exist, will it error.
30
+
31
+ For example:
32
+ `$> clusterfsck edit shared myconfig`
33
+ edit... edit... edit...
34
+ ```ruby
35
+ ENV['CLUSTERFSCK_ENV'] = 'production'
36
+ ClusterFsck::Reader.new(:myconfig).read #will be anything you set in the shared myconfig
37
+ ```
38
+
39
+ The command line client also provides several additional commands, including list, which lists config files in the current or specified `list`, and `override` which will copy down the files for the environment, and use those local files in place of the S3 based configuration. You can use this option to develop locally without internet access. In general, the command line uses the default environment, but allows specifying an environment as the first argument.
40
+
41
+ You can run `clusterfsck --help` to get usage, currently that outputs as follows:
42
+
43
+ `$> clusterfsck --help`
44
+ ```bash
45
+ NAME:
46
+
47
+ clusterfsck
48
+
49
+ DESCRIPTION:
50
+
51
+ Filebased S3 Cofiguration Kontrol for Clusters, by Amicus
52
+
53
+ COMMANDS:
54
+
55
+ edit Bring up the YAML for key specified in the current CLUSTER_FSCK_ENV or specified CLUSTER_FSCK_ENV in your $editor
56
+ environments List all environments defined in the bucket ClusterFsck is setup using
57
+ help Display global or [command] help documentation.
58
+ init Create ClusterFsck configuration file - called automatically from other commands if no config found.
59
+ list List all keys in the current or specified CLUSTER_FSCK_ENV
60
+ new Create a yaml file for your current CLUSTER_FSCK_ENV or specified CLUSTER_FSCK_ENV
61
+ override Will copy down the remote config and create a directory clusterfsck/:CLUSTER_FSCK_ENV/:key that will be used by default over the remote
62
+
63
+ GLOBAL OPTIONS:
64
+
65
+ -h, --help
66
+ Display help documentation
67
+
68
+ -v, --version
69
+ Display version information
70
+
71
+ -t, --trace
72
+ Display backtrace when an error occurs
73
+ ```
74
+
75
+ Please help us improve this documentation. Pull requests or feedback are very appreciated!
76
+
77
+ ## Usage
78
+
79
+ ### setup your credential file
80
+ You should probably run automated setup as a first step, but ClusterFsck checks for all its settings first in
81
+ ENV variables as below. For AWS keys, both access and secret keys must be defined or neither will be used (which is awesome in production, use IAM roles!):
82
+
83
+ You may also define ClusterFsck's configuration using environment variables:
84
+ ```bash
85
+ ENV['CLUSTER_FSCK_BUCKET']
86
+ ENV['CLUSTER_FSCK_ENV']
87
+ ENV['AWS_ACCESS_KEY_ID']
88
+ ENV['AWS_SECRET_ACCESS_KEY']
89
+ ```
90
+
91
+ After checking ENV variables, clusterfsck will look in './.clusterfsck','/usr/clusterfsck', or '~/.clusterfsck'] for the following yaml.
92
+
93
+ ```yaml
94
+ :aws_access_key_id: access_key
95
+ :aws_secret_access_key: secret_key
96
+ :cluster_fsck_bucket: bucket_name
97
+ :cluster_fsck_env: environment //probably development, production, staging or shared
98
+ ```
99
+
100
+ If you do not define AWS in the environment variables, or the .clusterfsck file, then clusterfsck will check in a ~/.fog file for something that looks like this:
101
+
102
+ ```yaml
103
+ :default:
104
+ :aws_access_key_id: access_key
105
+ :aws_secret_access_key: secret_key
106
+ ```
107
+
108
+ ### From Code
109
+
110
+ ```ruby
111
+ reader = ClusterFsck::Reader.new(:stripe)
112
+ reader.read[:api_key] # loads config_bucket/cluster_fsck_env/stripe and returns the api_key from the hash
113
+ ```
114
+
115
+ The ClusterFsck::Reader instance will load the configuration for the environment stored in the CLUSTER_FSCK_ENV.
116
+
117
+ 1. Fork it
118
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
119
+ 3. Commit your changes (`git commit -am 'Add some feature'`)
120
+ 4. Push to the branch (`git push origin my-new-feature`)
121
+ 5. Create new Pull Request
@@ -0,0 +1,10 @@
1
+ require "bundler/gem_tasks"
2
+ require 'rspec/core/rake_task'
3
+
4
+ RSpec::Core::RakeTask.new(:spec)
5
+
6
+ begin
7
+ require 'ci/reporter/rake/rspec'
8
+ rescue LoadError => ex
9
+ puts "Failed to load the ci_reporter gem. Make sure it is available in your loadpaths"
10
+ end
@@ -0,0 +1,60 @@
1
+ #!/usr/bin/env ruby
2
+ require 'commander/import'
3
+
4
+ $LOAD_PATH.unshift(File.join(File.expand_path(File.dirname(__FILE__)), "../lib"))
5
+ require "clusterfsck/cli"
6
+
7
+ program :version, ClusterFsck::VERSION
8
+ program :description, 'Filebased S3 Cofiguration Kontrol for Clusters, by Amicus'
9
+
10
+ #TODO: (topper) - fill in the help stuff
11
+
12
+ command :'init' do |c|
13
+ c.syntax = 'clusterfsck init'
14
+ c.summary = 'Create ClusterFsck configuration file - called automatically from other commands if no config found.'
15
+ c.description = 'clusterfsck init'
16
+ c.when_called ClusterFsck::Commands::Setup, :run_command
17
+ end
18
+
19
+ command :edit do |c|
20
+ c.syntax = 'clusterfsck edit [options]'
21
+ c.summary = 'Bring up the YAML for key specified in the current CLUSTER_FSCK_ENV or specified CLUSTER_FSCK_ENV in your $editor'
22
+ c.description = 'clusterfsck edit [cluster_fsck_env] key'
23
+ c.example 'edit stripe in current CLUSTER_FSCK_ENV', 'clusterfsck edit stripe'
24
+ c.example 'edit stripe in staging CLUSTER_FSCK_ENV', 'clusterfsck edit staging stripe'
25
+ c.option '--force', 'force edit even if local file override present'
26
+ c.when_called ClusterFsck::Commands::Edit, :run_command
27
+ end
28
+
29
+ command :new do |c|
30
+ c.syntax = 'clusterfsck new [options]'
31
+ c.summary = 'Create a yaml file for your current CLUSTER_FSCK_ENV or specified CLUSTER_FSCK_ENV'
32
+ c.description = 'clusterfsck new [cluster_fsck_env] key'
33
+ c.example 'create stripe key in current CLUSTER_FSCK_ENV', 'clusterfsck new stripe'
34
+ c.example 'create stripe key in staging CLUSTER_FSCK_ENV', 'clusterfsck new staging stripe'
35
+ c.when_called ClusterFsck::Commands::Create, :run_command
36
+ end
37
+
38
+ command :list do |c|
39
+ c.syntax = 'clusterfsck list'
40
+ c.summary = 'List all keys in the current or specified CLUSTER_FSCK_ENV'
41
+ c.description = 'clusterfsck list [cluster_fsck_env]'
42
+ c.example 'list keys in staging CLUSTER_FSCK_ENV', 'clusterfsck list staging'
43
+ c.when_called ClusterFsck::Commands::List, :run_command
44
+ end
45
+
46
+ command :environments do |c|
47
+ c.syntax = 'clusterfsck environments'
48
+ c.summary = 'List all environments defined in the bucket ClusterFsck is setup using'
49
+ c.description = 'clusterfsck environments [cluster_fsck_env]'
50
+ c.example 'list all environments defined', 'clusterfsck environments'
51
+ c.when_called ClusterFsck::Commands::Environments, :run_command
52
+ end
53
+
54
+ command :override do |c|
55
+ c.syntax = 'clusterfsck override [options]'
56
+ c.summary = 'Will copy down the remote config and create a directory clusterfsck/:CLUSTER_FSCK_ENV/:key that will be used by default over the remote'
57
+ c.description = ''
58
+ c.example 'override the staging stripe key in this working directory', 'clusterfsck override staging stripe'
59
+ c.when_called ClusterFsck::Commands::Override, :run_command
60
+ end
@@ -0,0 +1,34 @@
1
+ # -*- encoding: utf-8 -*-
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'clusterfsck/version'
5
+
6
+ Gem::Specification.new do |gem|
7
+ gem.name = "clusterfsck"
8
+ gem.version = ClusterFsck::VERSION
9
+ gem.authors = ["Topper Bowers, Brian Glusman"]
10
+ gem.email = ["topper@amicushq.com, brian@amicushq.com"]
11
+ gem.description = "cluster-aware S3 based config getter/setter"
12
+ gem.summary = %Q{
13
+ ClusterFsck manages configurable settings and sensitive login information
14
+ across any number of separate or related projects by reading writing simple
15
+ values or arrays/hashes of data to and from YAML files stored on Amazon S3.
16
+ It also allows centrally overriding or changing these on a per environment
17
+ basis.
18
+ }
19
+ gem.homepage = "http://github.com/amicus/clusterfsck"
20
+
21
+ # we need a big version here, because we rely on a change made in january
22
+ # that was breaking EC2 provider credentials
23
+ gem.add_dependency "aws-sdk", "~> 1.8.1.2"
24
+ gem.add_dependency "hashie"
25
+ gem.add_dependency "random-word"
26
+ gem.add_dependency "commander", "~> 4.1.0"
27
+
28
+ gem.add_development_dependency "rspec"
29
+
30
+ gem.files = `git ls-files`.split($/)
31
+ gem.executables = gem.files.grep(%r{^bin/}).map{ |f| File.basename(f) }
32
+ gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
33
+ gem.require_paths = ["lib"]
34
+ end
@@ -0,0 +1,48 @@
1
+ require 'clusterfsck/version'
2
+ require 'clusterfsck/setup'
3
+ require 'yaml'
4
+ require 'aws-sdk'
5
+ require 'hashie'
6
+ require 'random-word'
7
+ require 'commander'
8
+
9
+ module ClusterFsck
10
+ CLUSTER_FSCK_PATHS = ['./.clusterfsck','/usr/clusterfsck','~/.clusterfsck']
11
+
12
+ CLUSTER_FSCK_CONFIG = CLUSTER_FSCK_PATHS.map do |path_string|
13
+ path = File.expand_path(path_string)
14
+ YAML.load_file(path) if File.exists?(path)
15
+ end.compact.first || {}
16
+
17
+ def self.logger=(logger)
18
+ @logger = logger
19
+ end
20
+
21
+ def self.logger
22
+ @logger ||= Logger.new($stdout)
23
+ end
24
+
25
+ def self.cluster_fsck_env
26
+ raise "Configuration failure, check ~/.clusterfsck or other config values" unless config_bucket
27
+ @env ||= ENV['CLUSTER_FSCK_ENV'] || CLUSTER_FSCK_CONFIG['cluster_fsck_env'] || default_env
28
+ end
29
+
30
+ def self.config_bucket
31
+ @config_bucket ||= ENV['CLUSTER_FSCK_BUCKET'] || CLUSTER_FSCK_CONFIG['cluster_fsck_bucket'] || Setup.config
32
+ end
33
+
34
+ def self.default_env
35
+ ENV['CLUSTER_FSCK_ENV'] || 'development'
36
+ end
37
+
38
+ def self.config_hash
39
+ CLUSTER_FSCK_CONFIG
40
+ end
41
+
42
+ end
43
+
44
+ require 'clusterfsck/credential_grabber'
45
+ require 'clusterfsck/s3_methods'
46
+ require 'clusterfsck/configuration'
47
+ require 'clusterfsck/reader'
48
+ require 'clusterfsck/writer'
@@ -0,0 +1,8 @@
1
+ require_relative "../clusterfsck"
2
+ require_relative "commands/cluster_fsck_env_argument_parser"
3
+ require_relative "commands/edit"
4
+ require_relative "commands/create"
5
+ require_relative "commands/list"
6
+ require_relative "commands/override"
7
+ require_relative "commands/setup"
8
+ require_relative "commands/environments"
@@ -0,0 +1,21 @@
1
+ module ClusterFsck
2
+ module Commands
3
+ module ClusterFsckEnvArgumentParser
4
+
5
+ def self.included(base)
6
+ base.send(:attr_reader, :key) unless base.respond_to?(:reader_key)
7
+ base.send(:include, ClusterFsck::S3Methods)
8
+ end
9
+
10
+ def set_cluster_fsck_env_and_key_from_args(args)
11
+ if args.length > 1
12
+ @cluster_fsck_env, @key = args
13
+ else
14
+ @key = args.first
15
+ end
16
+ end
17
+
18
+
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,20 @@
1
+ require 'commander'
2
+ require_relative "edit"
3
+
4
+ module ClusterFsck
5
+ module Commands
6
+ class Create
7
+ include ClusterFsckEnvArgumentParser
8
+
9
+ def run_command(args, options = {})
10
+ raise ArgumentError, "must provide a project name" if args.empty?
11
+ set_cluster_fsck_env_and_key_from_args(args)
12
+ obj = s3_object(key)
13
+ raise ConflictError, "#{key} already exists!" if obj.exists?
14
+ obj.write('')
15
+ Edit.new.run_command(args)
16
+ end
17
+
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,30 @@
1
+ require 'commander'
2
+
3
+ module ClusterFsck
4
+ module Commands
5
+ class Edit
6
+ include Commander::UI
7
+ include ClusterFsckEnvArgumentParser
8
+
9
+ def run_command(args, options = Hashie::Mash.new)
10
+ raise ArgumentError, "must provide a project name" if args.empty?
11
+ set_cluster_fsck_env_and_key_from_args(args)
12
+
13
+ @options = options
14
+ raise ArgumentError, "File #{key} is overridden locally! use --force to force" if reader.has_local_override? and !options.force
15
+
16
+ new_yaml = ask_editor(YAML.dump(reader.read(remote_only: true).to_hash))
17
+ writer.set(Configuration.from_yaml(new_yaml), reader.version_count)
18
+ end
19
+
20
+ def writer
21
+ @writer ||= ClusterFsck::Writer.new(key, cluster_fsck_env: reader.cluster_fsck_env)
22
+ end
23
+
24
+ def reader
25
+ @reader ||= ClusterFsck::Reader.new(key, cluster_fsck_env: cluster_fsck_env)
26
+ end
27
+
28
+ end
29
+ end
30
+ end