nightcrawler_swift 0.4.0 → 0.5.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (37) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +1 -0
  3. data/.travis.yml +4 -1
  4. data/Changelog.md +12 -2
  5. data/Gemfile.lock +11 -1
  6. data/README.md +112 -7
  7. data/bin/nswift +1 -1
  8. data/lib/nightcrawler_swift/cli/commands/url_for.rb +9 -0
  9. data/lib/nightcrawler_swift/cli/formatters/basic.rb +40 -0
  10. data/lib/nightcrawler_swift/cli/opt_parser.rb +81 -0
  11. data/lib/nightcrawler_swift/cli/runner.rb +127 -0
  12. data/lib/nightcrawler_swift/cli.rb +16 -173
  13. data/lib/nightcrawler_swift/command.rb +5 -14
  14. data/lib/nightcrawler_swift/commands/delete.rb +4 -6
  15. data/lib/nightcrawler_swift/commands/download.rb +4 -6
  16. data/lib/nightcrawler_swift/commands/list.rb +0 -6
  17. data/lib/nightcrawler_swift/commands/upload.rb +1 -4
  18. data/lib/nightcrawler_swift/connection.rb +15 -15
  19. data/lib/nightcrawler_swift/exceptions.rb +2 -1
  20. data/lib/nightcrawler_swift/gateway.rb +68 -0
  21. data/lib/nightcrawler_swift/version.rb +1 -1
  22. data/lib/nightcrawler_swift.rb +7 -2
  23. data/nightcrawler_swift.gemspec +1 -0
  24. data/spec/lib/nightcrawler_swift/cli/commands/url_for_spec.rb +34 -0
  25. data/spec/lib/nightcrawler_swift/cli/formatters/basic_spec.rb +117 -0
  26. data/spec/lib/nightcrawler_swift/cli/opt_parser_spec.rb +135 -0
  27. data/spec/lib/nightcrawler_swift/{cli_spec.rb → cli/runner_spec.rb} +133 -136
  28. data/spec/lib/nightcrawler_swift/command_spec.rb +17 -32
  29. data/spec/lib/nightcrawler_swift/commands/delete_spec.rb +8 -29
  30. data/spec/lib/nightcrawler_swift/commands/download_spec.rb +8 -29
  31. data/spec/lib/nightcrawler_swift/commands/list_spec.rb +14 -44
  32. data/spec/lib/nightcrawler_swift/commands/upload_spec.rb +1 -8
  33. data/spec/lib/nightcrawler_swift/connection_spec.rb +26 -9
  34. data/spec/lib/nightcrawler_swift/gateway_spec.rb +139 -0
  35. data/spec/lib/nightcrawler_swift_spec.rb +15 -2
  36. data/spec/spec_helper.rb +3 -0
  37. metadata +31 -4
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 616e1624837906ed1b5381823a1de196ba8b41e7
4
- data.tar.gz: 2e4d0b8eb39afb34e6cda6d5e7725c6938a3a817
3
+ metadata.gz: ce783e76729a865b6b3cd1fffbed84cc287234e9
4
+ data.tar.gz: 922f51e1130d4bb27b84bde8de018793c5b5a1c4
5
5
  SHA512:
6
- metadata.gz: 193eccd937c649b468e4b24cff3728d22a6acd7de8ac824876732bff14fbb145e33dafb222ff6069e350912c849b7c55d5e75a56e25a11357e6a8e9d368ece6c
7
- data.tar.gz: 466c00ebec3b67d64efca29ec820afea48ad74a0e702617dc91e570cf0c8c08bfca7a0808b2d8c8d01d3c09d398c64d7df7e7766312e1c35826fa500dd1af264
6
+ metadata.gz: ba0dc5e45b62d8011f321aba5c0e28487d5b496cde054a2197db3db5baeb2c9936a542ef5ef02ad9b3d324261b8677b6520140df048045ed4f579fd5bdb8db8e
7
+ data.tar.gz: a55710e1eddf95712cb5c3821b1853854b815ecf066ee6bf22c7b259e66f1dd7ad65f1f10405e4b8fe88b0b7c3482dbea3e05faaf9a1343fc1c7425af4152da1
data/.gitignore CHANGED
@@ -1,2 +1,3 @@
1
1
  .DS_Store
