Skip to content

Commit

Permalink
create, describe, and destroy elastic file systems
Browse files Browse the repository at this point in the history
  • Loading branch information
Eugene Howe committed Oct 5, 2016
1 parent df01e7b commit 98f3af9
Show file tree
Hide file tree
Showing 10 changed files with 439 additions and 0 deletions.
2 changes: 2 additions & 0 deletions lib/fog/aws.rb
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ module AWS
autoload :DataPipeline, File.expand_path('../aws/data_pipeline', __FILE__)
autoload :DynamoDB, File.expand_path('../aws/dynamodb', __FILE__)
autoload :ECS, File.expand_path('../aws/ecs', __FILE__)
autoload :EFS, File.expand_path('../aws/efs', __FILE__)
autoload :ELB, File.expand_path('../aws/elb', __FILE__)
autoload :EMR, File.expand_path('../aws/emr', __FILE__)
autoload :ElasticBeanstalk, File.expand_path('../aws/beanstalk', __FILE__)
Expand Down Expand Up @@ -66,6 +67,7 @@ module AWS
service(:dynamodb, 'DynamoDB')
service(:elasticache, 'Elasticache')
service(:ecs, 'ECS')
service(:efs, 'EFS')
service(:elb, 'ELB')
service(:emr, 'EMR')
service(:federation, 'Federation')
Expand Down
147 changes: 147 additions & 0 deletions lib/fog/aws/efs.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,147 @@
module Fog
module AWS
class EFS < Fog::Service
extend Fog::AWS::CredentialFetcher::ServiceMethods

class FileSystemInUse < Fog::Errors::Error; end

requires :aws_access_key_id, :aws_secret_access_key

model_path 'fog/aws/models/efs'
request_path 'fog/aws/requests/efs'

model :file_system
collection :file_systems

request :create_file_system
request :delete_file_system
request :describe_file_systems

class Mock
def self.data
@data ||= Hash.new do |hash, region|
hash[region] = Hash.new do |region_hash, key|
region_hash[key] = {
:file_systems => {}
}
end
end
end

def self.reset
@data = nil
end

def data
self.class.data[@region][@aws_access_key_id]
end

def reset
self.class.reset
end

attr_accessor :region

def initialize(options={})
@region = options[:region] || "us-east-1"
end
end

class Real
include Fog::AWS::CredentialFetcher::ConnectionMethods

def initialize(options={})
@connection_options = options[:connection_options] || {}
@instrumentor = options[:instrumentor]
@instrumentor_name = options[:instrumentor_name] || 'fog.aws.efs'

@region = 'us-east-1'
@host = options[:host] || "elasticfilesystem.#{@region}.amazonaws.com"
@port = options[:port] || 443
@scheme = options[:scheme] || "https"
@persistent = options[:persistent] || false
@connection = Fog::XML::Connection.new("#{@scheme}://#{@host}:#{@port}#{@path}", @persistent, @connection_options)
@version = options[:version] || '2015-02-01'
@path = options[:path] || "/#{@version}/"

setup_credentials(options)
end

def reload
@connection.reset
end

def setup_credentials(options)
@aws_access_key_id = options[:aws_access_key_id]
@aws_secret_access_key = options[:aws_secret_access_key]
@aws_session_token = options[:aws_session_token]
@aws_credentials_expire_at = options[:aws_credentials_expire_at]

#global services that have no region are signed with the us-east-1 region
#the only exception is GovCloud, which requires the region to be explicitly specified as us-gov-west-1
@signer = Fog::AWS::SignatureV4.new(@aws_access_key_id, @aws_secret_access_key, @region, 'elasticfilesystem')
end

def request(params)
refresh_credentials_if_expired
idempotent = params.delete(:idempotent)
parser = params.delete(:parser)
expects = params.delete(:expects) || 200
path = @path + params.delete(:path)
method = params.delete(:method) || 'GET'
request_body = Fog::JSON.encode(params)

