fog-akamai 0.1.1 → 0.5.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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