fog 0.0.58 → 0.0.59
Sign up to get free protection for your applications and to get access to all the features.
- data/README.rdoc +56 -72
- data/VERSION.yml +1 -1
- data/fog.gemspec +2 -2
- data/lib/fog.rb +9 -20
- data/lib/fog/aws.rb +119 -135
- data/lib/fog/aws/ec2.rb +31 -1
- data/lib/fog/aws/requests/ec2/authorize_security_group_ingress.rb +1 -2
- data/lib/fog/aws/requests/ec2/create_security_group.rb +1 -1
- data/lib/fog/aws/requests/ec2/run_instances.rb +1 -1
- data/lib/fog/connection.rb +14 -32
- data/lib/fog/rackspace.rb +21 -51
- data/lib/fog/rackspace/files.rb +102 -76
- data/lib/fog/rackspace/models/files/directories.rb +14 -3
- data/lib/fog/rackspace/models/files/directory.rb +3 -1
- data/lib/fog/rackspace/models/files/file.rb +3 -1
- data/lib/fog/rackspace/models/files/files.rb +4 -1
- data/lib/fog/rackspace/models/servers/flavor.rb +3 -1
- data/lib/fog/rackspace/models/servers/flavors.rb +16 -4
- data/lib/fog/rackspace/models/servers/image.rb +3 -1
- data/lib/fog/rackspace/models/servers/images.rb +18 -5
- data/lib/fog/rackspace/models/servers/server.rb +3 -1
- data/lib/fog/rackspace/models/servers/servers.rb +14 -3
- data/lib/fog/rackspace/requests/files/delete_container.rb +5 -13
- data/lib/fog/rackspace/requests/files/delete_object.rb +5 -13
- data/lib/fog/rackspace/requests/files/get_container.rb +5 -13
- data/lib/fog/rackspace/requests/files/get_containers.rb +5 -13
- data/lib/fog/rackspace/requests/files/get_object.rb +5 -13
- data/lib/fog/rackspace/requests/files/head_container.rb +5 -13
- data/lib/fog/rackspace/requests/files/head_containers.rb +5 -13
- data/lib/fog/rackspace/requests/files/head_object.rb +5 -13
- data/lib/fog/rackspace/requests/files/put_container.rb +5 -13
- data/lib/fog/rackspace/requests/files/put_object.rb +6 -14
- data/lib/fog/rackspace/requests/servers/create_image.rb +7 -15
- data/lib/fog/rackspace/requests/servers/create_server.rb +7 -15
- data/lib/fog/rackspace/requests/servers/delete_image.rb +7 -15
- data/lib/fog/rackspace/requests/servers/delete_server.rb +7 -15
- data/lib/fog/rackspace/requests/servers/get_flavor_details.rb +5 -13
- data/lib/fog/rackspace/requests/servers/get_server_details.rb +5 -13
- data/lib/fog/rackspace/requests/servers/list_addresses.rb +5 -13
- data/lib/fog/rackspace/requests/servers/list_flavors.rb +5 -13
- data/lib/fog/rackspace/requests/servers/list_flavors_detail.rb +5 -13
- data/lib/fog/rackspace/requests/servers/list_images.rb +5 -13
- data/lib/fog/rackspace/requests/servers/list_images_detail.rb +7 -15
- data/lib/fog/rackspace/requests/servers/list_private_addresses.rb +5 -13
- data/lib/fog/rackspace/requests/servers/list_public_addresses.rb +5 -13
- data/lib/fog/rackspace/requests/servers/list_servers.rb +5 -13
- data/lib/fog/rackspace/requests/servers/list_servers_detail.rb +7 -15
- data/lib/fog/rackspace/requests/servers/reboot_server.rb +5 -13
- data/lib/fog/rackspace/requests/servers/update_server.rb +5 -13
- data/lib/fog/rackspace/servers.rb +85 -71
- data/lib/fog/slicehost.rb +74 -67
- data/lib/fog/slicehost/models/flavor.rb +3 -1
- data/lib/fog/slicehost/models/flavors.rb +4 -1
- data/lib/fog/slicehost/models/image.rb +3 -1
- data/lib/fog/slicehost/models/images.rb +4 -1
- data/lib/fog/slicehost/models/server.rb +3 -1
- data/lib/fog/slicehost/models/servers.rb +4 -1
- data/lib/fog/slicehost/requests/create_slice.rb +5 -9
- data/lib/fog/slicehost/requests/delete_slice.rb +4 -10
- data/lib/fog/slicehost/requests/get_backups.rb +5 -9
- data/lib/fog/slicehost/requests/get_flavor.rb +5 -9
- data/lib/fog/slicehost/requests/get_flavors.rb +5 -9
- data/lib/fog/slicehost/requests/get_image.rb +5 -9
- data/lib/fog/slicehost/requests/get_images.rb +5 -9
- data/lib/fog/slicehost/requests/get_slice.rb +5 -9
- data/lib/fog/slicehost/requests/get_slices.rb +5 -9
- data/lib/fog/slicehost/requests/reboot_slice.rb +4 -10
- data/lib/fog/terremark.rb +60 -51
- data/lib/fog/terremark/requests/get_catalog.rb +5 -9
- data/lib/fog/terremark/requests/get_catalog_item.rb +5 -9
- data/lib/fog/terremark/requests/get_organization.rb +5 -9
- data/lib/fog/terremark/requests/get_organizations.rb +5 -9
- data/lib/fog/terremark/requests/get_vapp_template.rb +5 -9
- data/lib/fog/terremark/requests/get_vdc.rb +5 -9
- data/spec/rackspace/requests/servers/list_images_detail_spec.rb +0 -1
- data/spec/rackspace/requests/servers/reboot_server_spec.rb +3 -1
- data/spec/slicehost/requests/create_slice_spec.rb +1 -0
- metadata +3 -3
data/README.rdoc
CHANGED
@@ -1,64 +1,44 @@
|
|
1
1
|
= fog
|
2
2
|
|
3
|
-
fog helps you interact with cloud services.
|
3
|
+
fog helps you interact with cloud services.
|
4
4
|
|
5
|
-
|
5
|
+
The quick and dirty, top to bottom:
|
6
|
+
* Models provide a simplified interface, making clouds easier to work with and switch between.
|
7
|
+
* Requests allow power users to get the most out of the features of each individual cloud.
|
8
|
+
* Mocks make testing and integrating a breeze.
|
6
9
|
|
7
|
-
|
10
|
+
Put them together and you get a great cloud computing experience, but we are getting ahead of ourselves...
|
8
11
|
|
9
12
|
== Getting Started
|
10
13
|
|
11
|
-
|
12
|
-
After installing, just type 'fog' to get started.
|
13
|
-
If you don't have credentials setup it will let you know what to do.
|
14
|
-
|
15
|
-
Then just start playing around, fog should let you know if you are forget things.
|
16
|
-
|
17
|
-
For example if you try to create a server but leave out stuff:
|
18
|
-
|
19
|
-
server = AWS.servers.create
|
14
|
+
sudo gem install fog
|
20
15
|
|
21
|
-
|
16
|
+
Now just type 'fog' to trying stuff out, confident that fog should let you know what you need to do. Here is an example of wading through server creation for Amazon Elastic Compute Cloud:
|
22
17
|
|
18
|
+
>> server = AWS.servers.create
|
23
19
|
ArgumentError: image_id is required for this operation
|
20
|
+
>> server = AWS.servers.create(:image_id => 'ami-5ee70037')
|
21
|
+
<Fog::AWS::EC2::Server [...]>
|
22
|
+
>> server.destroy # cleanup after yourself or regret it, trust me
|
23
|
+
true
|
24
24
|
|
25
|
-
|
26
|
-
|
27
|
-
server = AWS.servers.create(:image_id => 'ami-5ee70037')
|
28
|
-
|
29
|
-
But don't forget to cleanup or you'll regret it when you get the bill:
|
25
|
+
== Collections
|
30
26
|
|
31
|
-
|
27
|
+
Nouns like Images and Servers are collections, which form the interface to the cloud.
|
28
|
+
Collections provide all, create, get and new methods.
|
29
|
+
* all fetches every object of that type from the cloud.
|
30
|
+
* create initializes a new record locally and then persists it to the cloud.
|
31
|
+
* get fetches a single object by its identity.
|
32
|
+
* new initializes a new record locally.
|
32
33
|
|
33
|
-
|
34
|
+
Common compute nouns are flavors, images and servers.
|
34
35
|
|
35
|
-
|
36
|
+
Common storage nouns are directory and file.
|
36
37
|
|
37
|
-
|
38
|
+
As an example, we'll try initializing and persisting a rackspace server:
|
38
39
|
|
39
40
|
require 'fog'
|
40
41
|
|
41
|
-
# initialize a connection to Amazon Elastic Compute Cloud
|
42
|
-
connection = Fog::AWS::EC2.new(
|
43
|
-
:aws_access_key_id => id,
|
44
|
-
:aws_secret_access_key => key
|
45
|
-
)
|
46
|
-
|
47
|
-
# boot a gentoo server
|
48
|
-
server = connection.servers.new(:image_id => 'ami-5ee70037')
|
49
|
-
# you might also want to add the server to security groups, which goes like this:
|
50
|
-
# AWS.servers.create(:image_id => 'ami-5ee70037', :groups => ['web', 'db'])
|
51
|
-
|
52
|
-
# wait for it to be ready to do stuff
|
53
|
-
server.wait_for { ready? }
|
54
|
-
|
55
|
-
# DO STUFF
|
56
|
-
|
57
|
-
# shutdown the server
|
58
|
-
server.destroy
|
59
|
-
|
60
|
-
Now we will try again, but with Rackspace
|
61
|
-
|
62
42
|
# initialize a connection to Rackspace Servers
|
63
43
|
connection = Fog::Rackspace::Servers.new(
|
64
44
|
:rackspace_api_key => key,
|
@@ -76,53 +56,57 @@ Now we will try again, but with Rackspace
|
|
76
56
|
# shutdown the server
|
77
57
|
server.destroy
|
78
58
|
|
79
|
-
==
|
59
|
+
== Models
|
80
60
|
|
81
|
-
|
61
|
+
Many of the collection methods return individual objects, which provide destroy, save and wait_for methods.
|
62
|
+
* destroy will destroy the persisted object from the cloud
|
63
|
+
* save will persist the object to the cloud
|
64
|
+
* wait_for takes a block and waits for either the block to return true for the object or for a timeout (defaults to 10 minutes)
|
82
65
|
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
66
|
+
== Mocks
|
67
|
+
|
68
|
+
Mocking provides an in memory representation of clouds as you make different requests.
|
69
|
+
This representation allows subsequent calls to mimic the behavior of the cloud while eliminating the cost and time needed to actually run tests against various providers.
|
70
|
+
Mocking is easy to use, just write any functions as you normally would and then in your tests ensure you call:
|
71
|
+
|
72
|
+
Fog.mock!
|
73
|
+
|
74
|
+
Make sure you call it first (before you initialize any connections) and all your calls should now run in mock mode.
|
75
|
+
If you run into the edges of mock implementation it should let you know that they haven't been implemented yet.
|
88
76
|
|
89
|
-
|
90
|
-
directory = connection.directory.create(:name => 'directoryname')
|
77
|
+
== Requests
|
91
78
|
|
92
|
-
|
93
|
-
|
79
|
+
Requests allow you to dive deeper when the models just can't cut it.
|
80
|
+
For instance, ec2 provides methods related to reserved instances that don't have any models (yet anyway).
|
81
|
+
You can get a description of your reserved instances like this:
|
94
82
|
|
95
|
-
|
96
|
-
|
83
|
+
$ fog
|
84
|
+
>> AWS[:ec2].describe_reserved_instances
|
85
|
+
#<Excon::Response [...]>
|
97
86
|
|
98
|
-
|
99
|
-
file = directory.files.get('filename')
|
87
|
+
It will return an excon response, which has headers and body methods. Both give nice ruby hash representations of the result.
|
100
88
|
|
101
|
-
|
102
|
-
file.destroy
|
89
|
+
== Go forth and conquer
|
103
90
|
|
104
|
-
|
105
|
-
directory.destroy
|
91
|
+
That should give you some stuff to try and places to look.
|
106
92
|
|
107
|
-
|
93
|
+
You should try out the (varying) support fog has for:
|
94
|
+
* AWS [EC2, S3, SimpleDB]
|
95
|
+
* Rackspace [Files, Servers]
|
96
|
+
* Slicehost
|
97
|
+
* Terremark vCloud Express
|
98
|
+
|
99
|
+
Enjoy, and let me know what I can do to continue improving fog!
|
108
100
|
|
109
101
|
* Follow {@geemus}[http://twitter.com/geemus] on Twitter.
|
110
102
|
* See upcoming work in the {tracker}[http://www.pivotaltracker.com/projects/54635].
|
111
103
|
* Report bugs in {issues}[http://github.com/geemus/fog/issues].
|
112
104
|
|
113
|
-
== Supports
|
114
|
-
|
115
|
-
* AWS EC2
|
116
|
-
* AWS S3
|
117
|
-
* AWS SimpleDB (no models yet)
|
118
|
-
* Rackspace Files (no models yet, just getting started on requests)
|
119
|
-
* Rackspace Servers (some requests, server model, just getting started)
|
120
|
-
|
121
105
|
== Copyright
|
122
106
|
|
123
107
|
(The MIT License)
|
124
108
|
|
125
|
-
Copyright (c)
|
109
|
+
Copyright (c) 2010 {geemus (Wesley Beary)}[http://github.com/geemus]
|
126
110
|
|
127
111
|
Permission is hereby granted, free of charge, to any person obtaining
|
128
112
|
a copy of this software and associated documentation files (the
|
data/VERSION.yml
CHANGED
data/fog.gemspec
CHANGED
@@ -5,11 +5,11 @@
|
|
5
5
|
|
6
6
|
Gem::Specification.new do |s|
|
7
7
|
s.name = %q{fog}
|
8
|
-
s.version = "0.0.
|
8
|
+
s.version = "0.0.59"
|
9
9
|
|
10
10
|
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
11
11
|
s.authors = ["geemus (Wesley Beary)"]
|
12
|
-
s.date = %q{2010-03-
|
12
|
+
s.date = %q{2010-03-26}
|
13
13
|
s.default_executable = %q{fog}
|
14
14
|
s.description = %q{brings clouds to you}
|
15
15
|
s.email = %q{geemus@gmail.com}
|
data/lib/fog.rb
CHANGED
@@ -17,36 +17,25 @@ $LOAD_PATH.unshift __DIR__ unless
|
|
17
17
|
$LOAD_PATH.include?(__DIR__) ||
|
18
18
|
$LOAD_PATH.include?(File.expand_path(__DIR__))
|
19
19
|
|
20
|
+
require 'fog/collection'
|
21
|
+
require 'fog/connection'
|
22
|
+
require 'fog/model'
|
23
|
+
require 'fog/parser'
|
24
|
+
require 'fog/aws'
|
25
|
+
require 'fog/rackspace'
|
26
|
+
require 'fog/slicehost'
|
27
|
+
require 'fog/terremark'
|
28
|
+
|
20
29
|
module Fog
|
21
30
|
|
22
31
|
class MockNotImplemented < StandardError; end
|
23
32
|
|
24
33
|
def self.mock!
|
25
34
|
@mocking = true
|
26
|
-
self.reload
|
27
35
|
end
|
28
36
|
|
29
37
|
def self.mocking?
|
30
38
|
!!@mocking
|
31
39
|
end
|
32
40
|
|
33
|
-
def self.dependencies
|
34
|
-
[
|
35
|
-
'fog/collection.rb',
|
36
|
-
'fog/connection.rb',
|
37
|
-
'fog/model.rb',
|
38
|
-
'fog/parser.rb',
|
39
|
-
'fog/aws.rb',
|
40
|
-
'fog/rackspace.rb',
|
41
|
-
'fog/slicehost.rb',
|
42
|
-
'fog/terremark.rb'
|
43
|
-
]
|
44
|
-
end
|
45
|
-
|
46
|
-
def self.reload
|
47
|
-
self.dependencies.each {|dependency| load(dependency)}
|
48
|
-
end
|
49
|
-
|
50
41
|
end
|
51
|
-
|
52
|
-
Fog.dependencies.each {|dependency| require(dependency)}
|
data/lib/fog/aws.rb
CHANGED
@@ -1,19 +1,10 @@
|
|
1
|
+
require 'fog/aws/ec2.rb'
|
1
2
|
require 'fog/aws/s3'
|
2
3
|
require 'fog/aws/simpledb'
|
3
4
|
|
4
5
|
module Fog
|
5
6
|
module AWS
|
6
7
|
|
7
|
-
def self.dependencies
|
8
|
-
[
|
9
|
-
'fog/aws/ec2.rb'
|
10
|
-
]
|
11
|
-
end
|
12
|
-
|
13
|
-
def self.reload
|
14
|
-
self.dependencies.each {|dependency| load(dependency)}
|
15
|
-
end
|
16
|
-
|
17
8
|
def self.indexed_param(key, values)
|
18
9
|
params = {}
|
19
10
|
[*values].each_with_index do |value, index|
|
@@ -22,161 +13,154 @@ module Fog
|
|
22
13
|
params
|
23
14
|
end
|
24
15
|
|
25
|
-
|
26
|
-
srand(Time.now.to_i)
|
27
|
-
|
28
|
-
class Mock
|
29
|
-
|
30
|
-
def self.availability_zone
|
31
|
-
"us-east-1" << random_selection('abcd', 1)
|
32
|
-
end
|
16
|
+
class Mock
|
33
17
|
|
34
|
-
|
35
|
-
|
36
|
-
|
18
|
+
def self.availability_zone
|
19
|
+
"us-east-1" << random_selection('abcd', 1)
|
20
|
+
end
|
37
21
|
|
38
|
-
|
39
|
-
|
40
|
-
|
22
|
+
def self.box_usage
|
23
|
+
sprintf("%0.10f", rand / 100).to_f
|
24
|
+
end
|
41
25
|
|
42
|
-
|
43
|
-
|
44
|
-
|
26
|
+
def self.console_output
|
27
|
+
'This is my console. There are many like it, but this one is mine. My console is my best friend. It is my life. I must master it as I master my life. My console, without me, is useless. Without my console, I am useless.'
|
28
|
+
end
|
45
29
|
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
path << letters(rand(9) + 8)
|
50
|
-
end
|
51
|
-
{
|
52
|
-
"imageOwnerId" => letters(rand(5) + 4),
|
53
|
-
"productCodes" => [],
|
54
|
-
"kernelId" => kernel_id,
|
55
|
-
"ramdiskId" => ramdisk_id,
|
56
|
-
"imageState" => "available",
|
57
|
-
"imageId" => image_id,
|
58
|
-
"architecture" => "i386",
|
59
|
-
"isPublic" => true,
|
60
|
-
"imageLocation" => path.join('/'),
|
61
|
-
"imageType" => "machine"
|
62
|
-
}
|
63
|
-
end
|
30
|
+
def self.etag
|
31
|
+
hex(32)
|
32
|
+
end
|
64
33
|
|
65
|
-
|
66
|
-
|
67
|
-
|
34
|
+
def self.image
|
35
|
+
path = []
|
36
|
+
(rand(3) + 2).times do
|
37
|
+
path << letters(rand(9) + 8)
|
38
|
+
end
|
39
|
+
{
|
40
|
+
"imageOwnerId" => letters(rand(5) + 4),
|
41
|
+
"productCodes" => [],
|
42
|
+
"kernelId" => kernel_id,
|
43
|
+
"ramdiskId" => ramdisk_id,
|
44
|
+
"imageState" => "available",
|
45
|
+
"imageId" => image_id,
|
46
|
+
"architecture" => "i386",
|
47
|
+
"isPublic" => true,
|
48
|
+
"imageLocation" => path.join('/'),
|
49
|
+
"imageType" => "machine"
|
50
|
+
}
|
51
|
+
end
|
68
52
|
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
fingerprint << hex(2)
|
73
|
-
end
|
74
|
-
fingerprint.join(':')
|
75
|
-
end
|
53
|
+
def self.image_id
|
54
|
+
"ami-#{hex(8)}"
|
55
|
+
end
|
76
56
|
|
77
|
-
|
78
|
-
|
57
|
+
def self.key_fingerprint
|
58
|
+
fingerprint = []
|
59
|
+
20.times do
|
60
|
+
fingerprint << hex(2)
|
79
61
|
end
|
62
|
+
fingerprint.join(':')
|
63
|
+
end
|
80
64
|
|
81
|
-
|
82
|
-
|
83
|
-
|
65
|
+
def self.image_id
|
66
|
+
"ami-#{hex(8)}"
|
67
|
+
end
|
84
68
|
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
ip << numbers(rand(3) + 1).to_i.to_s # remove leading 0
|
89
|
-
end
|
90
|
-
ip.join('.')
|
91
|
-
end
|
69
|
+
def self.instance_id
|
70
|
+
"i-#{hex(8)}"
|
71
|
+
end
|
92
72
|
|
93
|
-
|
94
|
-
|
73
|
+
def self.ip_address
|
74
|
+
ip = []
|
75
|
+
4.times do
|
76
|
+
ip << numbers(rand(3) + 1).to_i.to_s # remove leading 0
|
95
77
|
end
|
78
|
+
ip.join('.')
|
79
|
+
end
|
96
80
|
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
key_material << base64(76)
|
101
|
-
end
|
102
|
-
key_material << base64(67) + '='
|
103
|
-
key_material << '-----END RSA PRIVATE KEY-----'
|
104
|
-
key_material.join("\n")
|
105
|
-
end
|
81
|
+
def self.kernel_id
|
82
|
+
"aki-#{hex(8)}"
|
83
|
+
end
|
106
84
|
|
107
|
-
|
108
|
-
|
85
|
+
def self.key_material
|
86
|
+
key_material = ['-----BEGIN RSA PRIVATE KEY-----']
|
87
|
+
20.times do
|
88
|
+
key_material << base64(76)
|
109
89
|
end
|
90
|
+
key_material << base64(67) + '='
|
91
|
+
key_material << '-----END RSA PRIVATE KEY-----'
|
92
|
+
key_material.join("\n")
|
93
|
+
end
|
110
94
|
|
111
|
-
|
112
|
-
|
113
|
-
|
95
|
+
def self.owner_id
|
96
|
+
numbers(12)
|
97
|
+
end
|
114
98
|
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
3.times do
|
119
|
-
request_id << hex(4)
|
120
|
-
end
|
121
|
-
request_id << hex(12)
|
122
|
-
request_id.join('-')
|
123
|
-
end
|
99
|
+
def self.ramdisk_id
|
100
|
+
"ari-#{hex(8)}"
|
101
|
+
end
|
124
102
|
|
125
|
-
|
126
|
-
|
103
|
+
def self.request_id
|
104
|
+
request_id = []
|
105
|
+
request_id << hex(8)
|
106
|
+
3.times do
|
107
|
+
request_id << hex(4)
|
127
108
|
end
|
109
|
+
request_id << hex(12)
|
110
|
+
request_id.join('-')
|
111
|
+
end
|
128
112
|
|
129
|
-
|
130
|
-
|
131
|
-
|
113
|
+
def self.reservation_id
|
114
|
+
"r-#{hex(8)}"
|
115
|
+
end
|
132
116
|
|
133
|
-
|
134
|
-
|
135
|
-
|
117
|
+
def self.snapshot_id
|
118
|
+
"snap-#{hex(8)}"
|
119
|
+
end
|
136
120
|
|
137
|
-
|
121
|
+
def self.volume_id
|
122
|
+
"vol-#{hex(8)}"
|
123
|
+
end
|
138
124
|
|
139
|
-
|
140
|
-
selection = ''
|
141
|
-
length.times do
|
142
|
-
position = rand(characters.length)
|
143
|
-
selection << characters[position..position]
|
144
|
-
end
|
145
|
-
selection
|
146
|
-
end
|
125
|
+
private
|
147
126
|
|
148
|
-
|
149
|
-
|
150
|
-
|
151
|
-
|
152
|
-
|
127
|
+
def self.random_selection(characters, length)
|
128
|
+
selection = ''
|
129
|
+
length.times do
|
130
|
+
position = rand(characters.length)
|
131
|
+
selection << characters[position..position]
|
153
132
|
end
|
133
|
+
selection
|
134
|
+
end
|
154
135
|
|
155
|
-
|
156
|
-
|
157
|
-
|
158
|
-
|
159
|
-
|
160
|
-
|
136
|
+
def self.letters(length)
|
137
|
+
random_selection(
|
138
|
+
'abcdefghijklmnopqrstuvwxyz',
|
139
|
+
length
|
140
|
+
)
|
141
|
+
end
|
161
142
|
|
162
|
-
|
163
|
-
|
164
|
-
|
165
|
-
|
166
|
-
|
167
|
-
|
143
|
+
def self.numbers(length)
|
144
|
+
random_selection(
|
145
|
+
'0123456789',
|
146
|
+
length
|
147
|
+
)
|
148
|
+
end
|
168
149
|
|
169
|
-
|
170
|
-
|
171
|
-
|
172
|
-
|
173
|
-
|
174
|
-
|
150
|
+
def self.hex(length)
|
151
|
+
random_selection(
|
152
|
+
'0123456789abcdef',
|
153
|
+
length
|
154
|
+
)
|
155
|
+
end
|
175
156
|
|
157
|
+
def self.base64(length)
|
158
|
+
random_selection(
|
159
|
+
"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/",
|
160
|
+
length
|
161
|
+
)
|
176
162
|
end
|
177
|
-
end
|
178
163
|
|
164
|
+
end
|
179
165
|
end
|
180
166
|
end
|
181
|
-
|
182
|
-
Fog::AWS.reload
|