body, headers = Fog::AWS.signed_params_v4(
params,
{
'Content-Type' => "application/x-amz-json-1.0",
},
{
:host => @host,
:path => path,
:port => @port,
:version => @version,
:signer => @signer,
:aws_session_token => @aws_session_token,
:method => method,
:body => request_body
}
)

if @instrumentor
@instrumentor.instrument("#{@instrumentor_name}.request", params) do
_request(body, headers, idempotent, parser, method, path, expects)
end
else
_request(body, headers, idempotent, parser, method, path, expects)
end
end

def _request(body, headers, idempotent, parser, method, path, expects)
response = @connection.request({
:body => body,
:expects => expects,
:idempotent => idempotent,
:headers => headers,
:method => method,
:parser => parser,
:path => path
})
unless response.body.empty?
response.body = Fog::JSON.decode(response.body)
end
response
rescue Excon::Errors::HTTPStatusError => error
match = Fog::AWS::Errors.match_error(error)
raise if match.empty?
raise case match[:message]
when /invalid file system id/i
Fog::AWS::EFS::NotFound.slurp(error, match[:message])
else
Fog::AWS::EFS::Error.slurp(error, "#{match[:code]} => #{match[:message]}")
end
end
end
end
end
end
36 changes: 36 additions & 0 deletions lib/fog/aws/models/efs/file_system.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
module Fog
module AWS
class EFS
class FileSystem < Fog::Model
identity :id, :aliases => 'FileSystemId'

attribute :owner_id, :aliases => 'OwnerId'
attribute :creation_token, :aliases => 'CreationToken'
attribute :performance_mode, :aliases => 'PerformanceMode'
attribute :creation_time, :aliases => 'CreationTime'
attribute :state, :aliases => 'LifeCycleState'
attribute :name, :aliases => 'Name'
attribute :number_of_mount_targets, :aliases => 'NumberOfMountTargets'
attribute :size_in_bytes, :aliases => 'SizeInBytes'

def destroy
requires :identity

service.delete_file_system(:id => self.identity)

true
end

def save
params = {
:creation_token => self.creation_token || Fog::Mock.random_hex(32)
}

params.merge!(:performance_mode => self.performance_mode) if self.performance_mode

merge_attributes(service.create_file_system(:creation_token => self.creation_token).body)
end
end
end
end
end
23 changes: 23 additions & 0 deletions lib/fog/aws/models/efs/file_systems.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
require 'fog/aws/models/efs/file_system'

module Fog
module AWS
class EFS
class FileSystems < Fog::Collection
model Fog::AWS::EFS::FileSystem

def all
data = service.describe_file_systems.body["FileSystems"]
load(data)
end

def get(identity)
data = service.describe_file_systems(:id => identity).body
new(data)
rescue Fog::AWS::EFS::NotFound
nil
end
end
end
end
end
51 changes: 51 additions & 0 deletions lib/fog/aws/requests/efs/create_file_system.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
module Fog
module AWS
class EFS
class Real
# Create a new, empty file system
# http://docs.aws.amazon.com/efs/latest/ug/API_CreateFileSystem.html
# ==== Parameters
# * CreationToken <~String> - String of up to 64 ASCII characters. Amazon EFS uses this to ensure idempotent creation.
# * PerformanceMode <~String> - (Optional) The PerformanceMode of the file system. We recommend generalPurpose performance mode for most file systems. File systems using the maxIO performance mode can scale to higher levels of aggregate throughput and operations per second with a tradeoff of slightly higher latencies for most file operations. This can't be changed after the file system has been created.
# ==== Returns
# * response<~Excon::Response>
# * body<~Hash>
def create_file_system(options={})
request({
:path => "file-systems",
:method => 'POST',
:expects => 201,
'CreationToken' => options[:creation_token],
'PerformanceMode' => options[:performance_mode] || 'generalPurpose'
})
end
end

class Mock
def create_file_system(options={})
response = Excon::Response.new