2
2
  pkg
3
+ coverage
data/.travis.yml CHANGED
@@ -1,4 +1,7 @@
1
1
  language: ruby
2
2
  rvm:
3
- - 2.1.2
3
+ - 2.1.2
4
4
  script: bundle exec rspec
5
+ env:
6
+ global:
7
+ secure: C1/OCk7bQxlGogDpgYf0vp6e5P/+TsFvO3bnJdfUoMlO3FAZafqq+xarWNZ/caaNEkYUQ2OaQmLYKZ32yVUAPoE1mUou9vijkOIi+m/JHr1sfeJykNYZYVqi7JQ/PILw2Qs80bZ3I0AS7hWCRIADeQUPuWul06uxYEUV1SB6mQI=
data/Changelog.md CHANGED
@@ -1,11 +1,21 @@
1
1
  # Changelog
2
2
 
3
+ ## 0.5.0
4
+
5
+ - CLI now supports ```-b/--bucket``` to override the default bucket/container (issue #10)
6
+ - CLI command for printing the public url of a given path (issue #18)
7
+ - CLI better treatment for errors and invalid commands
8
+ - Bugfix: CLI when receives a invalid command doesn't shows that it is an invalid command (issue #20)
9
+ - Configurable ```admin_url``` and ```public_url``` (issue #14)
10
+ - Included "public" directive in ```Cache-Control``` header
11
+ - Each request will retry X times before failing, the number of retries and the max waiting time can be configured through options
12
+
3
13
  ## 0.4.0
4
14
 
5
15
  - Better catalog selection
6
16
  - Treatment for no catalogs returned
7
- - Splited asset_sync task in two other tasks: sync and asset_sync
8
- - Configurable verify_ssl and timeout
17
+ - Splited asset_sync task in two other tasks: ```sync``` and ```asset_sync```
18
+ - Configurable ```verify_ssl``` and ```timeout```
9
19
  - Automatic connect/reconnect of commands
10
20
  - Bugfix: download command was not using the bucket/container name
11
21
  - Bugfix: the etag header must not be quoted
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- nightcrawler_swift (0.4.0)
4
+ nightcrawler_swift (0.5.0)
5
5
  multi_mime (>= 1.0.1)
6
6
  rest-client
7
7
 
@@ -11,10 +11,14 @@ GEM
11
11
  byebug (3.2.0)
12
12
  columnize (~> 0.8)
13
13
  debugger-linecache (~> 1.2)
14
+ codeclimate-test-reporter (0.4.0)
15
+ simplecov (>= 0.7.1, < 1.0.0)
14
16
  columnize (0.8.9)
15
17
  debugger-linecache (1.2.0)
16
18
  diff-lcs (1.2.5)
19
+ docile (1.1.5)
17
20
  mime-types (2.3)
21
+ multi_json (1.10.1)
18
22
  multi_mime (1.0.1)
19
23
  netrc (0.7.7)
20
24
  rake (10.3.2)
@@ -33,6 +37,11 @@ GEM
33
37
  rspec-mocks (3.0.4)
34
38
  rspec-support (~> 3.0.0)
35
39
  rspec-support (3.0.4)
40
+ simplecov (0.9.0)
41
+ docile (~> 1.1.0)
42
+ multi_json
43
+ simplecov-html (~> 0.8.0)
44
+ simplecov-html (0.8.0)
36
45
 
37
46
  PLATFORMS
38
47
  ruby
@@ -40,6 +49,7 @@ PLATFORMS
40
49
  DEPENDENCIES
41
50
  bundler (~> 1.6)
42
51
  byebug
52
+ codeclimate-test-reporter
43
53
  nightcrawler_swift!
44
54
  rake
45
55
  rspec
data/README.md CHANGED
@@ -6,18 +6,28 @@ Like the X-Men nightcrawler this gem teleports your assets to a OpenStack Swift
6
6
 
7
7
  Add this line to your application's Gemfile:
8
8
 
9
- gem 'nightcrawler_swift'
9
+ ```ruby
10
+ gem 'nightcrawler_swift'
11
+ ```
10
12
 
11
13
  And then execute:
12
14
 
13
- $ bundle
15
+ ```sh
16
+ $ bundle
17
+ ```
14
18
 
15
19
  Or install it yourself as:
16
20
 
17
- $ gem install nightcrawler_swift
21
+ ```sh
22
+ $ gem install nightcrawler_swift
23
+ ```
18
24
 
19
25
  ## Usage
20
26
 
27
+ * [With Rails](https://github.com/tulios/nightcrawler_swift#with-rails)
28
+ * [Programatically](https://github.com/tulios/nightcrawler_swift#programatically)
29
+ * [Command Line](https://github.com/tulios/nightcrawler_swift#command-line)
30
+
21
31
  ### With Rails
22
32
  #### 1) Configure your swift credentials and options
23
33
 
@@ -37,20 +47,36 @@ __Optional configurations:__
37
47
  config.nightcrawler_swift.max_age = 3600 # default: nil
38
48
  config.nightcrawler_swift.verify_ssl = true # default: false
39
49
  config.nightcrawler_swift.timeout = 10 # in seconds, default: nil
50
+ config.nightcrawler_swift.admin_url = "https://api.host.com/v1/AUTH_1234" # default: uses the admin_url returned by authentication
51
+ config.nightcrawler_swift.public_url = "http://asset.host.com/v1/AUTH_1234" # default: uses the public_url returned by authentication
52
+ config.nightcrawler_swift.retries = 3 # default: 5, to disable set it to false
53
+ config.nightcrawler_swift.max_retry_time = 64 # in seconds, default: 30
40
54
  ```
41
55
 
42
- _max_age_ will be used to define *Cache-Control:max-age=<value>* header.
43
-
44
56
  By default it will use ```Rails.logger``` as logger, to change that use a different logger in configurations, like:
45
57
 
46
58
  ```ruby
47
59
  config.nightcrawler_swift.logger = Logger.new(STDOUT)
48
60
  ```
49
61
 
62
+ ##### further explanation of configurations
63
+
64
+ > max_age
65
+
66
+ It will be used to define *Cache-Control:max-age=<value>* header.
67
+
68
+ > retries
69
+
70
+ The number of times to retry the request before failing. To disable this feature set it to __false__.
71
+
72
+ > max_retry_time
73
+
74
+ Maximum delay in seconds between each retry. The delay will start with 1s and will double for each retry until this value.
75
+
50
76
  #### 2) Profit!
51
77
 
52
78
  ```sh
53
- rake nightcrawler_swift:rails:asset_sync
79
+ $ rake nightcrawler_swift:rails:asset_sync
54
80
  ```
55
81
 
56
82
  It will invoke ```rake assets:precompile``` and will copy your public directory to swift bucket/container. To sync the public directory without the asset precompilation use the task: ```nightcrawler_swift:rails:sync```
@@ -74,7 +100,11 @@ __Optional configurations:__
74
100
  ```ruby
75
101
  max_age: 3600,
76
102
  verify_ssl: true,
77
- timeout: 10
103
+ timeout: 10, # in seconds
104
+ admin_url: "https://api.host.com/v1/AUTH_1234", # default: uses the admin_url returned by authentication
105
+ public_url: "http://asset.host.com/v1/AUTH_1234", # default: uses the public_url returned by authentication
106
+ retries: 3, # default: 5, to disable set it to false
107
+ max_retry_time: 64 # in seconds, default: 30
78
108
  ```
79
109
 
80
110
  By default it will use ```Logger.new(STDOUT)``` as logger, to change that use:
@@ -89,6 +119,58 @@ NightcrawlerSwift.logger = Logger.new(StringIO.new)
89
119
  NightcrawlerSwift.sync File.expand_path("./my-dir")
90
120
  ```
91
121
 
122
+ ### Command Line
123
+
124
+ The NightcrawlerSwift shell command (CLI) allows you to interact with your buckets/containers easily, it has the same commands of the gem. To see the help, use the cli without arguments or use the _-h_/_--help_ switch.
125
+
126
+ ```sh
127
+ $ nswift # or nswift -h
128
+ ```
129
+
130
+ ```nswift``` will use the configurations stored at the file __.nswiftrc__ located at your home directory. If you try to use any command without the file, it will create a sample configuration for you, but you can create your own.
131
+
132
+ The configuration is a __json__ file, named __.nswiftrc__. You can include any configuration available to the gem (see the other usages example to know each option available). Follow the format:
133
+
134
+ ```json
135
+ {
136
+ "bucket": "<bucket/container name>",
137
+ "tenant_name": "<tenant name>",
138
+ "username": "<username>",
139
+ "password": "<password>",
140
+ "auth_url": "<auth url, ex: https://auth.url.com:123/v2.0/tokens>"
141
+ }
142
+ ```
143
+
144
+ The following commands are available through the cli:
145
+
146
+ ```sh
147
+ $ nswift list
148
+ ```
149
+ ```sh
150
+ $ nswift upload <real_path> <swift_path> # nswift upload robots.txt assets/robots.txt
151
+ ```
152
+ ```sh
153
+ $ nswift download <swift_path> # nswift download assets/robots.txt > my-robots.txt
154
+ ```
155
+ ```sh
156
+ $ nswift delete <swift_path> # nswift delete assets/robots.txt
157
+ ```
158
+ ```sh
159
+ $ nswift url-for <swift_path> # nswift url-for assets/robots.txt
160
+ ```
161
+
162
+ For any commands you could provide a different configuration file through the _-c_/_--config_ switch, as:
163
+
164
+ ```sh
165
+ $ nswift list -c /dir/my-nswift-rc
166
+ ```
167
+
168
+ and a different bucket/container name through the _-b_/_--bucket_ switch, as:
169
+
170
+ ```sh
171
+ $ nwift list -b rogue
172
+ ```
173
+
92
174
  ## Commands
93
175
 
94
176
  NightcrawlerSwift has some useful built-in commands. All commands require the configuration and will __automatically__ connect/reconnect to keystone when necessary.
@@ -129,6 +211,13 @@ delete.execute "my_file_path.txt"
129
211
  # true / false
130
212
  ```
131
213
 
214
+ ### Sync
215
+
216
+ ```ruby
217
+ sync = NightcrawlerSwift::Sync.new
218
+ sync.execute "/dir/to/synchronize"
219
+ ```
220
+
132
221
  ## Connection
133
222
 
134
223
  To manually establish the connection with keystone, use:
@@ -145,6 +234,22 @@ NightcrawlerSwift.connection.connected?
145
234
 
146
235
  To reconnect just use ```NightcrawlerSwift.connection.connect!``` again.
147
236
 
237
+ ## Options
238
+
239
+ After configure the NightcrawlerSwift you can access your configurations through the __options__ method, like:
240
+
241
+ ```ruby
242
+ NightcrawlerSwift.options
243
+ ```
244
+
245
+ The only difference is that you will access each configuration as a method instead of a hash style, like:
246
+
247
+ ```ruby
248
+ NightcrawlerSwift.configure tenant_name: "rogue"
249
+
250
+ # Can be used as:
251
+ NightcrawlerSwift.options.tenant_name # "rogue"
252
+ ```
148
253
 
149
254
  ## Contributing
150
255
 
data/bin/nswift CHANGED
@@ -5,4 +5,4 @@ $LOAD_PATH.unshift File.dirname(__FILE__) + "/../lib"
5
5
  require "nightcrawler_swift"
6
6
  require "nightcrawler_swift/cli"
7
7
 
8
- NightcrawlerSwift::CLI.new(ARGV).run
8
+ NightcrawlerSwift::CLI::Runner.new(ARGV).run
@@ -0,0 +1,9 @@
1
+ module NightcrawlerSwift::CLI
2
+ class UrlFor < NightcrawlerSwift::Command
3
+
4
+ def execute path
5
+ "#{connection.public_url}/#{options.bucket}/#{path}"
6
+ end
7
+
8
+ end
9
+ end
@@ -0,0 +1,40 @@
1
+ module NightcrawlerSwift::CLI
2
+ module Formatters
3
+ class Basic
4
+
5
+ def initialize runner
6
+ @runner = runner
7
+ end
8
+
9
+ def command_list command
10
+ array = command.new.execute
11
+ array.each {|hash| @runner.log hash["name"]}
12
+ end
13
+
14
+ def command_download command
15
+ filepath = @runner.argv.first
16
+ @runner.log command.new.execute(filepath)
17
+ end
18
+
19
+ def command_upload command
20
+ realpath = @runner.argv.shift
21
+ swiftpath = @runner.argv.shift
22
+
23
+ uploaded = command.new.execute swiftpath, File.open(File.expand_path(realpath), "r")
24
+ @runner.log(uploaded ? "success" : "failure")
25
+ end
26
+
27
+ def command_delete command
28
+ filepath = @runner.argv.first
29
+ deleted = command.new.execute(filepath).to_json
30
+ @runner.log(deleted ? "success" : "failure")
31
+ end
32
+
33
+ def command_url_for command
34
+ filepath = @runner.argv.first
35
+ @runner.log command.new.execute(filepath)
36
+ end
37
+
38
+ end
39
+ end
40
+ end
@@ -0,0 +1,81 @@
1
+ module NightcrawlerSwift::CLI
2
+ class OptParser
3
+
4
+ attr_reader :parser
5
+
6
+ def initialize runner
7
+ @runner = runner
8
+ @parser = OptionParser.new
9
+ configure_instructions
10
+ configure_options
11
+ end
12
+
13
+ def parse!
14
+ @parser.parse!(@runner.argv)
15
+ end
16
+
17
+ def help
18
+ @parser.help
19
+ end
20
+
21
+ private
22
+ def configure_instructions
23
+ @parser.banner = "nswift #{NightcrawlerSwift::VERSION}"
24
+ @parser.separator "Usage: nswift command [options]"
25
+ @parser.separator ""
26
+ @parser.separator "commands:"
27
+ COMMANDS.keys.each do |key|
28
+ @parser.separator " #{key}\t\t\t #{COMMANDS[key][:description]}"
29
+ end
30
+
31
+ @parser.separator ""
32
+ end
33
+
34
+ def configure_options
35
+ @parser.separator "options:"
36
+ configure_option_bucket
37
+ configure_option_config
38
+ configure_option_help
39
+ configure_option_version
40
+ end
41
+
42
+ def configure_option_bucket
43
+ desc = "Alternative bucket/container name, overrides the '#{NightcrawlerSwift::CLI::CONFIG_FILE}' configuration"
44
+ @parser.on("-b", "--bucket=NAME", String, desc) do |name|
45
+ bucket = name.strip
46
+ @runner.options.bucket = bucket
47
+ @runner.log "Using bucket: #{@runner.options.bucket}"
48
+ end
49
+ end
50
+
51
+ def configure_option_config
52
+ @parser.on("-c", "--config=PATH", String, "Alternative '#{NightcrawlerSwift::CLI::CONFIG_FILE}' file") do |path|
53
+ path = File.expand_path(path.strip)
54
+
55
+ unless File.exist?(path)
56
+ @runner.log "Error: No such file or directory - #{path}"
57
+ exit 1
58
+ end
59
+
60
+ @runner.log "Using custom config file at: #{path}"
61
+ @runner.options.config_file = path
62
+ @runner.options.default_config_file = false
63
+ end
64
+ end
65
+
66
+ def configure_option_help
67
+ @parser.on_tail("-h", "--help", "Show this message") do
68
+ @runner.log help
69
+ exit
70
+ end
71
+ end
72
+
73
+ def configure_option_version
74
+ @parser.on_tail("-v", "--version", "Show version") do
75
+ @runner.log NightcrawlerSwift::VERSION
76
+ exit
77
+ end
78
+ end
79
+
80
+ end
81
+ end
@@ -0,0 +1,127 @@
1
+ module NightcrawlerSwift::CLI
2
+ class Runner
3
+ attr_reader :opt_parser, :options
4
+ attr_accessor :argv
5
+
6
+ def initialize argv
7
+ @argv = argv
8
+ configure_logger
9
+ end
10
+
11
+ def run
12
+ configure_default_options
13
+ configure_opt_parser
14
+ parse_parameters
15
+ @command_name = argv.shift
16
+ validate_command_and_options
17
+ execute_command if @command_name
18
+ end
19
+
20
+ def log string
21
+ NightcrawlerSwift.logger.info string
22
+ end
23
+
24
+ private
25
+ def configure_logger
26
+ STDOUT.sync = true
27
+ NightcrawlerSwift.logger.formatter = lambda {|severity, datetime, progname, msg| "#{msg}\n"}
28
+ end
29
+
30
+ def configure_default_options
31
+ user_home_dir = Dir.home
32
+ @options = OpenStruct.new
33
+ @options.configured = true
34
+ @options.default_config_file = true
35
+ @options.config_file = File.expand_path(File.join(user_home_dir, CONFIG_FILE))
36
+ @options.cache_file = File.expand_path(File.join(user_home_dir, CACHE_FILE))
37
+ @options.bucket = nil
38
+ end
39
+
40
+ def validate_command_and_options
41
+ if @command_name.nil? or argv.nil?
42
+ log @opt_parser.help
43
+ exit
44
+ end
45
+
46
+ unless COMMANDS.include?(@command_name)
47
+ log "Error: Unknown command '#{@command_name}'"
48
+ exit 1
49
+ end
50
+
51
+ unless options.configured
52
+ log "You must configure your swift credentials, take a look at:\n #{options.config_file}"
53
+ exit 1
54
+ end
55
+ end
56
+
57
+ def config_hash
58
+ @config_hash ||= JSON.parse(File.read(options.config_file))
59
+ end
60
+
61
+ def execute_command
62
+ NightcrawlerSwift.configure config_hash
63
+ NightcrawlerSwift.options.bucket = @options.bucket if @options.bucket
64
+
65
+ connect_and_execute do
66
+ command_method = "command_#{command_name_normalized}"
67
+ command_class = COMMANDS[@command_name][:command]
68
+ Formatters::Basic.new(self).send(command_method, command_class)
69
+ end
70
+
71
+ rescue NightcrawlerSwift::Exceptions::BaseError, Errno::ENOENT => e
72
+ log "Error: #{e.message}"
73
+ exit 1
74
+ end
75
+
76
+ def command_name_normalized
77
+ @command_name.downcase.gsub(/-/, "_")
78
+ end
79
+
80
+ def connect_and_execute &block
81
+ path = options.cache_file
82
+ if File.exist?(path)
83
+ hash = JSON.parse File.read(path)
84
+ NightcrawlerSwift.connection.auth_response = OpenStruct.new(hash)
85
+ NightcrawlerSwift.connection.configure
86
+
87
+ token_id = NightcrawlerSwift.connection.token_id
88
+ NightcrawlerSwift.logger.debug "Cache found, restablishing connection with token_id: #{token_id}"
89
+ end
90
+
91
+ begin
92
+ block.call
93
+ ensure
94
+ File.open(path, "w") do |f|
95
+ f.write(NightcrawlerSwift.connection.auth_response.to_h.to_json)
96
+ end
97
+ end
98
+ end
99
+
100
+ def parse_parameters
101
+ @opt_parser.parse!
102
+ check_rcfile if options.default_config_file
103
+
104
+ rescue OptionParser::InvalidOption => e
105
+ log e.message
106
+ exit 1
107
+ end
108
+
109
+ def configure_opt_parser
110
+ @opt_parser = OptParser.new self
111
+ end
112
+
113
+ def check_rcfile
114
+ sample = NightcrawlerSwift::CLI.sample_rcfile
115
+ unless File.exist?(options.config_file)
116
+ File.open(options.config_file, "w") { |f|
117
+ f.write(sample)
118
+ }
119
+ end
120
+
121
+ if sample == File.read(options.config_file)
122
+ options.configured = false
123
+ end
124
+ end
125
+
126
+ end
127
+ end