azure-armrest 0.0.6 → 0.0.7
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGES +6 -0
- data/lib/azure/armrest/model/base_model.rb +44 -29
- data/lib/azure/armrest/model/storage_account.rb +98 -7
- data/lib/azure/armrest/resource_group_service.rb +3 -5
- data/lib/azure/armrest/resource_provider_service.rb +22 -11
- data/lib/azure/armrest/version.rb +1 -1
- metadata +3 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: defac8d47729576388ef8ee13366182f5d2ba617
|
4
|
+
data.tar.gz: 226dd08875b1bcee85ce4ada88c0d31653a7c0d5
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: a111aa4f81c3a43699a5f39f78cbbadbc84361d18a58d40e4e5f803ad1ab2b90daa22d261ce3f58241ad787cd5c01c2678b91ec70ef977c6078d93bc74359ad1
|
7
|
+
data.tar.gz: 90cc8169495c37470eee3bc75b93fb907b93aa15a4a8f2c67c6cae34af5543b353a576f337f207f8c5da040a2ca4c4bf16e37a5bf92bb6821030c3669ad6b6bd
|
data/CHANGES
CHANGED
@@ -1,3 +1,9 @@
|
|
1
|
+
= 0.0.7 - 5-Nov-2015
|
2
|
+
* Refactored our BaseModel class so that it no longer uses Delegate or OpenStruct.
|
3
|
+
* Added more methods to the StorageAccount model, and modified methods so that
|
4
|
+
any options are always the last argument.
|
5
|
+
* Bug fix for the StorageAccount#all_blobs method.
|
6
|
+
|
1
7
|
= 0.0.6 - 23-Oct-2015
|
2
8
|
* Defined a custom == method for the BaseModel class.
|
3
9
|
* The TemplateDeployment#properties.outputs now returns a hash.
|
@@ -1,22 +1,21 @@
|
|
1
|
-
require 'delegate'
|
2
|
-
require 'ostruct'
|
3
|
-
|
4
1
|
module Azure
|
5
2
|
module Armrest
|
6
3
|
# Base class for JSON wrapper classes. Each Service class should have
|
7
4
|
# a corresponding class that wraps the JSON it collects, and each of
|
8
5
|
# them should subclass this base class.
|
9
|
-
class BaseModel
|
6
|
+
class BaseModel
|
7
|
+
# Initially inherit the exclusion list from parent class or create an empty Set.
|
10
8
|
def self.excl_list
|
11
|
-
# initially inherit the exclusion list from parent class or create an empty Set
|
12
9
|
@excl_list ||= superclass.respond_to?(:excl_list, true) ? superclass.send(:excl_list) : Set.new
|
13
10
|
end
|
11
|
+
|
14
12
|
private_class_method :excl_list
|
15
13
|
|
14
|
+
# Merge the declared exclusive attributes to the existing list.
|
16
15
|
def self.attr_hash(*attrs)
|
17
|
-
# merge the declared exclusive attributes to the existing list
|
18
16
|
@excl_list = excl_list | Set.new(attrs.map(&:to_s))
|
19
17
|
end
|
18
|
+
|
20
19
|
private_class_method :attr_hash
|
21
20
|
|
22
21
|
attr_hash :tags
|
@@ -62,8 +61,7 @@ module Azure
|
|
62
61
|
@json = json
|
63
62
|
end
|
64
63
|
|
65
|
-
|
66
|
-
super(@ostruct)
|
64
|
+
__setobj__(hash)
|
67
65
|
end
|
68
66
|
|
69
67
|
def resource_group
|
@@ -103,37 +101,54 @@ module Azure
|
|
103
101
|
__getobj__.eql?(other.__getobj__)
|
104
102
|
end
|
105
103
|
|
104
|
+
# Support hash style accessors
|
105
|
+
def [](key)
|
106
|
+
__getobj__[key]
|
107
|
+
end
|
108
|
+
|
109
|
+
def []=(key, val)
|
110
|
+
key_exists = __getobj__.include?(key)
|
111
|
+
__getobj__[key] = val
|
112
|
+
|
113
|
+
return if key_exists
|
114
|
+
add_accessor_methods(snake_case(key), key)
|
115
|
+
end
|
116
|
+
|
106
117
|
protected
|
107
118
|
|
108
|
-
#
|
109
|
-
# not use this method directly.
|
119
|
+
# Do not use this method directly.
|
110
120
|
def __getobj__
|
111
|
-
@
|
121
|
+
@hashobj
|
112
122
|
end
|
113
123
|
|
114
|
-
#
|
115
|
-
#
|
124
|
+
# Create snake_case accessor methods for all hash attributes
|
125
|
+
# Use _alias if an accessor conflicts with existing methods
|
116
126
|
def __setobj__(obj)
|
127
|
+
@hashobj = obj
|
117
128
|
excl_list = self.class.send(:excl_list)
|
118
|
-
obj.
|
119
|
-
|
120
|
-
|
121
|
-
if
|
122
|
-
newval =
|
123
|
-
obj
|
124
|
-
elsif
|
125
|
-
obj
|
129
|
+
obj.each do |key, value|
|
130
|
+
snake = snake_case(key)
|
131
|
+
unless excl_list.include?(snake) # Must deal with nested models
|
132
|
+
if value.is_a?(Array)
|
133
|
+
newval = value.map { |elem| elem.is_a?(Hash) ? @embedModel.new(elem) : elem }
|
134
|
+
obj[key] = newval
|
135
|
+
elsif value.is_a?(Hash)
|
136
|
+
obj[key] = @embedModel.new(value)
|
126
137
|
end
|
127
138
|
end
|
128
139
|
|
129
|
-
snake
|
140
|
+
add_accessor_methods(snake, key)
|
141
|
+
end
|
142
|
+
end
|
143
|
+
|
144
|
+
def add_accessor_methods(method, key)
|
145
|
+
method.prepend('_') if methods.include?(method.to_sym)
|
146
|
+
instance_eval { define_singleton_method(method) { __getobj__[key] } }
|
147
|
+
instance_eval { define_singleton_method("#{method}=") { |val| __getobj__[key] = val } }
|
148
|
+
end
|
130
149
|
|
131
|
-
|
132
|
-
|
133
|
-
rescue SyntaxError
|
134
|
-
next
|
135
|
-
end
|
136
|
-
}
|
150
|
+
def snake_case(name)
|
151
|
+
name.to_s.gsub(/(.)([A-Z])/,'\1_\2').downcase
|
137
152
|
end
|
138
153
|
end
|
139
154
|
|
@@ -169,4 +184,4 @@ module Azure
|
|
169
184
|
end
|
170
185
|
end
|
171
186
|
|
172
|
-
require_relative 'storage_account'
|
187
|
+
require_relative 'storage_account'
|
@@ -7,7 +7,9 @@ module Azure
|
|
7
7
|
class StorageAccount < BaseModel
|
8
8
|
# Classes used to wrap container and blob information.
|
9
9
|
class Container < BaseModel; end
|
10
|
+
class ContainerProperty < BaseModel; end
|
10
11
|
class Blob < BaseModel; end
|
12
|
+
class BlobProperty < BaseModel; end
|
11
13
|
class BlobServiceProperty < BaseModel; end
|
12
14
|
class BlobServiceStat < BaseModel; end
|
13
15
|
class BlobMetadata < BaseModel; end
|
@@ -35,6 +37,50 @@ module Azure
|
|
35
37
|
end
|
36
38
|
end
|
37
39
|
|
40
|
+
# Returns the properties for the given container +name+ using account +key+.
|
41
|
+
# If no key is provided, it is assumed that the StorageAccount object
|
42
|
+
# includes the key1 property.
|
43
|
+
#
|
44
|
+
def container_properties(name, key = nil)
|
45
|
+
key ||= properties.key1
|
46
|
+
|
47
|
+
response = blob_response(key, "restype=container", name)
|
48
|
+
|
49
|
+
ContainerProperty.new(response.headers)
|
50
|
+
end
|
51
|
+
|
52
|
+
# Returns the properties for the given container +name+ using account +key+.
|
53
|
+
# If no key is provided, it is assumed that the StorageAccount object
|
54
|
+
# includes the key1 property.
|
55
|
+
#
|
56
|
+
# If the returned object does not contain x_ms_blob_public_access then
|
57
|
+
# the container is private to the account owner. You can also use the
|
58
|
+
# :private? method to determine if the account is public or private.
|
59
|
+
#
|
60
|
+
def container_acl(name, key = nil)
|
61
|
+
key ||= properties.key1
|
62
|
+
|
63
|
+
response = blob_response(key, "restype=container&comp=acl", name)
|
64
|
+
response.headers[:private?] = response.headers.include?(:x_ms_blob_public_access) ? false : true
|
65
|
+
|
66
|
+
ContainerProperty.new(response.headers)
|
67
|
+
end
|
68
|
+
|
69
|
+
# Return the blob properties for the given +blob+ found in +container+. You may
|
70
|
+
# optionally provide a date to get information for a snapshot.
|
71
|
+
#
|
72
|
+
def blob_properties(container, blob, key = nil, options = {})
|
73
|
+
key ||= properties.key1
|
74
|
+
|
75
|
+
url = File.join(properties.primary_endpoints.blob, container, blob)
|
76
|
+
url += "?snapshot=" + options[:date] if options[:date]
|
77
|
+
|
78
|
+
headers = build_headers(url, key, :verb => 'HEAD')
|
79
|
+
response = RestClient.head(url, headers)
|
80
|
+
|
81
|
+
BlobProperty.new(response.headers)
|
82
|
+
end
|
83
|
+
|
38
84
|
# Return a list of blobs for the given +container+ using the given +key+
|
39
85
|
# or the key1 property of the StorageAccount object.
|
40
86
|
#
|
@@ -49,7 +95,9 @@ module Azure
|
|
49
95
|
doc = Nokogiri::XML(response.body)
|
50
96
|
|
51
97
|
doc.xpath('//Blobs/Blob').map do |node|
|
52
|
-
Blob.new(Hash.from_xml(node.to_s)['Blob'])
|
98
|
+
blob = Blob.new(Hash.from_xml(node.to_s)['Blob'])
|
99
|
+
blob[:container] = container
|
100
|
+
blob
|
53
101
|
end
|
54
102
|
end
|
55
103
|
|
@@ -60,8 +108,8 @@ module Azure
|
|
60
108
|
array = []
|
61
109
|
threads = []
|
62
110
|
|
63
|
-
containers.each do |container|
|
64
|
-
threads << Thread.new(container, key){ |c,k| array << blobs(c.name, k) }
|
111
|
+
containers(key).each do |container|
|
112
|
+
threads << Thread.new(container, key) { |c, k| array << blobs(c.name, k) }
|
65
113
|
end
|
66
114
|
|
67
115
|
threads.each(&:join)
|
@@ -71,7 +119,7 @@ module Azure
|
|
71
119
|
|
72
120
|
# Returns the blob service properties for the current storage account.
|
73
121
|
#
|
74
|
-
def
|
122
|
+
def blob_service_properties(key = nil)
|
75
123
|
key ||= properties.key1
|
76
124
|
|
77
125
|
response = blob_response(key, "restype=service&comp=properties")
|
@@ -84,11 +132,11 @@ module Azure
|
|
84
132
|
# Return metadata for the given +blob+ within +container+. You may
|
85
133
|
# specify a +date+ to retrieve metadata for a specific snapshot.
|
86
134
|
#
|
87
|
-
def blob_metadata(container, blob,
|
135
|
+
def blob_metadata(container, blob, key = nil, options = {})
|
88
136
|
key ||= properties.key1
|
89
137
|
|
90
138
|
query = "comp=metadata"
|
91
|
-
query << "&snapshot
|
139
|
+
query << "&snapshot=" + options[:date] if options[:date]
|
92
140
|
|
93
141
|
response = blob_response(key, query, container, blob)
|
94
142
|
|
@@ -109,6 +157,48 @@ module Azure
|
|
109
157
|
BlobServiceStat.new(Hash.from_xml(doc.to_s)[toplevel])
|
110
158
|
end
|
111
159
|
|
160
|
+
# Copy the blob from the source container/blob to the destination container/blob.
|
161
|
+
# If no destination blob name is provided, it will use the same name as the source.
|
162
|
+
#
|
163
|
+
# Example:
|
164
|
+
#
|
165
|
+
# source = "Microsoft.Compute/Images/your_container/your-img-osDisk.123xyz.vhd"
|
166
|
+
# storage_acct.copy_blob('system', source, 'vhds', nil, your_key)
|
167
|
+
#
|
168
|
+
def copy_blob(src_container, src_blob, dst_container, dst_blob = nil, key = nil)
|
169
|
+
key ||= properties.key1
|
170
|
+
dst_blob ||= File.basename(src_blob)
|
171
|
+
|
172
|
+
dst_url = File.join(properties.primary_endpoints.blob, dst_container, dst_blob)
|
173
|
+
src_url = File.join(properties.primary_endpoints.blob, src_container, src_blob)
|
174
|
+
|
175
|
+
options = {'x-ms-copy-source' => src_url, 'If-None-Match' => '*', :verb => 'PUT'}
|
176
|
+
|
177
|
+
headers = build_headers(dst_url, key, options)
|
178
|
+
|
179
|
+
# RestClient will set the Content-Type to application/x-www-form-urlencoded.
|
180
|
+
# We must override this setting or the request will fail.
|
181
|
+
headers['Content-Type'] = ''
|
182
|
+
|
183
|
+
response = RestClient.put(dst_url, '', headers)
|
184
|
+
|
185
|
+
Blob.new(response.headers)
|
186
|
+
end
|
187
|
+
|
188
|
+
# Delete the given +blob+ found in +container+.
|
189
|
+
#
|
190
|
+
def delete_blob(container, blob, key = nil, options = {})
|
191
|
+
key ||= properties.key1
|
192
|
+
|
193
|
+
url = File.join(properties.primary_endpoints.blob, container, blob)
|
194
|
+
url += "?snapshot=" + options[:date] if options[:date]
|
195
|
+
|
196
|
+
headers = build_headers(url, key, :verb => 'DELETE')
|
197
|
+
response = RestClient.delete(url, headers)
|
198
|
+
|
199
|
+
true
|
200
|
+
end
|
201
|
+
|
112
202
|
private
|
113
203
|
|
114
204
|
# Using the blob primary endpoint as a base, join any arguments to the
|
@@ -122,7 +212,7 @@ module Azure
|
|
122
212
|
|
123
213
|
# Set the headers needed, including the Authorization header.
|
124
214
|
#
|
125
|
-
def build_headers(url, key)
|
215
|
+
def build_headers(url, key, additional_headers = {})
|
126
216
|
sig = Signature.new(url, key)
|
127
217
|
|
128
218
|
headers = {
|
@@ -131,6 +221,7 @@ module Azure
|
|
131
221
|
:auth_string => true
|
132
222
|
}
|
133
223
|
|
224
|
+
headers.merge!(additional_headers)
|
134
225
|
headers['Authorization'] = sig.blob_signature(headers)
|
135
226
|
|
136
227
|
headers
|
@@ -13,16 +13,14 @@ module Azure
|
|
13
13
|
end
|
14
14
|
|
15
15
|
# List all the resources for the current subscription. You can optionally
|
16
|
-
# pass :top or :filter options as well to restrict returned results.
|
17
|
-
#
|
18
|
-
# If you pass a :resource_group option, then only resources for that
|
19
|
-
# resource group are returned.
|
16
|
+
# pass :top or :filter options as well to restrict returned results. The
|
17
|
+
# :filter option only applies to tags.
|
20
18
|
#
|
21
19
|
# Examples:
|
22
20
|
#
|
23
21
|
# rgs = ResourceGroupService.new
|
24
22
|
# rgs.list(:top => 2)
|
25
|
-
# rgs.list(:filter => "
|
23
|
+
# rgs.list(:filter => "sometag=value")
|
26
24
|
#
|
27
25
|
def list(options = {})
|
28
26
|
url = build_url
|
@@ -40,23 +40,34 @@ module Azure
|
|
40
40
|
# this method are cached.
|
41
41
|
#
|
42
42
|
def list
|
43
|
-
|
44
|
-
|
45
|
-
|
43
|
+
_list.map{ |hash| Azure::Armrest::ResourceProvider.new(hash) }
|
44
|
+
end
|
45
|
+
|
46
|
+
def _list
|
47
|
+
response = rest_get(build_url)
|
48
|
+
JSON.parse(response)["value"]
|
46
49
|
end
|
50
|
+
private :_list
|
47
51
|
|
48
|
-
|
52
|
+
# Cannot directly cache list method, because Marshal used by chche_method
|
53
|
+
# cannot dump anonymous class, including the ones derived from Azure::Armrest::BaseModel
|
54
|
+
# Same applies to other cached methods in this class
|
55
|
+
cache_method(:_list, cache_time)
|
49
56
|
|
50
57
|
# Return information about a specific +namespace+ provider. The results
|
51
58
|
# of this method are cached.
|
52
59
|
#
|
53
60
|
def get(namespace)
|
61
|
+
Azure::Armrest::ResourceProvider.new(_get(namespace))
|
62
|
+
end
|
63
|
+
|
64
|
+
def _get(namespace)
|
54
65
|
url = build_url(namespace)
|
55
|
-
|
56
|
-
Azure::Armrest::ResourceProvider.new(response)
|
66
|
+
rest_get(url).body
|
57
67
|
end
|
68
|
+
private :_get
|
58
69
|
|
59
|
-
cache_method(:
|
70
|
+
cache_method(:_get, cache_time)
|
60
71
|
|
61
72
|
# Returns an array of geo-locations for the given +namespace+ provider.
|
62
73
|
# The results of this method are cached.
|
@@ -84,16 +95,16 @@ module Azure
|
|
84
95
|
#
|
85
96
|
def register(namespace)
|
86
97
|
url = build_url(namespace, 'register')
|
87
|
-
|
88
|
-
|
98
|
+
rest_post(url)
|
99
|
+
nil
|
89
100
|
end
|
90
101
|
|
91
102
|
# Unregister the current subscription from the +namespace+ provider.
|
92
103
|
#
|
93
104
|
def unregister(namespace)
|
94
105
|
url = build_url(namespace, 'unregister')
|
95
|
-
|
96
|
-
|
106
|
+
rest_post(url)
|
107
|
+
nil
|
97
108
|
end
|
98
109
|
|
99
110
|
private
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: azure-armrest
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.7
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Daniel J. Berger
|
@@ -11,7 +11,7 @@ authors:
|
|
11
11
|
autorequire:
|
12
12
|
bindir: bin
|
13
13
|
cert_chain: []
|
14
|
-
date: 2015-
|
14
|
+
date: 2015-11-06 00:00:00.000000000 Z
|
15
15
|
dependencies:
|
16
16
|
- !ruby/object:Gem::Dependency
|
17
17
|
name: json
|
@@ -232,7 +232,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
232
232
|
version: '0'
|
233
233
|
requirements: []
|
234
234
|
rubyforge_project:
|
235
|
-
rubygems_version: 2.
|
235
|
+
rubygems_version: 2.5.0
|
236
236
|
signing_key:
|
237
237
|
specification_version: 4
|
238
238
|
summary: An interface for ARM/JSON Azure REST API
|