id = "fs-#{Fog::Mock.random_letters(8)}"
file_system = {
"OwnerId" => Fog::AWS::Mock.owner_id,
"CreationToken" => options[:creation_token],
"PerformanceMode" => options[:performance_mode] || "generalPurpose",
"FileSystemId" => id,
"CreationTime" => Time.now.to_i.to_f,
"LifeCycleState" => "creating",
"NumberOfMountTargets" => 0,
"SizeInBytes" => {
"Value" => 1024,
"Timestamp" => Time.now.to_i.to_f
}
}

self.data[:file_systems][id] = file_system
response.body = file_system
response.status = 201
response
end
end
end
end
end
46 changes: 46 additions & 0 deletions lib/fog/aws/requests/efs/delete_file_system.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
module Fog
module AWS
class EFS
class Real
# Delete a file system
# http://docs.aws.amazon.com/efs/latest/ug/API_DeleteFileSystem.html
# ==== Parameters
# * FileSystemId <~String> - ID of the file system you want to delete.
# ==== Response
# * response<~Excon::Response>
# * body - Empty
# * status - 204
def delete_file_system(options={})
id = options.delete(:id)
request({
:path => "file-systems/#{id}",
:method => 'DELETE',
:expects => 204,
'CreationToken' => options[:creation_token],
'PerformanceMode' => options[:performance_mode] || 'generalPurpose'
})
end
end

class Mock
def delete_file_system(options={})
id = options.delete(:id)

unless file_system = self.data[:file_systems][id]
raise Fog::AWS::EFS::NotFound.new("invalid file system ID: #{id}")
end

if file_system["NumberOfMountTargets"] > 0
raise Fog::AWS::EFS::FileSystemInUse.new("file system still has active mount targets")
end

self.data[:file_systems].delete(id)

response = Excon::Response.new
response.status = 204
response
end
end
end
end
end
62 changes: 62 additions & 0 deletions lib/fog/aws/requests/efs/describe_file_systems.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
module Fog
module AWS
class EFS
class Real
# Describe all or specified elastic file systems
# http://docs.aws.amazon.com/efs/latest/ug/API_DescribeFileSystems.html
# ==== Parameters
# * CreationToken <~String> - (Optional) Restricts the list to the file system with this creation token (String). You specify a creation token when you create an Amazon EFS file system.
# * FileSystemId <~String> - (Optional) ID of the file system whose description you want to retrieve (String).
# ==== Returns
# * response<~Excon::Response>:
# * body<~Hash>
def describe_file_systems(options={})
params = {}
if options[:marker]
params['Marker'] = options[:marker]
end
if options[:max_records]
params['MaxRecords'] = options[:max_records]
end
if options[:id]
params['FileSystemId'] = options[:id]
end
if options[:creation_token]
params['CreationToken'] = options[:creation_token]
end

request({
:path => "file-systems"
}.merge(params))
end
end

class Mock
def describe_file_systems(options={})
response = Excon::Response.new

file_systems = if id = options[:id]
if fs = self.data[:file_systems][id]
[fs]
else
raise Fog::AWS::EFS::NotFound.new("invalid file system ID: #{id}")
end
elsif creation_token = options[:creation_token]
fs = self.data[:file_systems].values.detect { |file_system| file_system["CreationToken"] == creation_token }
[fs]
else
self.data[:file_systems].values
end

file_systems.each do |file_system|
file_system['LifeCycleState'] = 'available'
self.data[:file_systems][file_system['FileSystemId']] = file_system
end

response.body = {"FileSystems" => file_systems}
response
end
end
end
end
end
12 changes: 12 additions & 0 deletions tests/models/efs/file_system_tests.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
Shindo.tests("AWS::EFS | file system", ["aws", "efs"]) do
file_system_params = {
:creation_token => "fogtoken#{rand(999).to_s}"
}

model_tests(Fog::AWS[:efs].file_systems, file_system_params, true)

file_system_params = {
:creation_token => "fogtoken#{rand(999).to_s}"
}
collection_tests(Fog::AWS[:efs].file_systems, file_system_params, true)
end
Loading

0 comments on commit 98f3af9

Please sign in to comment.