fog-akamai 0.1.1 → 0.5.0

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: f8e1c183618f068be64f0d0959e390b23b19b46f
4
- data.tar.gz: cdb9cd220be1caff79b65c156aa6754fb75b7fde
3
+ metadata.gz: f6c27c6eba6ca0f38e804c4eb82ebb102367e1eb
4
+ data.tar.gz: b2f945bf7fdb1be2e4bb987c31fc1af89be4ef8d
5
5
  SHA512:
6
- metadata.gz: 5197933b51c297b44232851ce28e99ba5911019ed43db5f4de44b7907c327f1fe4a70a85ba1b59bdd510e2239bbb830b666aaf8be235216fb85eaf8c454e66f9
7
- data.tar.gz: fc093806a9fd762caddce13ad6f6796f5a05dbd857097d0f77fb8744a99cd04cd2d1d565d5ae8477db05d140f303eda50d37c2e996647f1c23456fbf2a1d1e07
6
+ metadata.gz: b4f0605c05d091ce683511b8363ed4d07c9a737df8950373b91f8a38ebca998c9b7b741010a2e327579428ce6d44bcaaccb24887381960824380f5b20d77408c
7
+ data.tar.gz: 163d6e859734fb81e94c6f9897adc7a125c436f1339b38a4b0edc18119adac2ed84cb3e22cc879ef8e8ed78738e29b6104ae990fc66ce396f1fd49a0f2444e97
data/.rubocop.yml ADDED
@@ -0,0 +1,5 @@
1
+ Metrics/LineLength:
2
+ Max: 160
3
+
4
+ Style/Documentation:
5
+ Enabled: false
data/Gemfile CHANGED
@@ -3,4 +3,4 @@ source 'https://rubygems.org'
3
3
  # Specify your gem's dependencies in fog-netstorage.gemspec
4
4
  gemspec
5
5
 
6
- gem 'codeclimate-test-reporter', group: :test, require: nil
6
+ gem 'codeclimate-test-reporter', group: :test, require: nil
data/README.md CHANGED
@@ -2,7 +2,7 @@
2
2
 
3
3
  Welcome to your new gem! In this directory, you'll find the files you need to be able to package up your Ruby library into a gem. Put your Ruby code in the file `lib/fog/storage`. To experiment with that code, run `bin/console` for an interactive prompt.
4
4
 
5
- This is still under development only very basic net storage functionality has been put in place.
5
+ All the functionality of the net storage api is implemented except the really dangerous bit, quick-delete.
6
6
 
7
7
  ## Installation
8
8
 
@@ -66,8 +66,6 @@ directory.files.create(directory: directory, body: file_body, key: file_name)
66
66
 
67
67
  ## Roadmap
68
68
 
69
- - finish implementing the netstorage api
70
- - add mock support
71
69
  - implement ccu api
72
70
 
73
71
  ## Development
data/Rakefile CHANGED
@@ -8,4 +8,4 @@ Rake::TestTask.new do |t|
8
8
  end
9
9
 
10
10
  desc 'Default Task'
11
- task :default => [ :test ]
11
+ task default: [:test]
data/bin/console CHANGED
@@ -1,7 +1,7 @@
1
1
  #!/usr/bin/env ruby
2
2
 
3
- require "bundler/setup"
4
- require "fog/akamai"
3
+ require 'bundler/setup'
4
+ require 'fog/akamai'
5
5
 
6
6
  # You can add fixtures and/or initialization code here to make experimenting
7
7
  # with your gem easier. You can also use a different console, if you like.
@@ -10,5 +10,5 @@ require "fog/akamai"
10
10
  # require "pry"
11
11
  # Pry.start
12
12
 
13
- require "irb"
13
+ require 'irb'
14
14
  IRB.start
data/fog-akamai.gemspec CHANGED
@@ -10,9 +10,9 @@ Gem::Specification.new do |spec|
10
10
  spec.email = ['calinoiu.alexandru@agilefreaks.com']
11
11
  spec.license = 'MIT'
12
12
 
13
- spec.summary = %q{Module for 'fog' gem to support Akamai}
14
- spec.description = %q{This library can be used as a module for `fog` or as standalone provider
15
- to use Akamai}
13
+ spec.summary = "Module for 'fog' gem to support Akamai"
14
+ spec.description = 'This library can be used as a module for `fog` or as standalone provider
15
+ to use Akamai'
16
16
  spec.homepage = 'https://github.com/alexandru-calinoiu/fog-akamai'
17
17
 
18
18
  spec.files = `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
@@ -26,6 +26,8 @@ Gem::Specification.new do |spec|
26
26
  spec.add_development_dependency 'minitest-reporters', '~> 1.1'
27
27
  spec.add_development_dependency 'test-unit', '~> 3.1'
28
28
  spec.add_development_dependency 'webmock', '~> 1.22'
29
+ spec.add_development_dependency 'rubocop', '~> 0.35'
30
+ spec.add_development_dependency 'timecop', '~> 0.8.0'
29
31
 
30
32
  spec.add_dependency 'fog-core', '~> 1.27'
31
33
  spec.add_dependency 'fog-json', '~> 1.0'
@@ -4,15 +4,33 @@ module Fog
4
4
  class Directories < Fog::Collection
5
5
  model Fog::Storage::Akamai::Directory
6
6
 
7
+ attribute :parent
8
+
9
+ def all
10
+ requires :parent
11
+ parent.directories
12
+ end
13
+
7
14
  def get(key)
8
15
  data = service.dir(key).body
9
16
 
10
- directory = new(:key => data[:directory].sub("/#{service.akamai_cp_code}", ''))
11
- directory.files.load(data[:files].map { |file| file.merge(:directory => directory) })
17
+ directory = new(key: data[:directory].sub("/#{service.akamai_cp_code}", ''))
18
+ load_files(directory, data)
19
+ load_directories(directory, data)
12
20
 
13
21
  directory
14
22
  end
23
+
24
+ private
25
+
26
+ def load_files(directory, data)
27
+ directory.files.load(data[:files].map { |file| file.merge(directory: directory) })
28
+ end
29
+
30
+ def load_directories(directory, data)
31
+ directory.directories.load(data[:directories].map { |dir| dir.merge(parent: directory) })
32
+ end
15
33
  end
16
34
  end
17
35
  end
18
- end
36
+ end
@@ -2,16 +2,38 @@ module Fog
2
2
  module Storage
3
3
  class Akamai
4
4
  class Directory < Fog::Model
5
- identity :key
5
+ include Fog::Akamai::Shared
6
+
7
+ identity :key, aliases: 'name'
6
8
 
7
9
  attribute :parent
10
+ attribute :name
11
+ attribute :mtime
8
12
 
9
13
  def files
10
14
  @files ||= Fog::Storage::Akamai::Files.new(
11
- :directory => self,
12
- :service => service
15
+ directory: self,
16
+ service: service
17
+ )
18
+ end
19
+
20
+ def directories
21
+ @directories ||= Fog::Storage::Akamai::Directories.new(
22
+ parent: self,
23
+ service: service
13
24
  )
14
25
  end
26
+
27
+ def save
28
+ requires :key
29
+ path = parent.nil? ? key : full_path(key, parent)
30
+ service.mkdir(path)
31
+ end
32
+
33
+ def destroy
34
+ requires :key
35
+ service.rmdir(key)
36
+ end
15
37
  end
16
38
  end
17
39
  end
@@ -1,35 +1,47 @@
1
1
  module Fog
2
- module Storage
3
- class Akamai
4
- class File < Fog::Model
5
- include Fog::Akamai::Shared
6
-
7
- identity :key, :aliases => 'name'
8
-
9
- attribute :directory
10
- attribute :name
11
- attribute :mtime
12
- attribute :md5
13
- attribute :size
14
- attribute :body
15
-
16
- def get(key)
17
- requires :directory
18
- end
19
-
20
- def save
21
- requires :body, :directory, :key
22
- service.upload(full_path(key, directory), body)
23
- end
24
-
25
- def destroy
26
- requires :directory, :key
27
- end
28
-
29
- def ready?
30
- true
31
- end
32
- end
33
- end
34
- end
2
+ module Storage
3
+ class Akamai
4
+ class File < Fog::Model
5
+ include Fog::Akamai::Shared
6
+
7
+ identity :key, aliases: 'name'
8
+
9
+ attribute :directory
10
+ attribute :name
11
+ attribute :mtime
12
+ attribute :md5
13
+ attribute :size
14
+ attribute :body
15
+
16
+ def get(_key)
17
+ requires :directory
18
+ end
19
+
20
+ def save
21
+ requires :body, :directory, :key
22
+ service.upload(full_path(key, directory), body)
23
+ end
24
+
25
+ def destroy
26
+ requires :directory, :key
27
+ end
28
+
29
+ def ready?
30
+ true
31
+ end
32
+
33
+ def touch(mtime = DateTime.now.to_time.to_i)
34
+ requires :directory, :key
35
+ service.mtime(full_path(key, directory), mtime)
36
+ end
37
+
38
+ def rename(new_name)
39
+ requires :directory, :key
40
+ service.rename(full_path(key, directory), full_path(new_name, directory))
41
+ self.key = new_name
42
+ self.name = new_name
43
+ end
44
+ end
45
+ end
46
+ end
35
47
  end
@@ -10,11 +10,12 @@ module Fog
10
10
 
11
11
  def all
12
12
  requires :directory
13
+ directory.files
13
14
  end
14
15
 
15
16
  def get(path)
16
17
  body = service.download(full_path(path, directory)).data[:body]
17
- new(:body => body)
18
+ new(body: body)
18
19
  end
19
20
 
20
21
  def stat(path)
@@ -25,4 +26,4 @@ module Fog
25
26
  end
26
27
  end
27
28
  end
28
- end
29
+ end
@@ -4,30 +4,30 @@ module Fog
4
4
  module Akamai
5
5
  class Dir < Fog::Parsers::Base
6
6
  def reset
7
- @response = { :directory => '', :files => [] }
7
+ @response = { directory: '', files: [], directories: [] }
8
8
  end
9
9
 
10
10
  def start_element(name, attrs = [])
11
11
  case name
12
- when 'stat'
13
- @response[:directory] = attrs.first.value
14
- when 'file'
15
- @response[:files] << attrs_to_hash(attrs) if is_file?(attrs)
12
+ when 'stat'
13
+ @response[:directory] = attrs.first.value
14
+ when 'file'
15
+ @response[:files] << attrs_to_hash(attrs) if of_type?(attrs, 'file')
16
+ @response[:directories] << attrs_to_hash(attrs) if of_type?(attrs, 'dir')
16
17
  end
17
18
  end
18
19
 
19
20
  private
20
21
 
21
- def is_file?(attrs)
22
- attrs.any? { |attr| attr.localname == 'type' && attr.value == 'file' }
23
- end
24
-
25
- def attrs_to_hash(attrs)
26
- attrs.inject({}) { |result, attr| result.merge(attr.localname => attr.value) }
27
- end
22
+ def of_type?(attrs, type)
23
+ attrs.any? { |attr| attr.localname == 'type' && attr.value == type }
24
+ end
28
25
 
26
+ def attrs_to_hash(attrs)
27
+ attrs.inject({}) { |a, e| a.merge(e.localname => e.value) }
28
+ end
29
29
  end
30
30
  end
31
31
  end
32
32
  end
33
- end
33
+ end
@@ -0,0 +1,29 @@
1
+ module Fog
2
+ module Parsers
3
+ module Storage
4
+ module Akamai
5
+ class Du < Fog::Parsers::Base
6
+ def reset
7
+ @response = { directory: '', files: '', bytes: '' }
8
+ end
9
+
10
+ def start_element(name, attrs = [])
11
+ case name
12
+ when 'du'
13
+ @response[:directory] = value_for_attr(attrs, 'directory')
14
+ when 'du-info'
15
+ @response[:files] = value_for_attr(attrs, 'files')
16
+ @response[:bytes] = value_for_attr(attrs, 'bytes')
17
+ end
18
+ end
19
+
20
+ private
21
+
22
+ def value_for_attr(attrs, name)
23
+ attrs.find { |attr| attr.localname == name }.value
24
+ end
25
+ end
26
+ end
27
+ end
28
+ end
29
+ end
@@ -0,0 +1,46 @@
1
+ require 'pathname'
2
+
3
+ module Fog
4
+ module Storage
5
+ class Akamai
6
+ class Real
7
+ # Use this action to delete an individual file or symbolic link.
8
+ # @param path [String] the path for the file that will be downloaded
9
+ # @return [Excon::Response] response
10
+
11
+ def delete(path)
12
+ path_guard(path)
13
+ request(:delete,
14
+ path: format_path(path),
15
+ method: 'PUT',
16
+ expects: 200)
17
+ end
18
+ end
19
+
20
+ class Mock
21
+ def delete(path)
22
+ path_guard(path)
23
+
24
+ if remove_file(Pathname.new(format_path(path)))
25
+ Excon::Response.new(status: 200)
26
+ else
27
+ fail(Excon::Errors::NotFound, '404 Not Found')
28
+ end
29
+ end
30
+
31
+ private
32
+
33
+ def remove_file(path)
34
+ return false unless data.key?(path.to_s)
35
+
36
+ data[path.to_s] = nil
37
+ remove_file_from_parent_dir(path)
38
+ end
39
+
40
+ def remove_file_from_parent_dir(path)
41
+ data[path.split.first.to_s][:files].reject! { |hash| hash['name'] == path.basename.to_s }
42
+ end
43
+ end
44
+ end
45
+ end
46
+ end
@@ -4,23 +4,36 @@ module Fog
4
4
  class Real
5
5
  require 'fog/akamai/parsers/storage/dir'
6
6
 
7
- def dir(path = nil)
8
- path ||= ''
7
+ # Use this action to return the structure for a selected directory
8
+ # @return [Excon::Response] response:
9
+ # * body [Hash]:
10
+ # * directory [String] - Path to directory
11
+ # * files [Array]:
12
+ # * type [String]
13
+ # * name [String]
14
+ # * mtime [String]
15
+ # * size [String]
16
+ # * md5 [String]
17
+ # * directories [Array]:
18
+ # * type [String]
19
+ # * name [String]
20
+ # * mtime [String]
21
+
22
+ def dir(path = '')
9
23
  request(:dir,
10
- {
11
- :path => format_path(path),
12
- :method => 'GET',
13
- :expects => 200,
14
- :parser => Fog::Parsers::Storage::Akamai::Dir.new
15
- })
24
+ path: format_path(path),
25
+ method: 'GET',
26
+ expects: 200,
27
+ parser: Fog::Parsers::Storage::Akamai::Dir.new)
16
28
  end
17
29
  end
18
30
 
19
31
  class Mock
20
- def dir
21
- raise Fog::Mock.not_implemented
32
+ def dir(path = '')
33
+ key = format_path(path)
34
+ data.key?(key) ? Excon::Response.new(status: 200, body: data[key]) : fail(Excon::Errors::NotFound, '404 Not Found')
22
35
  end
23
36
  end
24
37
  end
25
38
  end
26
- end
39
+ end
@@ -2,21 +2,28 @@ module Fog
2
2
  module Storage
3
3
  class Akamai
4
4
  class Real
5
+ # Use this action to download a file
6
+ # @param path [String] the path for the file that will be downloaded
7
+ # @return [Excon::Response] response:
8
+ # * body [binary]
9
+
5
10
  def download(path)
11
+ path_guard(path)
6
12
  request(:download,
7
- {
8
- :path => format_path(path),
9
- :method => 'GET',
10
- :expects => 200
11
- })
13
+ path: format_path(path),
14
+ method: 'GET',
15
+ expects: 200)
12
16
  end
13
17
  end
14
18
 
15
19
  class Mock
16
20
  def download(path)
17
- raise Fog::Mock.not_implemented
21
+ path_guard(path)
22
+ formatted_path = format_path(path)
23
+ fail(Excon::Errors::NotFound, '404 Not Found') unless data.key?(formatted_path) && data[formatted_path].key?(:body)
24
+ Excon::Response.new(status: 200, body: data[formatted_path][:body])
18
25
  end
19
26
  end
20
27
  end
21
28
  end
22
- end
29
+ end
@@ -0,0 +1,42 @@
1
+ module Fog
2
+ module Storage
3
+ class Akamai
4
+ class Real
5
+ require 'fog/akamai/parsers/storage/du'
6
+
7
+ # Use this action to return disk usage information for the directory specified by the
8
+ # @path, including all files stored in any sub-directories that may exist.
9
+ # @param path [String] the path for the file that will be downloaded
10
+ # @return [Excon::Response] response:
11
+ # * body [Hash]:
12
+ # * directory [String] - The path to the directory
13
+ # * files [String] - The size of the files in bytes
14
+ # * bytes [String] - The size of the directory in bytes
15
+
16
+ def du(path)
17
+ path_guard(path)
18
+ request(:du,
19
+ path: format_path(path),
20
+ method: 'GET',
21
+ expects: 200,
22
+ parser: Fog::Parsers::Storage::Akamai::Du.new)
23
+ end
24
+ end
25
+
26
+ class Mock
27
+ def du(path)
28
+ path_guard(path)
29
+
30
+ key = format_path(path)
31
+ directory = data[key]
32
+
33
+ if directory
34
+ Excon::Response.new(status: 200, body: { directory: key, files: directory[:files].count.to_s, bytes: directory[:directories].count.to_s })
35
+ else
36
+ fail(Excon::Errors::NotFound, '404 Not Found')
37
+ end
38
+ end
39
+ end
40
+ end
41
+ end
42
+ end
@@ -0,0 +1,52 @@
1
+ require 'pathname'
2
+
3
+ module Fog
4
+ module Storage
5
+ class Akamai
6
+ class Real
7
+ # Use this action to create a dir
8
+ # @param path [String] the path to create, it will create directories recursively
9
+ # @return [Excon::Response] response
10
+
11
+ def mkdir(path)
12
+ path_guard(path)
13
+ request(:mkdir,
14
+ path: format_path(path),
15
+ method: 'PUT',
16
+ expects: 200
17
+ )
18
+ end
19
+ end
20
+
21
+ class Mock
22
+ def mkdir(path)
23
+ path_guard(path)
24
+
25
+ path = Pathname.new(format_path(path))
26
+ last_path_basename = ''
27
+
28
+ path.ascend do |parent|
29
+ break if parent.nil?
30
+
31
+ key = parent.to_s
32
+ update_data(key, last_path_basename)
33
+ last_path_basename = parent.basename.to_s
34
+ end
35
+
36
+ Excon::Response.new(headers: { 'Status' => 200 })
37
+ end
38
+
39
+ private
40
+
41
+ def update_data(key, last_path_basename)
42
+ data[key] ||= { directory: key, files: [], directories: [] }
43
+ data[key][:directories] << build_directory_node(last_path_basename) unless last_path_basename.empty?
44
+ end
45
+
46
+ def build_directory_node(last_path_basename)
47
+ { 'type' => 'dir', 'name' => last_path_basename, 'mtime' => DateTime.now.to_time.to_i.to_s }
48
+ end
49
+ end
50
+ end
51
+ end
52
+ end
@@ -0,0 +1,45 @@
1
+ require 'pathname'
2
+
3
+ module Fog
4
+ module Storage
5
+ class Akamai
6
+ class Real
7
+ # Use this action to change a file's modification time ("touch").
8
+ # @param path [String] the path for he file that will be downloaded
9
+ # @param mtime [int] the desired modification time for the target content (i.e., in UNIX epoch time).
10
+ # @return [Excon::Response] response
11
+
12
+ def mtime(path, mtime = DateTime.now.to_time.to_i)
13
+ path_guard(path)
14
+ request({ action: :mtime, mtime: mtime },
15
+ path: format_path(path),
16
+ method: 'POST',
17
+ expects: 200)
18
+ end
19
+ end
20
+
21
+ class Mock
22
+ def mtime(path, mtime = DateTime.now.to_time.to_i)
23
+ path_guard(path)
24
+
25
+ pathname = Pathname.new(format_path(path))
26
+ file = get_file(pathname)
27
+
28
+ if file
29
+ file['mtime'] = mtime.to_s
30
+ Excon::Response.new(status: 200)
31
+ else
32
+ fail(Excon::Errors::NotFound, '404 Not Found')
33
+ end
34
+ end
35
+
36
+ private
37
+
38
+ def get_file(pathname)
39
+ dir = data[pathname.split.first.to_s] || { files: [] }
40
+ dir[:files].find { |file_hash| file_hash['name'] == pathname.basename.to_s }
41
+ end
42
+ end
43
+ end
44
+ end
45
+ end
@@ -0,0 +1,54 @@
1
+ require 'pathname'
2
+
3
+ module Fog
4
+ module Storage
5
+ class Akamai
6
+ class Real
7
+ # Use this action to rename a file or symbolic link.
8
+ # @param source [String] the path to check
9
+ # @param destination [String] the path to check
10
+ # @return [Excon::Response] response
11
+
12
+ def rename(source, destination)
13
+ path_guard(source)
14
+ path_guard(destination)
15
+
16
+ request({ action: :rename, destination: CGI.escape(format_path(destination)) },
17
+ path: format_path(source),
18
+ method: 'POST',
19
+ expects: 200)
20
+ end
21
+ end
22
+
23
+ class Mock
24
+ def rename(source, destination)
25
+ path_guard(source)
26
+ path_guard(destination)
27
+
28
+ source_pathname = Pathname.new(format_path(source))
29
+ destination_pathname = Pathname.new(format_path(destination))
30
+
31
+ if rename_file(source_pathname, destination_pathname)
32
+ move_file(source_pathname, destination_pathname)
33
+ Excon::Response.new(status: 200)
34
+ else
35
+ fail(Excon::Errors::NotFound, '404 Not Found')
36
+ end
37
+ end
38
+
39
+ private
40
+
41
+ def rename_file(source, destination)
42
+ source_dir = data[source.split.first.to_s] || { files: [] }
43
+ source_file = source_dir[:files].find { |file| file['name'] == source.basename.to_s }
44
+ source_file['name'] = destination.basename.to_s if source_file
45
+ end
46
+
47
+ def move_file(source, destination)
48
+ data[destination.to_s] = data[source.to_s]
49
+ data[source.to_s] = nil
50
+ end
51
+ end
52
+ end
53
+ end
54
+ end
@@ -0,0 +1,41 @@
1
+ module Fog
2
+ module Storage
3
+ class Akamai
4
+ class Real
5
+ # Use this action to delete an empty directory.
6
+ # @param path [String] the path to the directory
7
+ # @return [Excon::Response] response
8
+
9
+ def rmdir(path)
10
+ path_guard(path)
11
+ request(:rmdir,
12
+ method: 'POST',
13
+ path: format_path(path),
14
+ expects: 200)
15
+ end
16
+ end
17
+
18
+ class Mock
19
+ def rmdir(path)
20
+ path_guard(path)
21
+
22
+ formatted_path = format_path(path)
23
+ dir = data[formatted_path]
24
+
25
+ if empty?(dir)
26
+ data.delete(formatted_path)
27
+ Excon::Response.new(status: 200)
28
+ else
29
+ fail(Excon::Errors::Conflict, 'Not a empty directory')
30
+ end
31
+ end
32
+
33
+ private
34
+
35
+ def empty?(dir)
36
+ dir[:files].empty? && dir[:directories].empty?
37
+ end
38
+ end
39
+ end
40
+ end
41
+ end
@@ -1,26 +1,66 @@
1
+ require 'pathname'
2
+
1
3
  module Fog
2
4
  module Storage
3
5
  class Akamai
4
6
  class Real
5
7
  require 'fog/akamai/parsers/storage/dir'
6
8
 
9
+ # Use this action to check if a file or directory existis
10
+ # @param path [String] the path to check
11
+ # @return [Excon::Response] response:
12
+ # * body [Hash]:
13
+ # * directory [String] - Path of the parnt directory
14
+ # * files [Array]: - In case the stat was for a file
15
+ # * type [String]
16
+ # * name [String]
17
+ # * mtime [String]
18
+ # * size [String]
19
+ # * md5 [String]
20
+ # * directories [Array]: - In case the stat was for a directory
21
+ # * type [String]
22
+ # * name [String]
23
+ # * mtime [String]
24
+
7
25
  def stat(path)
8
- raise ArgumentError.new('path needs to have a value') if path.empty?
26
+ path_guard(path)
9
27
  request(:stat,
10
- {
11
- :path => format_path(path),
12
- :method => 'GET',
13
- :expects => 200,
14
- :parser => Fog::Parsers::Storage::Akamai::Dir.new
15
- })
28
+ path: format_path(path),
29
+ method: 'GET',
30
+ expects: 200,
31
+ parser: Fog::Parsers::Storage::Akamai::Dir.new)
16
32
  end
17
33
  end
18
34
 
19
35
  class Mock
20
36
  def stat(path)
21
- raise Fog::Mock.not_implemented
37
+ path_guard(path)
38
+
39
+ path = Pathname.new(format_path(path))
40
+ key = path.split.first.to_s
41
+
42
+ response = Excon::Response.new(status: get_status(key, path.basename.to_s), body: get_body(key))
43
+
44
+ fail(Excon::Errors::NotFound, '404 Not Found') if response.status == 404
45
+ response
46
+ end
47
+
48
+ private
49
+
50
+ def get_status(key, basename)
51
+ if data.key?(key) &&
52
+ (data[key][:directories].any? { |dir| dir['name'] == basename } ||
53
+ data[key][:files].any? { |file| file['name'] == basename })
54
+ 200
55
+ else
56
+ 404
57
+ end
58
+ end
59
+
60
+ def get_body(key)
61
+ data[key] if data.key?(key)
22
62
  end
23
63
  end
24
64
  end
25
65
  end
26
- end
66
+ end
@@ -0,0 +1,25 @@
1
+ module Fog
2
+ module Storage
3
+ class Akamai
4
+ class Real
5
+ # Use this action to rename a file or symbolic link.
6
+ # @param source [String] the path to check
7
+ # @param target [String] the path to check
8
+ # @return [Excon::Response] response
9
+
10
+ def symlink(source, target)
11
+ path_guard(source)
12
+ path_guard(target)
13
+
14
+ request({ action: :symlink, target: CGI.escape(format_path(target)) },
15
+ path: format_path(source),
16
+ method: 'POST',
17
+ expects: 200)
18
+ end
19
+ end
20
+
21
+ class Mock
22
+ end
23
+ end
24
+ end
25
+ end
@@ -1,27 +1,51 @@
1
+ require 'pathname'
2
+
1
3
  module Fog
2
4
  module Storage
3
5
  class Akamai
4
6
  class Real
7
+ # Use this action to upload a file
8
+ # @param path [String] the path to where to upload
9
+ # @param body [File] the file to upload, can be file or a byte array
10
+ # @return [Excon::Response] response
11
+
5
12
  def upload(path, body)
6
- raise ArgumentError('path is required') if path.empty?
7
- raise ArgumentError('body is required') if body == nil
13
+ path_and_body_guard(path, body)
14
+
8
15
  data = Fog::Storage.parse_data(body)
9
16
  request(:upload,
10
- {
11
- :path => format_path(path),
12
- :method => 'PUT',
13
- :headers => data[:headers],
14
- :body => data[:body],
15
- :expects => 200
16
- })
17
+ path: format_path(path),
18
+ method: 'PUT',
19
+ headers: data[:headers],
20
+ body: data[:body],
21
+ expects: 200)
17
22
  end
18
23
  end
19
24
 
20
25
  class Mock
21
26
  def upload(path, body)
22
- raise Fog::Mock.not_implementedend
27
+ path_and_body_guard(path, body)
28
+
29
+ path = Pathname(path)
30
+ dir = path.split.first.to_s
31
+
32
+ mkdir(dir)
33
+ add_file(dir, path, body)
34
+
35
+ Excon::Response.new(status: 200)
36
+ end
37
+
38
+ private
39
+
40
+ def add_file(dir, path, body)
41
+ data[format_path(dir)][:files] << build_file(body, path)
42
+ data[format_path(path.to_s)] = { body: body }
43
+ end
44
+
45
+ def build_file(body, path)
46
+ { 'type' => 'file', 'name' => path.basename.to_s, 'mtime' => DateTime.now.to_time.to_i.to_s, 'size' => body.size.to_s }
23
47
  end
24
48
  end
25
49
  end
26
50
  end
27
- end
51
+ end
@@ -3,7 +3,7 @@ module Fog
3
3
  class Akamai < Fog::Service
4
4
  requires :akamai_host, :akamai_key_name, :akamai_key, :akamai_cp_code
5
5
 
6
- VALID_ACTIONS = [:dir, :download, :stat, :upload]
6
+ VALID_ACTIONS = [:dir, :mkdir, :download, :stat, :upload, :delete, :du, :mtime, :rename, :rmdir, :symlink]
7
7
  ACS_AUTH_DATA_HEADER = 'X-Akamai-ACS-Auth-Data'
8
8
  ACS_AUTH_SIGN_HEADER = 'X-Akamai-ACS-Auth-Sign'
9
9
  ACS_AUTH_ACTION_HEADER = 'X-Akamai-ACS-Action'
@@ -16,25 +16,75 @@ module Fog
16
16
 
17
17
  request_path 'fog/akamai/requests/storage'
18
18
  request :dir
19
+ request :mkdir
19
20
  request :download
20
21
  request :stat
21
22
  request :upload
23
+ request :delete
24
+ request :du
25
+ request :mtime
26
+ request :rename
27
+ request :rmdir
28
+ request :symlink
22
29
 
23
30
  module Helpers
24
31
  def format_path(path)
25
32
  ["/#{akamai_cp_code}", path].reject(&:empty?).join
26
33
  end
34
+
35
+ def path_and_body_guard(path, body)
36
+ path_guard(path)
37
+ fail ArgumentError('body is required') if body.nil?
38
+ end
39
+
40
+ def path_guard(path)
41
+ fail(ArgumentError, 'path needs to have a value') if path.nil? || path.empty?
42
+ end
43
+ end
44
+
45
+ module Initializer
46
+ def self.included(klass)
47
+ klass.instance_eval do
48
+ attr_reader :akamai_key, :akamai_host, :akamai_cp_code, :akamai_key_name, :scheme, :port
49
+ end
50
+ end
51
+
52
+ def init(options)
53
+ @akamai_host = options[:akamai_host]
54
+ @akamai_key_name = options[:akamai_key_name]
55
+ @akamai_key = options[:akamai_key]
56
+ @akamai_cp_code = options[:akamai_cp_code]
57
+
58
+ @scheme = options[:scheme] || 'https'
59
+ @port = options[:port] || 443
60
+ end
27
61
  end
28
62
 
29
63
  class Mock
30
- def initialize(_options = {})
64
+ include Helpers
65
+ include Initializer
66
+
67
+ def self.data
68
+ @data ||= {}
69
+ end
70
+
71
+ def initialize(options = {})
72
+ init(options)
73
+ end
74
+
75
+ def data
76
+ self.class.data
77
+ end
78
+
79
+ def reset_data
80
+ self.class.data.clear
31
81
  end
32
82
  end
33
83
 
34
84
  class Real
35
85
  include Helpers
86
+ include Initializer
36
87
 
37
- attr_reader :akamai_key, :akamai_host, :akamai_cp_code, :akamai_key_name, :scheme, :port
38
88
  # Initialize connection to Akamai
39
89
  #
40
90
  # ==== Notes
@@ -55,13 +105,7 @@ module Fog
55
105
  # ==== Returns
56
106
  # * Storage object for akamai.
57
107
  def initialize(options = {})
58
- @akamai_host = options[:akamai_host]
59
- @akamai_key_name = options[:akamai_key_name]
60
- @akamai_key = options[:akamai_key]
61
- @akamai_cp_code = options[:akamai_cp_code]
62
-
63
- @scheme = options[:scheme] || 'https'
64
- @port = options[:port] || 443
108
+ init(options)
65
109
  end
66
110
 
67
111
  def acs_auth_data
@@ -74,40 +118,41 @@ module Fog
74
118
  end
75
119
 
76
120
  def acs_action(action)
77
- raise ArgumentError.new("Invalid action #{action} valid actions are: #{VALID_ACTIONS}") unless VALID_ACTIONS.include?(action)
121
+ action = { action: action } if action.is_a?(Symbol)
122
+
123
+ fail(ArgumentError, "Invalid action #{action} valid actions are: #{VALID_ACTIONS}") unless VALID_ACTIONS.include?(action[:action])
78
124
 
79
- "version=1&action=#{action}&format=xml"
125
+ "version=1&#{action.map { |v, k| "#{v}=#{k}" }.join('&')}&format=xml"
80
126
  end
81
127
 
82
128
  def acs_auth_sign(auth_data, path, action)
83
129
  data = auth_data + sign_string(path, action)
84
130
  digest = OpenSSL::Digest::Digest::SHA256.new
85
- Base64.encode64(OpenSSL::HMAC.digest(digest, akamai_key, data)).strip()
131
+ Base64.encode64(OpenSSL::HMAC.digest(digest, akamai_key, data)).strip
86
132
  end
87
133
 
88
134
  private
89
135
 
90
- def request(action, params)
91
- url = "#{scheme}://#{akamai_host}:#{port}"
136
+ def request(action, params)
137
+ url = "#{scheme}://#{akamai_host}:#{port}"
92
138
 
93
- path = params[:path]
94
- auth_data = acs_auth_data
95
- auth_sign = acs_auth_sign(auth_data, path, action)
139
+ path = params[:path]
140
+ auth_data = acs_auth_data
96
141
 
97
- headers = {
98
- ACS_AUTH_DATA_HEADER => auth_data,
99
- ACS_AUTH_SIGN_HEADER => auth_sign,
100
- ACS_AUTH_ACTION_HEADER => acs_action(action)
101
- }.merge(params[:headers] || {})
142
+ headers = {
143
+ ACS_AUTH_DATA_HEADER => auth_data,
144
+ ACS_AUTH_SIGN_HEADER => acs_auth_sign(auth_data, path, action),
145
+ ACS_AUTH_ACTION_HEADER => acs_action(action)
146
+ }.merge(params[:headers] || {})
102
147
 
103
- params = params.merge(headers: headers)
104
- Fog::XML::Connection.new(url).request(params)
105
- end
148
+ params = params.merge(headers: headers)
149
+ Fog::XML::Connection.new(url).request(params)
150
+ end
106
151
 
107
- def sign_string(path, action)
108
- action = "x-akamai-acs-action:#{acs_action(action)}\n"
109
- "#{path}\n#{action}"
110
- end
152
+ def sign_string(path, action)
153
+ action = "x-akamai-acs-action:#{acs_action(action)}\n"
154
+ "#{path}\n#{action}"
155
+ end
111
156
  end
112
157
  end
113
158
  end
@@ -1,5 +1,5 @@
1
1
  module Fog
2
2
  module Akamai
3
- VERSION = '0.1.1'
3
+ VERSION = '0.5.0'
4
4
  end
5
5
  end
data/lib/fog/akamai.rb CHANGED
@@ -14,9 +14,7 @@ module Fog
14
14
 
15
15
  module Shared
16
16
  def full_path(path, directory = nil)
17
- if directory
18
- path = [directory.key, path].join('/')
19
- end
17
+ path = [directory.key, path].join('/') if directory
20
18
  path
21
19
  end
22
20
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: fog-akamai
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.1
4
+ version: 0.5.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Calin
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2015-11-05 00:00:00.000000000 Z
11
+ date: 2015-11-29 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
@@ -94,6 +94,34 @@ dependencies:
94
94
  - - "~>"
95
95
  - !ruby/object:Gem::Version
96
96
  version: '1.22'
97
+ - !ruby/object:Gem::Dependency
98
+ name: rubocop
99
+ requirement: !ruby/object:Gem::Requirement
100
+ requirements:
101
+ - - "~>"
102
+ - !ruby/object:Gem::Version
103
+ version: '0.35'
104
+ type: :development
105
+ prerelease: false
106
+ version_requirements: !ruby/object:Gem::Requirement
107
+ requirements:
108
+ - - "~>"
109
+ - !ruby/object:Gem::Version
110
+ version: '0.35'
111
+ - !ruby/object:Gem::Dependency
112
+ name: timecop
113
+ requirement: !ruby/object:Gem::Requirement
114
+ requirements:
115
+ - - "~>"
116
+ - !ruby/object:Gem::Version
117
+ version: 0.8.0
118
+ type: :development
119
+ prerelease: false
120
+ version_requirements: !ruby/object:Gem::Requirement
121
+ requirements:
122
+ - - "~>"
123
+ - !ruby/object:Gem::Version
124
+ version: 0.8.0
97
125
  - !ruby/object:Gem::Dependency
98
126
  name: fog-core
99
127
  requirement: !ruby/object:Gem::Requirement
@@ -146,6 +174,7 @@ extensions: []
146
174
  extra_rdoc_files: []
147
175
  files:
148
176
  - ".gitignore"
177
+ - ".rubocop.yml"
149
178
  - ".ruby-gemset"
150
179
  - ".ruby-version"
151
180
  - ".travis.yml"
@@ -166,9 +195,17 @@ files:
166
195
  - lib/fog/akamai/models/storage/file.rb
167
196
  - lib/fog/akamai/models/storage/files.rb
168
197
  - lib/fog/akamai/parsers/storage/dir.rb
198
+ - lib/fog/akamai/parsers/storage/du.rb
199
+ - lib/fog/akamai/requests/storage/delete.rb
169
200
  - lib/fog/akamai/requests/storage/dir.rb
170
201
  - lib/fog/akamai/requests/storage/download.rb
202
+ - lib/fog/akamai/requests/storage/du.rb
203
+ - lib/fog/akamai/requests/storage/mkdir.rb
204
+ - lib/fog/akamai/requests/storage/mtime.rb
205
+ - lib/fog/akamai/requests/storage/rename.rb
206
+ - lib/fog/akamai/requests/storage/rmdir.rb
171
207
  - lib/fog/akamai/requests/storage/stat.rb
208
+ - lib/fog/akamai/requests/storage/symlink.rb
172
209
  - lib/fog/akamai/requests/storage/upload.rb
173
210
  - lib/fog/akamai/storage.rb
174
211
  - lib/fog/akamai/version.rb
@@ -192,7 +229,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
192
229
  version: '0'
193
230
  requirements: []
194
231
  rubyforge_project:
195
- rubygems_version: 2.4.6
232
+ rubygems_version: 2.4.8
196
233
  signing_key:
197
234
  specification_version: 4
198
235
  summary: Module for 'fog' gem to support Akamai