initial deliverable from the contractor.

This commit is contained in:
Barry Steinglass 2012-06-06 11:12:35 -07:00
Коммит 3e5a887b07
50 изменённых файлов: 2869 добавлений и 0 удалений

Двоичные данные
.DS_Store поставляемый Normal file

Двоичный файл не отображается.

23
Gemfile Executable file
Просмотреть файл

@ -0,0 +1,23 @@
source "http://rubygems.org"
# Add dependencies required to use your gem here.
# Example:
# gem "activesupport", ">= 2.3.5"
gemspec
#gem "chef", "~> 0.10.8"
# Add dependencies to develop your gem here.
# Include everything needed to run rake, tests, features, etc.
group :development do
gem "rspec", "~> 2.8.0"
gem "rdoc", "~> 3.12"
gem "bundler", "~> 1.0.0"
gem "jeweler", "~> 1.8.3"
gem "rcov", ">= 0"
gem "guard-rspec"
gem "libnotify"
gem "rubygems-bundler", "~> 0.2.8"
gem "interactive_editor"
gem "equivalent-xml", "~> 0.2.9"
end

110
Gemfile.lock Executable file
Просмотреть файл

@ -0,0 +1,110 @@
PATH
remote: .
specs:
knife-azure (0.5.11)
chef (~> 0.10)
nokogiri
GEM
remote: http://rubygems.org/
specs:
bunny (0.7.9)
chef (0.10.8)
bunny (>= 0.6.0)
erubis
highline
json (>= 1.4.4, <= 1.6.1)
mixlib-authentication (>= 1.1.0)
mixlib-cli (>= 1.1.0)
mixlib-config (>= 1.1.2)
mixlib-log (>= 1.3.0)
moneta
net-ssh (~> 2.1.3)
net-ssh-multi (~> 1.1.0)
ohai (>= 0.6.0)
rest-client (>= 1.0.4, < 1.7.0)
treetop (~> 1.4.9)
uuidtools
diff-lcs (1.1.3)
equivalent-xml (0.2.9)
nokogiri (>= 1.4.3)
erubis (2.7.0)
ffi (1.0.11)
git (1.2.5)
guard (1.0.1)
ffi (>= 0.5.0)
thor (~> 0.14.6)
guard-rspec (0.7.0)
guard (>= 0.10.0)
highline (1.6.11)
interactive_editor (0.0.10)
spoon (>= 0.0.1)
ipaddress (0.8.0)
jeweler (1.8.3)
bundler (~> 1.0)
git (>= 1.2.5)
rake
rdoc
json (1.6.1)
libnotify (0.7.2)
mime-types (1.18)
mixlib-authentication (1.1.4)
mixlib-log
mixlib-cli (1.2.2)
mixlib-config (1.1.2)
mixlib-log (1.3.0)
moneta (0.6.0)
net-ssh (2.1.4)
net-ssh-gateway (1.1.0)
net-ssh (>= 1.99.1)
net-ssh-multi (1.1)
net-ssh (>= 2.1.4)
net-ssh-gateway (>= 0.99.0)
nokogiri (1.5.0)
ohai (0.6.12)
ipaddress
mixlib-cli
mixlib-config
mixlib-log
systemu
yajl-ruby
polyglot (0.3.3)
rake (0.9.2.2)
rcov (1.0.0)
rdoc (3.12)
json (~> 1.4)
rest-client (1.6.7)
mime-types (>= 1.16)
rspec (2.8.0)
rspec-core (~> 2.8.0)
rspec-expectations (~> 2.8.0)
rspec-mocks (~> 2.8.0)
rspec-core (2.8.0)
rspec-expectations (2.8.0)
diff-lcs (~> 1.1.2)
rspec-mocks (2.8.0)
rubygems-bundler (0.2.8)
spoon (0.0.1)
systemu (2.5.0)
thor (0.14.6)
treetop (1.4.10)
polyglot
polyglot (>= 0.3.1)
uuidtools (2.1.2)
yajl-ruby (1.1.0)
PLATFORMS
ruby
DEPENDENCIES
bundler (~> 1.0.0)
equivalent-xml (~> 0.2.9)
guard-rspec
interactive_editor
jeweler (~> 1.8.3)
knife-azure!
libnotify
rcov
rdoc (~> 3.12)
rspec (~> 2.8.0)
rubygems-bundler (~> 0.2.8)

8
Guardfile Executable file
Просмотреть файл

@ -0,0 +1,8 @@
# A sample Guardfile
# More info at https://github.com/guard/guard#readme
guard :rspec, :version => 2 do
watch(%r{^spec/.+_spec\.rb$})
watch(%r{^lib/(.+)\.rb$}) # { |m| "spec/lib/#{m[1]}_spec.rb" }
watch('spec/spec_helper.rb') { "spec" }
end

20
LICENSE.txt Executable file
Просмотреть файл

@ -0,0 +1,20 @@
Copyright (c) 2012 Barry Davis
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
"Software"), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

57
Rakefile Executable file
Просмотреть файл

@ -0,0 +1,57 @@
# encoding: utf-8
require 'rubygems'
require 'bundler'
begin
Bundler.setup(:default, :development)
rescue Bundler::BundlerError => e
$stderr.puts e.message
$stderr.puts "Run `bundle install` to install missing gems"
exit e.status_code
end
require 'rake'
require 'jeweler'
Jeweler::Tasks.new do |gem|
# gem is a Gem::Specification... see http://docs.rubygems.org/read/chapter/20 for more options
gem.name = "knife-azure"
gem.homepage = "http://github.com/northwestcommercial/knife-azure"
gem.license = "MIT"
gem.summary = %Q{TODO: one-line summary of your gem}
gem.description = %Q{TODO: longer description of your gem}
gem.email = "barryfromseattle@gmail.com"
gem.authors = ["Barry Davis"]
# dependencies defined in Gemfile
end
Jeweler::RubygemsDotOrgTasks.new
require 'rspec/core'
require 'rspec/core/rake_task'
RSpec::Core::RakeTask.new(:spec) do |spec|
spec.pattern = FileList['spec/unit/**/*_spec.rb']
end
RSpec::Core::RakeTask.new(:functional) do |spec|
spec.pattern = FileList['spec/functional/**/*_test.rb']
end
RSpec::Core::RakeTask.new(:integration) do |spec|
spec.pattern = FileList['spec/integration/**/*_test.rb']
end
RSpec::Core::RakeTask.new(:rcov) do |spec|
spec.pattern = 'spec/**/*_spec.rb'
spec.rcov = true
end
task :default => :spec
require 'rdoc/task'
Rake::RDocTask.new do |rdoc|
version = File.exist?('VERSION') ? File.read('VERSION') : ""
rdoc.rdoc_dir = 'rdoc'
rdoc.title = "knife-azure #{version}"
rdoc.rdoc_files.include('README*')
rdoc.rdoc_files.include('lib/**/*.rb')
end

22
knife-azure.gemspec Executable file
Просмотреть файл

@ -0,0 +1,22 @@
# -*- encoding: utf-8 -*-
$:.push File.expand_path("../lib", __FILE__)
require "knife-azure/version"
Gem::Specification.new do |s|
s.name = "knife-azure"
s.version = Knife::Azure::VERSION
s.has_rdoc = true
s.authors = ["Barry Davis"]
s.email = ["barryd@jetstreamsoftware.com"]
s.homepage = "http://wiki.opscode.com/display/chef"
s.summary = "Azure Support for Chef's Knife Command"
s.description = s.summary
s.files = `git ls-files`.split("\n")
s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
s.add_dependency "chef", "~> 0.10"
s.add_dependency "nokogiri"
s.require_paths = ["lib"]
end

Двоичные данные
lib/.DS_Store поставляемый Normal file

Двоичный файл не отображается.

75
lib/azure/connection.rb Executable file
Просмотреть файл

@ -0,0 +1,75 @@
#
# Author:: Barry Davis (barryd@jetstreamsoftware.com)
# Copyright:: Copyright (c) 2010-2011 Opscode, Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
require File.expand_path('../utility', __FILE__)
require File.expand_path('../rest', __FILE__)
require File.expand_path('../host', __FILE__)
require File.expand_path('../deploy', __FILE__)
require File.expand_path('../role', __FILE__)
require File.expand_path('../disk', __FILE__)
require File.expand_path('../image', __FILE__)
class Azure
class Connection
include AzureAPI
attr_accessor :hosts, :rest, :images, :deploys, :roles, :disks
def initialize(params={})
@rest = Rest.new(params)
@hosts = Hosts.new(self)
@images = Images.new(self)
@deploys = Deploys.new(self)
@roles = Roles.new(self)
@disks = Disks.new(self)
end
def query_azure(service_name, verb = 'get', body = '')
Chef::Log.info 'calling ' + verb + ' ' + service_name
Chef::Log.debug body unless body == ''
response = @rest.query_azure(service_name, verb, body)
if response.code.to_i == 200
ret_val = Nokogiri::XML response.body
elsif response.code.to_i >= 201 && response.code.to_i <= 299
ret_val = wait_for_completion()
else
if response.body
ret_val = Nokogiri::XML response.body
Chef::Log.warn ret_val.at_css('Error Code').content + ' : ' + ret_val.at_css('Error Message').content
else
Chef::Log.warn 'http error: ' + response.code
end
end
ret_val
end
def wait_for_completion()
status = 'InProgress'
Chef::Log.info 'Waiting while status returns InProgress'
while status == 'InProgress'
response = @rest.query_for_completion()
ret_val = Nokogiri::XML response.body
status = ret_val.at_css('Status').content
if status == 'InProgress'
print '.'
sleep(0.5)
elsif status == 'Succeeded'
Chef::Log.debug 'not InProgress : ' + ret_val.to_xml
else
Chef::Log.warn status + ret_val.at_css('Error Code').content + ' : ' + ret_val.at_css('Error Message').content
end
end
ret_val
end
end
end

114
lib/azure/deploy.rb Executable file
Просмотреть файл

@ -0,0 +1,114 @@
#
# Author:: Barry Davis (barryd@jetstreamsoftware.com)
# Copyright:: Copyright (c) 2010-2011 Opscode, Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
class Azure
class Deploys
def initialize(connection)
@connection=connection
end
def all
deploys = Array.new
hosts = @connection.hosts.all
hosts.each do |host|
deploy = Deploy.new(@connection)
deploy.retrieve(host.name)
unless deploy.name == nil
deploys << deploy
end
end
deploys
end
def find(hostedservicename)
deployName = nil
self.all.each do |deploy|
next unless deploy.hostedservicename == hostedservicename
deployName = deploy.name
end
deployName
end
def create(params)
unless @connection.hosts.exists(params[:hosted_service_name])
@connection.hosts.create(params)
end
params['deploy_name'] = find(params[:hosted_service_name])
if params['deploy_name'] != nil
role = Role.new(@connection)
roleXML = role.setup(params)
ret_val = role.create(params, roleXML)
else
params['deploy_name'] = params[:hosted_service_name]
deploy = Deploy.new(@connection)
deployXML = deploy.setup(params)
ret_val = deploy.create(params, deployXML)
end
if ret_val.css('Error Code').length > 0
Chef::Log.fatal 'Unable to create role:' + ret_val.at_css('Error Code').content + ' : ' + ret_val.at_css('Error Message').content
exit 1
end
@connection.roles.find(params[:role_name])
end
def delete(rolename)
end
end
class Deploy
include AzureUtility
attr_accessor :connection, :name, :status, :url, :roles, :hostedservicename
def initialize(connection)
@connection = connection
end
def retrieve(hostedservicename)
@hostedservicename = hostedservicename
deployXML = @connection.query_azure("hostedservices/#{hostedservicename}/deploymentslots/Production")
if deployXML.at_css('Deployment Name') != nil
@name = xml_content(deployXML, 'Deployment Name')
@status = xml_content(deployXML,'Deployment Status')
@url = xml_content(deployXML, 'Deployment Url')
@roles = Array.new
rolesXML = deployXML.css('Deployment RoleInstanceList RoleInstance')
rolesXML.each do |roleXML|
role = Role.new(@connection)
role.parse(roleXML, hostedservicename, @name)
@roles << role
end
end
end
def setup(params)
role = Role.new(@connection)
roleXML = role.setup(params)
#roleXML = Nokogiri::XML role.setup(params)
builder = Nokogiri::XML::Builder.new do |xml|
xml.Deployment(
'xmlns'=>'http://schemas.microsoft.com/windowsazure',
'xmlns:i'=>'http://www.w3.org/2001/XMLSchema-instance'
) {
xml.Name params['deploy_name']
xml.DeploymentSlot 'Production'
xml.Label Base64.encode64(params['deploy_name']).strip
xml.RoleList { xml.Role('i:type'=>'PersistentVMRole') }
}
end
builder.doc.at_css('Role') << roleXML.at_css('PersistentVMRole').children.to_s
builder.doc
end
def create(params, deployXML)
servicecall = "hostedservices/#{params[:hosted_service_name]}/deployments"
@connection.query_azure(servicecall, "post", deployXML.to_xml)
end
end
end

62
lib/azure/disk.rb Executable file
Просмотреть файл

@ -0,0 +1,62 @@
#
# Author:: Barry Davis (barryd@jetstreamsoftware.com)
# Copyright:: Copyright (c) 2010-2011 Opscode, Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
class Azure
class Disks
def initialize(connection)
@connection=connection
end
def all
disks = Array.new
response = @connection.query_azure('disks')
founddisks = response.css('Disk')
founddisks.each do |disk|
item = Disk.new(disk)
disks << item
end
disks
end
def find(name)
founddisk = nil
self.all.each do |disk|
next unless disk.name == name
founddisk = disk
end
founddisk
end
def exists(name)
find(name) != nil
end
def clear_unattached
self.all.each do |disk|
next unless disk.attached == false
@connection.query_azure('disks/' + disk.name, 'delete')
end
end
end
end
class Azure
class Disk
attr_accessor :name, :attached
def initialize(disk)
@name = disk.at_css('Name').content
@attached = disk.at_css('AttachedTo') != nil
end
end
end

90
lib/azure/host.rb Executable file
Просмотреть файл

@ -0,0 +1,90 @@
#
# Author:: Barry Davis (barryd@jetstreamsoftware.com)
# Copyright:: Copyright (c) 2010-2011 Opscode, Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
class Azure
class Hosts
def initialize(connection)
@connection=connection
end
def all
hosted_services = Array.new
responseXML = @connection.query_azure('hostedservices')
servicesXML = responseXML.css('HostedServices HostedService')
servicesXML.each do |serviceXML|
host = Host.new(@connection)
hosted_services << host.parse(serviceXML)
end
hosted_services
end
def exists(name)
hostExists = false
self.all.each do |host|
next unless host.name == name
hostExists = true
end
hostExists
end
def create(params)
host = Host.new(@connection)
host.create(params)
end
def delete(name)
if self.exists name
servicecall = "hostedservices/" + name
@connection.query_azure(servicecall, "delete")
end
end
end
end
class Azure
class Host
include AzureUtility
attr_accessor :connection, :name, :url, :label
attr_accessor :dateCreated, :description, :location
attr_accessor :dateModified, :status
def initialize(connection)
@connection = connection
end
def parse(serviceXML)
@name = xml_content(serviceXML, 'ServiceName')
@url = xml_content(serviceXML, 'Url')
@label = xml_content(serviceXML, 'HostedServiceProperties Label')
@dateCreated = xml_content(serviceXML, 'HostedServiceProperties DateCreated')
@description = xml_content(serviceXML, 'HostedServiceProperties Description')
@location = xml_content(serviceXML, 'HostedServiceProperties Location')
@dateModified = xml_content(serviceXML, 'HostedServiceProperties DateLastModified')
@status = xml_content(serviceXML, 'HostedServiceProperties Status')
self
end
def create(params)
builder = Nokogiri::XML::Builder.new do |xml|
xml.CreateHostedService('xmlns'=>'http://schemas.microsoft.com/windowsazure') {
xml.ServiceName params[:hosted_service_name]
xml.Label Base64.encode64(params[:hosted_service_name])
xml.Description params['hosted_service_description'] || 'Explicitly created hosted service'
xml.Location params['hosted_service_location'] || 'Windows Azure Preview'
}
end
@connection.query_azure("hostedservices", "post", builder.to_xml)
end
def details
response = @connection.query_azure('hostedservices/' + @name + '?embed-detail=true')
end
end
end

58
lib/azure/image.rb Executable file
Просмотреть файл

@ -0,0 +1,58 @@
#
# Author:: Barry Davis (barryd@jetstreamsoftware.com)
# Copyright:: Copyright (c) 2010-2011 Opscode, Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
class Azure
class Images
def initialize(connection)
@connection=connection
end
def all
images = Array.new
response = @connection.query_azure('images')
osimages = response.css('OSImage')
osimages.each do |image|
item = Image.new(image)
images << item
end
images
end
def exists(name)
imageExists = false
self.all.each do |host|
next unless host.name == name
imageExists = true
end
imageExists
end
end
end
class Azure
class Image
attr_accessor :category, :label
attr_accessor :name, :os, :eula, :description
def initialize(image)
@category = image.at_css('Category').content
@label = image.at_css('Label').content
@name = image.at_css('Name').content
@os = image.at_css('OS').content
@eula = image.at_css('Eula').content
@description = image.at_css('Description').content
end
end
end

97
lib/azure/rest.rb Executable file
Просмотреть файл

@ -0,0 +1,97 @@
#
# Author:: Barry Davis (barryd@jetstreamsoftware.com)
# Copyright:: Copyright (c) 2010-2011 Opscode, Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
require "net/https"
require "uri"
require "nokogiri"
module AzureAPI
class Rest
def initialize(params)
@subscription_id = params[:azure_subscription_id]
@pem_file = File.read find_pem(params[:azure_pem_file])
@host_name = params[:azure_host_name]
end
def find_pem(name)
config_dir = Chef::Knife.chef_config_dir
if File.exist? name
pem_file = name
elsif config_dir && File.exist?(File.join(config_dir, name))
pem_file = File.join(config_dir, name)
elsif File.exist?(File.join(ENV['HOME'], '.chef', name))
pem_file = File.join(ENV['HOME'], '.chef', name)
else
raise 'Unable to find certificate pem file - ' + name
end
pem_file
end
def query_azure(service_name, verb = 'get', body = '')
request_url = "https://#{@host_name}/#{@subscription_id}/services/#{service_name}"
print '.'
uri = URI.parse(request_url)
http = http_setup(uri)
request = request_setup(uri, verb, body)
response = http.request(request)
@last_request_id = response['x-ms-request-id']
response
end
def query_for_completion()
request_url = "https://#{@host_name}/#{@subscription_id}/operations/#{@last_request_id}"
uri = URI.parse(request_url)
http = http_setup(uri)
request = request_setup(uri, 'get', '')
response = http.request(request)
end
def http_setup(uri)
http = Net::HTTP.new(uri.host, uri.port)
store = OpenSSL::X509::Store.new
store.add_cert(OpenSSL::X509::Certificate.new(File.read(find_pem("cacert.pem"))))
http.cert_store = store
http.verify_mode = OpenSSL::SSL::VERIFY_PEER
http.use_ssl = true
http.cert = OpenSSL::X509::Certificate.new(@pem_file)
http.key = OpenSSL::PKey::RSA.new(@pem_file)
http
end
def request_setup(uri, verb, body)
if verb == 'get'
request = Net::HTTP::Get.new(uri.request_uri)
elsif verb == 'post'
request = Net::HTTP::Post.new(uri.request_uri)
elsif verb == 'delete'
request = Net::HTTP::Delete.new(uri.request_uri)
end
request["x-ms-version"] = "2012-03-01"
request["content-type"] = "application/xml"
request["accept"] = "application/xml"
request["accept-charset"] = "utf-8"
request.body = body
request
end
def showResponse(response)
puts "=== response body ==="
puts response.body
puts "=== response.code ==="
puts response.code
puts "=== response.inspect ==="
puts response.inspect
puts "=== all of the headers ==="
puts response.each_header { |h, j| puts h.inspect + ' : ' + j.inspect}
end
end
end

182
lib/azure/role.rb Executable file
Просмотреть файл

@ -0,0 +1,182 @@
#
# Author:: Barry Davis (barryd@jetstreamsoftware.com)
# Copyright:: Copyright (c) 2010-2011 Opscode, Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
class Azure
class Roles
attr_accessor :connection, :roles
def initialize(connection)
@connection = connection
@roles = nil
end
def all
@roles = Array.new
@connection.deploys.all.each do |deploy|
deploy.roles.each do |role|
@roles << role
end
end
@roles
end
def find(name)
if @roles == nil
all
end
@roles.each do |role|
if(role.name == name)
return role
end
end
nil
end
def alone_on_host(name)
found_role = find(name)
@roles.each do |role|
if (role.name != found_role.name &&
role.deployname == found_role.deployname &&
role.hostedservicename == found_role.hostedservicename)
return false;
end
end
true
end
def exists(name)
find(name) != nil
end
def delete(name)
role = find(name)
if role != nil
if alone_on_host(name)
servicecall = "hostedservices/#{role.hostedservicename}/deployments" +
"/#{role.deployname}"
else
servicecall = "hostedservices/#{role.hostedservicename}/deployments" +
"/#{role.deployname}/roles/#{role.name}"
end
@connection.query_azure(servicecall, "delete")
end
#@connection.disks.clear_unattached
end
end
class Role
include AzureUtility
attr_accessor :connection, :name, :status, :size, :ipaddress
attr_accessor :sshport, :sshipaddress, :hostedservicename, :deployname
attr_accessor :hostname, :tcpports, :udpports
def initialize(connection)
@connection = connection
end
def parse(roleXML, hostedservicename, deployname)
@name = xml_content(roleXML, 'RoleName')
@status = xml_content(roleXML, 'InstanceStatus')
@size = xml_content(roleXML, 'InstanceSize')
@ipaddress = xml_content(roleXML, 'IpAddress')
@hostname = xml_content(roleXML, 'HostName')
@hostedservicename = hostedservicename
@deployname = deployname
@tcpports = Array.new
@udpports = Array.new
endpoints = roleXML.css('InstanceEndpoint')
endpoints.each do |endpoint|
if xml_content(endpoint, 'Name').downcase == 'ssh'
@sshport = xml_content(endpoint, 'PublicPort')
@sshipaddress = xml_content(endpoint, 'Vip')
else
hash = Hash.new
hash['Name'] = xml_content(endpoint, 'Name')
hash['Vip'] = xml_content(endpoint, 'Vip')
hash['PublicPort'] = xml_content(endpoint, 'PublicPort')
hash['LocalPort'] = xml_content(endpoint, 'LocalPort')
if xml_content(endpoint, 'Protocol') == 'tcp'
@tcpports << hash
else # == 'udp'
@udpports << hash
end
end
end
end
def setup(params)
builder = Nokogiri::XML::Builder.new do |xml|
xml.PersistentVMRole(
'xmlns'=>'http://schemas.microsoft.com/windowsazure',
'xmlns:i'=>'http://www.w3.org/2001/XMLSchema-instance'
) {
xml.RoleName {xml.text params[:role_name]}
xml.OsVersion('i:nil' => 'true')
xml.RoleType 'PersistentVMRole'
xml.ConfigurationSets {
xml.ConfigurationSet('i:type' => 'LinuxProvisioningConfigurationSet') {
xml.ConfigurationSetType 'LinuxProvisioningConfiguration'
xml.HostName params[:host_name]
xml.UserName params[:ssh_user]
xml.UserPassword params[:ssh_password]
xml.DisableSshPasswordAuthentication 'false'
}
xml.ConfigurationSet('i:type' => 'NetworkConfigurationSet') {
xml.ConfigurationSetType 'NetworkConfiguration'
xml.InputEndpoints {
xml.InputEndpoint {
xml.LocalPort '22'
xml.Name 'SSH'
xml.Protocol 'TCP'
}
if params[:tcp_endpoints]
params[:tcp_endpoints].split(',').each do |endpoint|
ports = endpoint.split(':')
xml.InputEndpoint {
xml.LocalPort ports[0]
xml.Name 'tcpport_' + ports[0] + '_' + params[:host_name]
if ports.length > 1
xml.Port ports[1]
end
xml.Protocol 'TCP'
}
end
end
if params[:udp_endpoints]
params[:udp_endpoints].split(',').each do |endpoint|
ports = endpoint.split(':')
xml.InputEndpoint {
xml.LocalPort ports[0]
xml.Name 'udpport_' + ports[0] + '_' + params[:host_name]
if ports.length > 1
xml.Port ports[1]
end
xml.Protocol 'UDP'
}
end
end
}
}
}
xml.Label Base64.encode64(params[:role_name]).strip
xml.OSVirtualHardDisk {
xml.MediaLink 'http://' + params[:media_location_prefix] + 'imagestore.blob.core.azure-preview.com/os-disks/' + (params[:os_disk_name] || Time.now.strftime('disk_%Y_%m_%d_%H_%M'))
xml.SourceImageName params[:source_image]
}
xml.RoleSize params[:role_size]
}
end
builder.doc
end
def create(params, roleXML)
servicecall = "hostedservices/#{params[:hosted_service_name]}/deployments" +
"/#{params['deploy_name']}/roles"
@connection.query_azure(servicecall, "post", roleXML.to_xml)
end
end
end

29
lib/azure/utility.rb Executable file
Просмотреть файл

@ -0,0 +1,29 @@
#
# Author:: Barry Davis (barryd@jetstreamsoftware.com)
# Copyright:: Copyright (c) 2010-2011 Opscode, Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
module AzureUtility
def xml_content(xml, key, default='')
content = default
node = xml.at_css(key)
if node
content = node.content
end
content
end
end

Двоичные данные
lib/chef/.DS_Store поставляемый Normal file

Двоичный файл не отображается.

102
lib/chef/knife/azure_base.rb Executable file
Просмотреть файл

@ -0,0 +1,102 @@
# Author:: Barry Davis (barryd@jetstreamsoftware.com)
# Author:: Seth Chisamore (<schisamo@opscode.com>)
# Copyright:: Copyright (c) 2011 Opscode, Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
require 'chef/knife'
require File.expand_path('../../../azure/connection', __FILE__)
class Chef
class Knife
module AzureBase
# :nodoc:
# Would prefer to do this in a rational way, but can't be done b/c of
# Mixlib::CLI's design :(
def self.included(includer)
includer.class_eval do
deps do
require 'readline'
require 'chef/json_compat'
end
option :azure_subscription_id,
:short => "-S ID",
:long => "--azure-subscription-id ID",
:description => "Your Azure subscription ID",
:proc => Proc.new { |key| Chef::Config[:knife][:azure_subscription_id] = key }
option :azure_pem_file,
:short => "-p FILENAME",
:long => "--azure-pem-filename FILENAME",
:description => "Your Azure PEM file name",
:proc => Proc.new { |key| Chef::Config[:knife][:azure_pem_file] = key }
option :azure_host_name,
:short => "-H HOSTNAME",
:long => "--azure_host_name HOSTNAME",
:description => "Your Azure host name",
:proc => Proc.new { |key| Chef::Config[:knife][:azure_host_name] = key }
end
end
def connection
@connection ||= begin
connection = Azure::Connection.new(
:azure_subscription_id =>
config[:azure_subscription_id] || Chef::Config[:knife][:azure_subscription_id],
:azure_pem_file =>
config[:azure_pem_file] || Chef::Config[:knife][:azure_pem_file],
:azure_host_name =>
config[:azure_host_name] || Chef::Config[:knife][:azure_host_name]
)
end
end
def locate_config_value(key)
key = key.to_sym
config[key] || Chef::Config[:knife][key]
end
def msg_pair(label, value, color=:cyan)
if value && !value.to_s.empty?
puts "#{ui.color(label, color)}: #{value}"
end
end
def validate!(keys=[:azure_subscription_id, :azure_pem_file, :azure_host_name])
errors = []
keys.each do |k|
pretty_key = k.to_s.gsub(/_/, ' ').gsub(/\w+/){ |w| (w =~ /(ssh)|(aws)/i) ? w.upcase : w.capitalize }
if Chef::Config[:knife][k].nil?
errors << "You did not provide a valid '#{pretty_key}' value."
end
end
if errors.each{|e| ui.error(e)}.any?
exit 1
end
end
end
end
end

Просмотреть файл

@ -0,0 +1,58 @@
#
# Author:: Barry Davis (barryd@jetstreamsoftware.com)
# Author:: Seth Chisamore (<schisamo@opscode.com>)
# Author:: Adam Jacob (<adam@opscode.com>)
# Copyright:: Copyright (c) 2010-2011 Opscode, Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
require File.expand_path('../azure_base', __FILE__)
class Chef
class Knife
class AzureImageList < Knife
include Knife::AzureBase
banner "knife azure image list (options)"
def run
$stdout.sync = true
validate!
image_list = [
ui.color('Name', :bold),
#ui.color('Category', :bold),
#ui.color('Label', :bold),
#ui.color('OS', :bold),
#ui.color('Eula', :bold),
]
items = connection.images.all
items.each do |image|
if image.os == 'Linux'
image_list << image.name.to_s
#image_list << image.category.to_s
#image_list << image.label.to_s
#image_list << image.os.to_s
#image_list << image.eula.to_s
end
end
puts ''
puts ui.list(image_list, :columns_across, 1)
end
end
end
end

Просмотреть файл

@ -0,0 +1,282 @@
#
# Author:: Barry Davis (barryd@jetstreamsoftware.com)
# Author:: Adam Jacob (<adam@opscode.com>)
# Author:: Seth Chisamore (<schisamo@opscode.com>)
# Copyright:: Copyright (c) 2010-2011 Opscode, Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
require File.expand_path('../azure_base', __FILE__)
class Chef
class Knife
class AzureServerCreate < Knife
include Knife::AzureBase
deps do
require 'readline'
require 'chef/json_compat'
require 'chef/knife/bootstrap'
Chef::Knife::Bootstrap.load_deps
end
banner "knife azure server create (options)"
attr_accessor :initial_sleep_delay
option :chef_node_name,
:short => "-N NAME",
:long => "--node-name NAME",
:description => "The Chef node name for your new node"
option :ssh_user,
:short => "-x USERNAME",
:long => "--ssh-user USERNAME",
:description => "The ssh username"
option :ssh_password,
:short => "-P PASSWORD",
:long => "--ssh-password PASSWORD",
:description => "The ssh password"
option :identity_file,
:short => "-i IDENTITY_FILE",
:long => "--identity-file IDENTITY_FILE",
:description => "The SSH identity file used for authentication"
option :prerelease,
:long => "--prerelease",
:description => "Install the pre-release chef gems"
option :bootstrap_version,
:long => "--bootstrap-version VERSION",
:description => "The version of Chef to install",
:proc => Proc.new { |v| Chef::Config[:knife][:bootstrap_version] = v }
option :distro,
:short => "-d DISTRO",
:long => "--distro DISTRO",
:description => "Bootstrap a distro using a template",
:proc => Proc.new { |d| Chef::Config[:knife][:distro] = d }
option :template_file,
:long => "--template-file TEMPLATE",
:description => "Full path to location of template to use",
:proc => Proc.new { |t| Chef::Config[:knife][:template_file] = t },
:default => false
option :run_list,
:short => "-r RUN_LIST",
:long => "--run-list RUN_LIST",
:description => "Comma separated list of roles/recipes to apply",
:proc => lambda { |o| o.split(/[\s,]+/) },
:default => []
option :no_host_key_verify,
:long => "--no-host-key-verify",
:description => "Disable host key verification",
:boolean => true,
:default => false
option :hosted_service_name,
:short => "-s NAME",
:long => "--hosted-service-name NAME",
:description => "specifies the name for the hosted service"
option :role_name,
:short => "-R name",
:long => "--role-name NAME",
:description => "specifies the name for the virtual machine"
option :host_name,
:short => "-H NAME",
:long => "--host-name NAME",
:description => "specifies the host name for the virtual machine"
option :media_location_prefix,
:short => "-m PREFIX",
:long => "--media-location-prefix PREFIX",
:description => "user account name (used for constructing os disk media link)"
option :os_disk_name,
:short => "-o DISKNAME",
:long => "--os-disk-name DISKNAME",
:description => "unique name for specifying os disk (optional)"
option :source_image,
:short => "-I IMAGE",
:long => "--source-image IMAGE",
:description => "disk image name to use to create virtual machine"
option :role_size,
:short => "-z SIZE",
:long => "--role-size SIZE",
:description => "size of virtual machine (ExtraSmall, Small, Medium, Large, ExtraLarge)"
option :tcp_endpoints,
:short => "-t PORT_LIST",
:long => "--tcp-endpoints PORT_LIST",
:description => "Comma separated list of TCP local and public ports to open i.e. '80:80,433:5000'"
option :udp_endpoints,
:short => "-u PORT_LIST",
:long => "--udp-endpoints PORT_LIST",
:description => "Comma separated list of UDP local and public ports to open i.e. '80:80,433:5000'"
def tcp_test_ssh(fqdn, sshport)
tcp_socket = TCPSocket.new(fqdn, sshport)
readable = IO.select([tcp_socket], nil, nil, 5)
if readable
Chef::Log.debug("sshd accepting connections on #{fqdn}, banner is #{tcp_socket.gets}")
yield
true
else
false
end
rescue SocketError
sleep 2
false
rescue Errno::ETIMEDOUT
false
rescue Errno::EPERM
false
rescue Errno::ECONNREFUSED
sleep 2
false
# This happens on EC2 quite often
rescue Errno::EHOSTUNREACH
sleep 2
false
ensure
tcp_socket && tcp_socket.close
end
def parameter_test
details = Array.new
details << ui.color('name', :bold, :blue)
details << ui.color('Chef::Config', :bold, :blue)
details << ui.color('config', :bold, :blue)
details << ui.color('winner is', :bold, :blue)
[
:azure_subscription_id,
:azure_pem_file,
:azure_host_name,
:hosted_service_name,
:role_name,
:host_name,
:ssh_user,
:ssh_password,
:media_location_prefix,
:source_image,
:role_size
].each do |key|
key = key.to_sym
details << key.to_s
details << Chef::Config[:knife][key].to_s
details << config[key].to_s
details << locate_config_value(key)
end
puts ui.list(details, :columns_across, 4)
end
def run
$stdout.sync = true
Chef::Log.info("validating...")
validate!
Chef::Log.info("creating...")
server = connection.deploys.create(create_server_def)
puts("\n")
unless server && server.sshipaddress && server.sshport
Chef::Log.fatal("server not created")
exit 1
end
fqdn = server.sshipaddress
port = server.sshport
print "\n#{ui.color("Waiting for sshd on #{fqdn}:#{port}", :magenta)}"
print(".") until tcp_test_ssh(fqdn,port) {
sleep @initial_sleep_delay ||= 10
puts("done")
}
sleep 15
bootstrap_for_node(server,fqdn,port).run
puts "\n"
end
def bootstrap_for_node(server,fqdn,port)
bootstrap = Chef::Knife::Bootstrap.new
bootstrap.name_args = [fqdn]
bootstrap.config[:run_list] = config[:run_list]
bootstrap.config[:ssh_user] = locate_config_value(:ssh_user)
bootstrap.config[:ssh_password] = locate_config_value(:ssh_password)
bootstrap.config[:ssh_port] = port
bootstrap.config[:identity_file] = locate_config_value(:identity_file)
bootstrap.config[:chef_node_name] = locate_config_value(:chef_node_name) || server.name
bootstrap.config[:prerelease] = locate_config_value(:prerelease)
bootstrap.config[:bootstrap_version] = locate_config_value(:bootstrap_version)
bootstrap.config[:distro] = locate_config_value(:distro)
bootstrap.config[:use_sudo] = true unless locate_config_value(:ssh_user) == 'root'
bootstrap.config[:template_file] = config[:template_file]
bootstrap.config[:environment] = locate_config_value(:environment)
# may be needed for vpc_mode
bootstrap.config[:no_host_key_verify] = config[:no_host_key_verify]
bootstrap
end
def validate!
super([
:azure_subscription_id,
:azure_pem_file,
:azure_host_name,
:hosted_service_name,
:role_name,
:host_name,
:ssh_user,
:ssh_password,
:media_location_prefix,
:source_image,
:role_size
])
end
def create_server_def
server_def = {
:hosted_service_name => locate_config_value(:hosted_service_name),
:role_name => locate_config_value(:role_name),
:host_name => locate_config_value(:host_name),
:ssh_user => locate_config_value(:ssh_user),
:ssh_password => locate_config_value(:ssh_password),
:media_location_prefix => locate_config_value(:media_location_prefix),
:os_disk_name => locate_config_value(:os_disk_name),
:source_image => locate_config_value(:source_image),
:role_size => locate_config_value(:role_size),
:tcp_endpoints => locate_config_value(:tcp_endpoints),
:udp_endpoints => locate_config_value(:udp_endpoints)
}
server_def
end
end
end
end

Просмотреть файл

@ -0,0 +1,103 @@
#
# Author:: Barry Davis (barryd@jetstreamsoftware.com)
# Author:: Adam Jacob (<adam@opscode.com>)
# Author:: Seth Chisamore (<schisamo@opscode.com>)
# Copyright:: Copyright (c) 2009-2011 Opscode, Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
require File.expand_path('../azure_base', __FILE__)
# These two are needed for the '--purge' deletion case
require 'chef/node'
require 'chef/api_client'
class Chef
class Knife
class AzureServerDelete < Knife
include Knife::AzureBase
banner "knife azure server delete SERVER [SERVER] (options)"
option :purge,
:short => "-P",
:long => "--purge",
:boolean => true,
:default => false,
:description => "Destroy corresponding node and client on the Chef Server, in addition to destroying the EC2 node itself. Assumes node and client have the same name as the server (if not, add the '--node-name' option)."
option :chef_node_name,
:short => "-N NAME",
:long => "--node-name NAME",
:description => "The name of the node and client to delete, if it differs from the server name. Only has meaning when used with the '--purge' option."
# Extracted from Chef::Knife.delete_object, because it has a
# confirmation step built in... By specifying the '--purge'
# flag (and also explicitly confirming the server destruction!)
# the user is already making their intent known. It is not
# necessary to make them confirm two more times.
def destroy_item(klass, name, type_name)
begin
object = klass.load(name)
object.destroy
ui.warn("Deleted #{type_name} #{name}")
rescue Net::HTTPServerException
ui.warn("Could not find a #{type_name} named #{name} to delete!")
end
end
def run
validate!
@name_args.each do |name|
begin
server = connection.roles.find(name)
puts "\n"
msg_pair('Service', server.hostedservicename)
msg_pair('Deployment', server.deployname)
msg_pair('Role', server.name)
msg_pair('Size', server.size)
msg_pair('SSH Ip Address', server.sshipaddress)
msg_pair('SSH Port', server.sshport)
puts "\n"
confirm("Do you really want to delete this server")
connection.roles.delete(name)
puts "\n"
ui.warn("Deleted server #{server.name}")
if config[:purge]
thing_to_delete = config[:chef_node_name] || name
destroy_item(Chef::Node, thing_to_delete, "node")
destroy_item(Chef::ApiClient, thing_to_delete, "client")
else
ui.warn("Corresponding node and client for the #{name} server were not deleted and remain registered with the Chef Server")
end
rescue NoMethodError
ui.error("Could not locate server '#{name}'. Please verify it was provisioned.")
end
end
end
end
end
end

Просмотреть файл

@ -0,0 +1,85 @@
#
# Author:: Barry Davis (barryd@jetstreamsoftware.com)
# Author:: Seth Chisamore (<schisamo@opscode.com>)
# Author:: Adam Jacob (<adam@opscode.com>)
# Copyright:: Copyright (c) 2010-2011 Opscode, Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
require File.expand_path('../azure_base', __FILE__)
class Chef
class Knife
class AzureServerDescribe < Knife
include Knife::AzureBase
banner "knife azure server describe ROLE [ROLE]"
def run
$stdout.sync = true
validate!
@name_args.each do |name|
role = connection.roles.find name
puts ''
if (role)
details = Array.new
details << ui.color('Role name', :bold, :blue)
details << role.name
details << ui.color('Status', :bold, :blue)
details << role.status
details << ui.color('Size', :bold, :blue)
details << role.size
details << ui.color('Hosted service name', :bold, :blue)
details << role.hostedservicename
details << ui.color('Deployment name', :bold, :blue)
details << role.deployname
details << ui.color('Host name', :bold, :blue)
details << role.hostname
details << ui.color('SSH', :bold, :blue)
details << role.sshipaddress + ':' + role.sshport
puts ui.list(details, :columns_across, 2)
if role.tcpports.length > 0 || role.udpports.length > 0
details.clear
details << ui.color('Ports open', :bold, :blue)
details << ui.color('Local port', :bold, :blue)
details << ui.color('IP', :bold, :blue)
details << ui.color('Public port', :bold, :blue)
if role.tcpports.length > 0
role.tcpports.each do |port|
details << 'tcp'
details << port['LocalPort']
details << port['Vip']
details << port['PublicPort']
end
end
if role.udpports.length > 0
role.udpports.each do |port|
details << 'udp'
details << port['LocalPort']
details << port['Vip']
details << port['PublicPort']
end
end
puts ui.list(details, :columns_across, 4)
end
end
end
end
end
end
end

Просмотреть файл

@ -0,0 +1,70 @@
#
# Author:: Barry Davis (barryd@jetstreamsoftware.com)
# Author:: Seth Chisamore (<schisamo@opscode.com>)
# Author:: Adam Jacob (<adam@opscode.com>)
# Copyright:: Copyright (c) 2010-2011 Opscode, Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
require File.expand_path('../azure_base', __FILE__)
class Chef
class Knife
class AzureServerList < Knife
include Knife::AzureBase
banner "knife azure server list (options)"
def run
$stdout.sync = true
validate!
server_list = [
ui.color('Status', :bold),
ui.color('Service', :bold),
ui.color('Deployment', :bold),
ui.color('Role', :bold),
ui.color('Host', :bold),
ui.color('SSH IP', :bold),
ui.color('SSH Port', :bold)
]
items = connection.roles.all
items.each do |server|
server_list << begin
state = server.status.to_s.downcase
case state
when 'shutting-down','terminated','stopping','stopped'
ui.color(state, :red)
when 'pending'
ui.color(state, :yellow)
else
ui.color('ready', :green)
end
end
server_list << server.hostedservicename.to_s
server_list << server.deployname.to_s
server_list << server.name.to_s
server_list << server.hostname.to_s
server_list << server.sshipaddress.to_s
server_list << server.sshport.to_s
end
puts ''
puts ui.list(server_list, :columns_across, 7)
end
end
end
end

7
lib/knife-azure/version.rb Executable file
Просмотреть файл

@ -0,0 +1,7 @@
module Knife
module Azure
VERSION = "0.5.11"
MAJOR, MINOR, TINY = VERSION.split('.')
end
end

199
readme.rdoc Executable file
Просмотреть файл

@ -0,0 +1,199 @@
=Knife Azure
Description: This plugin supports listing, creating, and deleting Azure instances bootstrapped with chef client.
==Installation:
Be sure you are running the latest version Chef. Versions earlier than 0.10.0 dont support plugins:
gem install chef
This plugin is distributed as a Ruby Gem. To install it, run:
gem install knife-azure
Depending on your systems configuration, you may need to run this command with root privileges.
==Configuration:
Most configuration options can be specified either in your knife.rb file or as command line parameters.
Options common and necessary for all subcommands:
option :azure_subscription_id,
:short => "-S ID",
:long => "--azure-subscription-id ID",
:description => "Your Azure subscription ID",
option :azure_pem_file,
:short => "-p FILENAME",
:long => "--azure-pem-filename FILENAME",
:description => "Your Azure PEM file name",
option :azure_host_name,
:short => "-H HOSTNAME",
:long => "--azure_host_name HOSTNAME",
:description => "Your Azure host name",
Options used with the Create subcommand:
option :chef_node_name,
:short => "-N NAME",
:long => "--node-name NAME",
:description => "The Chef node name for your new node"
option :ssh_user,
:short => "-x USERNAME",
:long => "--ssh-user USERNAME",
:description => "The ssh username",
:default => "root"
option :ssh_password,
:short => "-P PASSWORD",
:long => "--ssh-password PASSWORD",
:description => "The ssh password"
option :identity_file,
:short => "-i IDENTITY_FILE",
:long => "--identity-file IDENTITY_FILE",
:description => "The SSH identity file used for authentication"
option :prerelease,
:long => "--prerelease",
:description => "Install the pre-release chef gems"
option :bootstrap_version,
:long => "--bootstrap-version VERSION",
:description => "The version of Chef to install",
option :distro,
:short => "-d DISTRO",
:long => "--distro DISTRO",
:description => "Bootstrap a distro using a template",
:default => "ubuntu10.04-gems"
option :template_file,
:long => "--template-file TEMPLATE",
:description => "Full path to location of template to use",
:default => false
option :run_list,
:short => "-r RUN_LIST",
:long => "--run-list RUN_LIST",
:description => "Comma separated list of roles/recipes to apply",
:default => []
option :no_host_key_verify,
:long => "--no-host-key-verify",
:description => "Disable host key verification",
:boolean => true,
:default => false
option :hosted_service_name,
:short => "-s NAME",
:long => "--hosted-service-name NAME",
:description => "specifies the name for the hosted service"
option :role_name,
:short => "-R name",
:long => "-- role-name NAME",
:description => "specifies the name for the virtual machine"
option :host_name,
:short => "-H NAME",
:long => "--host-name NAME",
:description => "specifies the host name for the virtual machine"
option :media_location_prefix,
:short => "-m PREFIX",
:long => "--media-location-prefix PREFIX",
:description => "user account name (used for constructing os disk media link)"
option :os_disk_name,
:short => "-o DISKNAME",
:long => "--os-disk-name DISKNAME",
:description => "unique name for specifying os disk (optional)"
option :source_image,
:short => "-I IMAGE",
:long => "--source-image IMAGE",
:description => "disk image name to use to create virtual machine"
option :role_size,
:short => "-z SIZE",
:long => "--role-size SIZE",
:description => "size of virtual machine (ExtraSmall, Small, Medium, Large, ExtraLarge)"
option :tcp_endpoints,
:short => "-t PORT_LIST",
:long => "--tcp-endpoints PORT_LIST",
:description => "Comma separated list of TCP local and public ports to open i.e. '80:80,433:5000'"
option :udp_endpoints,
:short => "-u PORT_LIST",
:long => "--udp-endpoints PORT_LIST",
:description => "Comma separated list of UDP local and public ports to open i.e. '80:80,433:5000'"
====Here are some lines with example values in a knife.rb file:
knife[:azure_subscription_id] = "YOUR-GUID"
knife[:azure_pem_file] = "YOUR-CERT.pem"
knife[:azure_host_name] = "azure-api-endpoint"
knife[:hosted_service_name]='service001'
knife[:role_name]='role105'
knife[:host_name]='host105'
knife[:ssh_user]='yoursshuser'
knife[:ssh_password]='yoursshpw'
knife[:media_location_prefix]='auxpreview104'
knife[:os_disk_name]='disk107'
knife[:distro]='centos5-gems'
knife[:tcp_endpoints]='66'
knife[:udp_endpoints]='77,88,99'
# To use the CentOS image, the following lines are necessary
# note that the role_size must be Medium or larger
knife[:source_image]='OpenLogic__OpenLogic-CentOS-62-20120509-en-us-30GB.vhd'
knife[:role_size]='Medium'
# Alternatively, at the present time you could use a SUSE image
# note that you can use Small or ExtraSmall for the role_size
knife[:source_image]='SUSE__OpenSUSE64121-03192012-en-us-15GB.vhd'
knife[:role_size]='Small'
==Subcommands
This plugin provides the following Knife subcommands. Specific command options can be found by invoking the subcommand with a --help flag
===knife azure server create
Provisions a new server in Azure and then perform a Chef bootstrap (using the SSH protocol). The goal of the bootstrap is to get Chef installed on the target system so it can run Chef Client with a Chef Server. The main assumption is a baseline OS installation exists (provided by the provisioning). It is primarily intended for Chef Client systems that talk to a Chef server. By default the server is bootstrapped using the ubuntu10.04-gems template. This can be overridden using the -d or --template-file command options.
===knife azure server delete [role_name_to_delete]
Deletes an existing server(role) in the currently configured AWS account. PLEASE NOTE - By default, this does not delete the associated node and client objects from the Chef server. To do so, add the --purge flag.
===knife azure server list
Outputs a list of all servers in the currently configured AWS account. PLEASE NOTE - this shows all instances associated with the account, some of which may not be currently managed by the Chef server.
===knife azure server describe [role_name_to_describe]
Outputs detail about a specific role, including all the ports that it has open
===knife azure image list
Outputs a list of all linux images that are available to use for provisioning. You should choose one of these to use for the :source_image parameter to the server create command.
== Understanding Azure
Azure implements the following hierarchy - subscription=>hosted service=>deployment=>role (and the guest operating system has a hostname as well, which uses the role as its container)
These are generally a one to many relationship from top to bottom, however there are two anamolies relating to the deployment
1) a hosted service can have more than one deployment, but that seems to be an artifact of the PAAS origins of Azure. PAAS allows there to be one staging and one production deployment per hosted service. It is my understanding (and how the code works) that there should be only one deployment per hosted service. Some initial internal code I examined used the technique of looking at the "production" deployment slot to iterate for existing roles. If a create request occurs and a deployment does not exist, it is created and given the same name as the hosted service and the deployment slot is marked as "production".
2) Azure enforces that a deployment must include the initial role when it is created. It also will not allow you to delete a role if it is the last remaining role in a deployment; in that case you are required to delete the deployment.

43
spec/functional/deploys_test.rb Executable file
Просмотреть файл

@ -0,0 +1,43 @@
require File.expand_path(File.dirname(__FILE__) + '/../spec_helper')
describe "deploys" do
before(:all) do
params = { :azure_subscription_id => "155a9851-88a8-49b4-98e4-58055f08f412",
:azure_pem_file => "AzureLinuxCert.pem",
:azure_host_name => "management-preview.core.windows-int.net",
:service_name => "hostedservices"}
@connection = Azure::Connection.new(params)
@deploys = @connection.deploys.all
end
specify {@deploys.length.should be > 0}
it 'each deployment should have values' do
@deploys.each do |deploy|
deploy.name.should_not be_nil
deploy.status.should_not be_nil
deploy.url.should_not be_nil
deploy.roles.length.should be > 0
end
end
it 'each role should have values' do
@deploys.each do |deploy|
Chef::Log.info '============================='
Chef::Log.info 'hosted service: ' + deploy.hostedservicename + ' deployment: ' + deploy.name
deploy.roles.each do |role|
role.name.should_not be_nil
role.status.should_not be_nil
role.size.should_not be_nil
role.ipaddress.should_not be_nil
role.sshport.should_not be_nil
role.sshipaddress.should_not be_nil
Chef::Log.info '============================='
Chef::Log.info 'role: ' + role.name
Chef::Log.info 'status: ' + role.status
Chef::Log.info 'size: ' + role.size
Chef::Log.info 'ip address: ' + role.ipaddress
Chef::Log.info 'ssh port: ' + role.sshport
Chef::Log.info 'ssh ip address: ' + role.sshipaddress
end
end
end
end

26
spec/functional/host_test.rb Executable file
Просмотреть файл

@ -0,0 +1,26 @@
require File.expand_path(File.dirname(__FILE__) + '/../spec_helper')
describe "Connection" do
before(:all) do
params = { :azure_subscription_id => "155a9851-88a8-49b4-98e4-58055f08f412",
:azure_pem_file => "AzureLinuxCert.pem",
:azure_host_name => "management-preview.core.windows-int.net",
:service_name => "hostedservices"}
@connection = Azure::Connection.new(params)
@items = @connection.hosts.all
end
specify {@items.length.should be > 0}
specify {@connection.hosts.exists("thisServiceShouldNotBeThere").should == false}
specify{@connection.hosts.exists("service002").should == true}
it "looking for a specific host" do
foundNamedHost = false
@items.each do |host|
next unless host.name == "service002"
foundNamedHost = true
end
foundNamedHost.should == true
end
end

Просмотреть файл

@ -0,0 +1,48 @@
require File.expand_path(File.dirname(__FILE__) + '/../spec_helper')
describe "Connection" do
before(:all) do
params = { :azure_subscription_id => "155a9851-88a8-49b4-98e4-58055f08f412",
:azure_pem_file => "AzureLinuxCert.pem",
:azure_host_name => "management-preview.core.windows-int.net",
:service_name => "hostedservices"}
@connection = Azure::Connection.new(params)
@items = @connection.images.all
end
it "should be contain images" do
@items.length.should be > 1
end
it "each image should have all fields valid" do
@items.each do |image|
image.category.should_not be_nil
image.label.should_not be_nil
image.name.should_not be_nil
image.os.should_not be_nil
image.eula.should_not be_nil
image.description.should_not be_nil
end
end
# it "should get services" do
# @demo.DemoGet
# end
# it "bad subscription should fail with ResourceNotFound" do
# @demo.subscription = "ae2ff9b3-12b2-45cf-b58e-468bc7e29110xxxxx"
#
# expect{@demo.DemoGet}.to raise_error(RuntimeError, /ResourceNotFound/)
# end
# it "bad pem_path should fail with CertificateError" do
# @demo.pem_file = ""
#
# expect{@demo.DemoGet}.to raise_error(OpenSSL::X509::CertificateError)
# end
# it "bad service_name should fail with " do
# @demo.service_name = ""
#
# expect{@demo.DemoGet}.to raise_error(RuntimeError, /ResourceNotFound/)
# end
end

20
spec/functional/role_test.rb Executable file
Просмотреть файл

@ -0,0 +1,20 @@
require File.expand_path(File.dirname(__FILE__) + '/../spec_helper')
describe "roles" do
before(:all) do
params = { :azure_subscription_id => "155a9851-88a8-49b4-98e4-58055f08f412",
:azure_pem_file => "AzureLinuxCert.pem",
:azure_host_name => "management-preview.core.windows-int.net",
:service_name => "hostedservices"}
@connection = Azure::Connection.new(params)
@roles = @connection.roles.all
end
specify {@connection.roles.exists('notexist').should == false}
specify {@connection.roles.exists('role126').should == true}
it 'run through roles' do
@connection.roles.roles.each do |role|
role.name.should_not be_nil
end
end
end

Просмотреть файл

@ -0,0 +1,62 @@
require File.expand_path(File.dirname(__FILE__) + '/../spec_helper')
describe "role lifecycle" do
Chef::Log.init()
Chef::Log.level=:info
before(:all) do
connection_params = { :azure_subscription_id => "155a9851-88a8-49b4-98e4-58055f08f412",
:azure_pem_file => "AzureLinuxCert.pem",
:azure_host_name => "management-preview.core.windows-int.net",
:service_name => "hostedservices"}
@connection = Azure::Connection.new(connection_params)
arbitrary = rand(1000) + 1
@params = {
:hosted_service_name=>'service002',
:role_name=>'role' + arbitrary.to_s,
:host_name=>'host' + arbitrary.to_s,
:ssh_user=>'jetstream',
:ssh_password=>'jetstream1!',
:media_location_prefix=>'auxpreview104',
:source_image=>'SUSE__OpenSUSE64121-03192012-en-us-15GB',
:role_size=>'ExtraSmall'
}
end
# ToFix - breaks because it does not refresh each role
# within loop and does not know that it needs to delete
# a deployment instead of a role when it gets down to
# the last role in a deployment
it 'delete everything, build out completely' do
Chef::Log.info 'deleting any existing roles'
@connection.roles.all.each do |role|
Chef::Log.info 'deleting role' + role.name
@connection.roles.delete role.name
break
end
Chef::Log.info 'deleting any existing hosts'
@connection.hosts.all.each do |host|
Chef::Log.info 'deleting host' + host.name
@connection.hosts.delete host.name
end
# create 5 new roles
['001', '002', '003', '004', '005'].each do |val|
arbitrary = rand(1000) + 1
@params[:role_name]='role' + val + arbitrary.to_s
@params[:host_name]='host' + val
Chef::Log.info 'creating a new role named ' + @params[:role_name]
@connection.deploys.create(@params)
end
# refresh the roles list
Chef::Log.info 'refreshing roles'
@connection.roles.all
# list the roles
Chef::Log.info 'display roles'
@connection.roles.roles.each do |role|
Chef::Log.info role.name
end
end
#specify {@connection.roles.exists(@params[:role_name]).should == true}
#specify {@connection.roles.exists(@params[:role_name] + 'notexist').should == false}
end

40
spec/spec_helper.rb Executable file
Просмотреть файл

@ -0,0 +1,40 @@
#$LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
require 'rspec'
require 'equivalent-xml'
require 'chef'
require 'chef/log'
require 'azure/connection'
require 'azure/rest'
require 'azure/host'
require 'azure/image'
require 'azure/deploy'
require 'azure/role'
require 'azure/disk'
require 'chef/knife/azure_server_list'
require 'chef/knife/azure_server_delete'
require 'chef/knife/azure_server_create'
require 'chef/knife/azure_server_describe'
require 'chef/knife/azure_image_list'
def tmpFile filename
tmpdir = 'tmp'
Dir::mkdir tmpdir unless FileTest::directory?(tmpdir)
tmpdir + '/' + filename
end
Chef::Log.init(tmpFile('debug.log'), 'daily')
Chef::Log.level=:debug
module AzureSpecHelper
def readFile filename
File.read(File.dirname(__FILE__) + "/unit/assets/#{filename}")
end
def test_params
params = {:azure_subscription_id => "155a9851-88a8-49b4-98e4-58055f08f412", :azure_pem_file => "AzureLinuxCert.pem",
:azure_host_name => "management-preview.core.windows-int.net",
:service_name => "hostedservices"}
end
end

Просмотреть файл

@ -0,0 +1,37 @@
<?xml version="1.0"?> <Deployment xmlns:i="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://schemas.microsoft.com/windowsazure">
<Name>unknown_yet</Name>
<DeploymentSlot>Production</DeploymentSlot>
<Label>dW5rbm93bl95ZXQ=</Label>
<RoleList>
<Role i:type="PersistentVMRole">
<RoleName>vm01</RoleName>
<OsVersion i:nil="true"/>
<RoleType>PersistentVMRole</RoleType>
<ConfigurationSets>
<ConfigurationSet i:type="LinuxProvisioningConfigurationSet">
<ConfigurationSetType>LinuxProvisioningConfiguration</ConfigurationSetType>
<HostName>myVm</HostName>
<UserName>jetstream</UserName>
<UserPassword>jetstream1!</UserPassword>
<DisableSshPasswordAuthentication>false</DisableSshPasswordAuthentication>
</ConfigurationSet>
<ConfigurationSet i:type="NetworkConfigurationSet">
<ConfigurationSetType>NetworkConfiguration</ConfigurationSetType>
<InputEndpoints>
<InputEndpoint>
<LocalPort>22</LocalPort>
<Name>SSH</Name>
<Protocol>TCP</Protocol>
</InputEndpoint>
</InputEndpoints>
</ConfigurationSet>
</ConfigurationSets>
<Label>dm0wMQ==</Label>
<OSVirtualHardDisk>
<MediaLink>http://auxpreview104imagestore.blob.core.azure-preview.com/os-disks/disk004Test</MediaLink>
<SourceImageName>SUSE__OpenSUSE64121-03192012-en-us-15GB</SourceImageName>
</OSVirtualHardDisk>
<RoleSize>ExtraSmall</RoleSize>
</Role>
</RoleList>
</Deployment>

Просмотреть файл

@ -0,0 +1 @@
<Operation xmlns="http://schemas.microsoft.com/windowsazure" xmlns:i="http://www.w3.org/2001/XMLSchema-instance"><ID>878c6cd7-73d1-4527-949e-44eb7451547c</ID><Status>InProgress</Status></Operation>

Просмотреть файл

@ -0,0 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<CreateHostedService xmlns="http://schemas.microsoft.com/windowsazure">
<ServiceName>service003</ServiceName>
<Label>c2VydmljZTAwMw==</Label>
<Description>Explicitly created hosted service</Description>
<Location>Windows Azure Preview</Location>
</CreateHostedService>

Просмотреть файл

@ -0,0 +1,54 @@
<?xml version="1.0"?>
<PersistentVMRole xmlns="http://schemas.microsoft.com/windowsazure" xmlns:i="http://www.w3.org/2001/XMLSchema-instance">
<RoleName>vm01</RoleName>
<OsVersion i:nil="true"/>
<RoleType>PersistentVMRole</RoleType>
<ConfigurationSets>
<ConfigurationSet i:type="LinuxProvisioningConfigurationSet">
<ConfigurationSetType>LinuxProvisioningConfiguration</ConfigurationSetType>
<HostName>myVm</HostName>
<UserName>jetstream</UserName>
<UserPassword>jetstream1!</UserPassword>
<DisableSshPasswordAuthentication>false</DisableSshPasswordAuthentication>
</ConfigurationSet>
<ConfigurationSet i:type="NetworkConfigurationSet">
<ConfigurationSetType>NetworkConfiguration</ConfigurationSetType>
<InputEndpoints>
<InputEndpoint>
<LocalPort>22</LocalPort>
<Name>SSH</Name>
<Protocol>TCP</Protocol>
</InputEndpoint>
<InputEndpoint>
<LocalPort>44</LocalPort>
<Name>tcpport_44_myVm</Name>
<Port>45</Port>
<Protocol>TCP</Protocol>
</InputEndpoint>
<InputEndpoint>
<LocalPort>55</LocalPort>
<Name>tcpport_55_myVm</Name>
<Port>55</Port>
<Protocol>TCP</Protocol>
</InputEndpoint>
<InputEndpoint>
<LocalPort>65</LocalPort>
<Name>udpport_65_myVm</Name>
<Port>65</Port>
<Protocol>UDP</Protocol>
</InputEndpoint>
<InputEndpoint>
<LocalPort>75</LocalPort>
<Name>udpport_75_myVm</Name>
<Protocol>UDP</Protocol>
</InputEndpoint>
</InputEndpoints>
</ConfigurationSet>
</ConfigurationSets>
<Label>dm0wMQ==</Label>
<OSVirtualHardDisk>
<MediaLink>http://auxpreview104imagestore.blob.core.azure-preview.com/os-disks/disk004Test</MediaLink>
<SourceImageName>SUSE__OpenSUSE64121-03192012-en-us-15GB</SourceImageName>
</OSVirtualHardDisk>
<RoleSize>ExtraSmall</RoleSize>
</PersistentVMRole>

Просмотреть файл

@ -0,0 +1,126 @@
<?xml version="1.0"?>
<Deployment xmlns="http://schemas.microsoft.com/windowsazure" xmlns:i="http://www.w3.org/2001/XMLSchema-instance">
<Name>service003</Name>
<DeploymentSlot>Production</DeploymentSlot>
<PrivateID>34f75bed486643d39affeb9f98d47227</PrivateID>
<Status>Running</Status>
<Label>YzJWeWRtbGpaVEF3TXc9PQ==</Label>
<Url>http://service003.cloudapp-preview.net/</Url>
<Configuration>PFNlcnZpY2VDb25maWd1cmF0aW9uIHhtbG5zOnhzaT0iaHR0cDovL3d3dy53My5vcmcvMjAwMS9YTUxTY2hlbWEtaW5zdGFuY2UiIHhtbG5zOnhzZD0iaHR0cDovL3d3dy53My5vcmcvMjAwMS9YTUxTY2hlbWEiIHhtbG5zPSJodHRwOi8vc2NoZW1hcy5taWNyb3NvZnQuY29tL1NlcnZpY2VIb3N0aW5nLzIwMDgvMTAvU2VydmljZUNvbmZpZ3VyYXRpb24iPg0KICA8Um9sZSBuYW1lPSJyb2xlMjA2Ij4NCiAgICA8SW5zdGFuY2VzIGNvdW50PSIxIiAvPg0KICA8L1JvbGU+DQo8L1NlcnZpY2VDb25maWd1cmF0aW9uPg==</Configuration>
<RoleInstanceList>
<RoleInstance>
<RoleName>role206</RoleName>
<InstanceName>role206</InstanceName>
<InstanceStatus>StoppedVM</InstanceStatus>
<InstanceUpgradeDomain>0</InstanceUpgradeDomain>
<InstanceFaultDomain>0</InstanceFaultDomain>
<InstanceSize>ExtraSmall</InstanceSize>
<InstanceStateDetails/>
<IpAddress>10.26.198.33</IpAddress>
<InstanceEndpoints>
<InstanceEndpoint>
<Name>SSH</Name>
<Vip>65.52.251.57</Vip>
<PublicPort>49627</PublicPort>
<LocalPort>22</LocalPort>
<Protocol>tcp</Protocol>
</InstanceEndpoint>
<InstanceEndpoint>
<Name>tcpport66</Name>
<Vip>65.52.251.57</Vip>
<PublicPort>66</PublicPort>
<LocalPort>66</LocalPort>
<Protocol>tcp</Protocol>
</InstanceEndpoint>
<InstanceEndpoint>
<Name>udpport77</Name>
<Vip>65.52.251.57</Vip>
<PublicPort>77</PublicPort>
<LocalPort>77</LocalPort>
<Protocol>udp</Protocol>
</InstanceEndpoint>
<InstanceEndpoint>
<Name>udpport88</Name>
<Vip>65.52.251.57</Vip>
<PublicPort>88</PublicPort>
<LocalPort>88</LocalPort>
<Protocol>udp</Protocol>
</InstanceEndpoint>
<InstanceEndpoint>
<Name>udpport99</Name>
<Vip>65.52.251.57</Vip>
<PublicPort>99</PublicPort>
<LocalPort>99</LocalPort>
<Protocol>udp</Protocol>
</InstanceEndpoint>
</InstanceEndpoints>
<PowerState>Stopped</PowerState>
</RoleInstance>
</RoleInstanceList>
<UpgradeDomainCount>1</UpgradeDomainCount>
<RoleList>
<Role i:type="PersistentVMRole">
<RoleName>role206</RoleName>
<OsVersion/>
<RoleType>PersistentVMRole</RoleType>
<ConfigurationSets>
<ConfigurationSet i:type="NetworkConfigurationSet">
<ConfigurationSetType>NetworkConfiguration</ConfigurationSetType>
<InputEndpoints>
<InputEndpoint>
<LocalPort>22</LocalPort>
<Name>SSH</Name>
<Port>49627</Port>
<Protocol>tcp</Protocol>
<Vip>65.52.251.57</Vip>
</InputEndpoint>
<InputEndpoint>
<LocalPort>66</LocalPort>
<Name>tcpport66</Name>
<Port>66</Port>
<Protocol>tcp</Protocol>
<Vip>65.52.251.57</Vip>
</InputEndpoint>
<InputEndpoint>
<LocalPort>77</LocalPort>
<Name>udpport77</Name>
<Port>77</Port>
<Protocol>udp</Protocol>
<Vip>65.52.251.57</Vip>
</InputEndpoint>
<InputEndpoint>
<LocalPort>88</LocalPort>
<Name>udpport88</Name>
<Port>88</Port>
<Protocol>udp</Protocol>
<Vip>65.52.251.57</Vip>
</InputEndpoint>
<InputEndpoint>
<LocalPort>99</LocalPort>
<Name>udpport99</Name>
<Port>99</Port>
<Protocol>udp</Protocol>
<Vip>65.52.251.57</Vip>
</InputEndpoint>
</InputEndpoints>
<SubnetNames/>
</ConfigurationSet>
</ConfigurationSets>
<DataVirtualHardDisks/>
<OSVirtualHardDisk>
<HostCaching>ReadWrite</HostCaching>
<DiskName>service003-role206-0-20120528151407</DiskName>
<MediaLink>http://auxpreview104imagestore.blob.core.azure-preview.com/os-disks/disk_2012_05_28_08_13</MediaLink>
<SourceImageName>SUSE__OpenSUSE64121-03192012-en-us-15GB.vhd</SourceImageName>
<OS>Linux</OS>
</OSVirtualHardDisk>
<RoleSize>ExtraSmall</RoleSize>
</Role>
</RoleList>
<SdkVersion/>
<Locked>false</Locked>
<RollbackAllowed>false</RollbackAllowed>
<CreatedTime>2012-05-28T15:14:05Z</CreatedTime>
<LastModifiedTime>2012-05-28T16:29:06Z</LastModifiedTime>
<ExtendedProperties/>
</Deployment>

Просмотреть файл

@ -0,0 +1,166 @@
<?xml version="1.0"?>
<Deployment xmlns="http://schemas.microsoft.com/windowsazure" xmlns:i="http://www.w3.org/2001/XMLSchema-instance">
<Name>deployment001</Name>
<DeploymentSlot>Production</DeploymentSlot>
<PrivateID>2b1f2f0a4b414088a0ec64d583d9c4b3</PrivateID>
<Status>Running</Status>
<Label>WkdWd2JHOTViV1Z1ZERBd01RPT0=</Label>
<Url>http://service001.cloudapp-preview.net/</Url>
<Configuration>PFNlcnZpY2VDb25maWd1cmF0aW9uIHhtbG5zOnhzaT0iaHR0cDovL3d3dy53My5vcmcvMjAwMS9YTUxTY2hlbWEtaW5zdGFuY2UiIHhtbG5zOnhzZD0iaHR0cDovL3d3dy53My5vcmcvMjAwMS9YTUxTY2hlbWEiIHhtbG5zPSJodHRwOi8vc2NoZW1hcy5taWNyb3NvZnQuY29tL1NlcnZpY2VIb3N0aW5nLzIwMDgvMTAvU2VydmljZUNvbmZpZ3VyYXRpb24iPg0KICA8Um9sZSBuYW1lPSJyb2xlMDAyIj4NCiAgICA8SW5zdGFuY2VzIGNvdW50PSIxIiAvPg0KICA8L1JvbGU+DQogIDxSb2xlIG5hbWU9InJvbGUwMDEiPg0KICAgIDxJbnN0YW5jZXMgY291bnQ9IjEiIC8+DQogIDwvUm9sZT4NCjwvU2VydmljZUNvbmZpZ3VyYXRpb24+</Configuration>
<RoleInstanceList>
<RoleInstance>
<RoleName>vm002</RoleName>
<InstanceName>vm002</InstanceName>
<InstanceStatus>ReadyRole</InstanceStatus>
<InstanceUpgradeDomain>0</InstanceUpgradeDomain>
<InstanceFaultDomain>0</InstanceFaultDomain>
<InstanceSize>ExtraSmall</InstanceSize>
<InstanceStateDetails/>
<IpAddress>10.26.198.146</IpAddress>
<InstanceEndpoints>
<InstanceEndpoint>
<Name>tcpport66</Name>
<Vip>65.52.251.57</Vip>
<PublicPort>66</PublicPort>
<LocalPort>66</LocalPort>
<Protocol>tcp</Protocol>
</InstanceEndpoint>
<InstanceEndpoint>
<Name>SSH</Name>
<Vip>65.52.249.191</Vip>
<PublicPort>22</PublicPort>
<LocalPort>22</LocalPort>
<Protocol>tcp</Protocol>
</InstanceEndpoint>
</InstanceEndpoints>
<PowerState>Started</PowerState>
<HostName>myVm2</HostName>
</RoleInstance>
<RoleInstance>
<RoleName>role002</RoleName>
<InstanceName>role002</InstanceName>
<InstanceStatus>RoleStateUnknown</InstanceStatus>
<InstanceUpgradeDomain>0</InstanceUpgradeDomain>
<InstanceFaultDomain>0</InstanceFaultDomain>
<InstanceSize>Small</InstanceSize>
<InstanceStateDetails/>
<IpAddress>10.26.196.201</IpAddress>
<InstanceEndpoints>
<InstanceEndpoint>
<Name>ssh</Name>
<Vip>65.52.249.191</Vip>
<PublicPort>23</PublicPort>
<LocalPort>22</LocalPort>
<Protocol>tcp</Protocol>
</InstanceEndpoint>
</InstanceEndpoints>
<PowerState>Started</PowerState>
<HostName>role002</HostName>
</RoleInstance>
<RoleInstance>
<RoleName>role001</RoleName>
<InstanceName>role001</InstanceName>
<InstanceStatus>ReadyRole</InstanceStatus>
<InstanceUpgradeDomain>0</InstanceUpgradeDomain>
<InstanceFaultDomain>0</InstanceFaultDomain>
<InstanceSize>Small</InstanceSize>
<InstanceStateDetails/>
<IpAddress>10.26.196.254</IpAddress>
<InstanceEndpoints>
<InstanceEndpoint>
<Name>ssh</Name>
<Vip>65.52.249.191</Vip>
<PublicPort>22</PublicPort>
<LocalPort>22</LocalPort>
<Protocol>tcp</Protocol>
</InstanceEndpoint>
</InstanceEndpoints>
<PowerState>Started</PowerState>
<HostName>role001</HostName>
</RoleInstance>
</RoleInstanceList>
<UpgradeDomainCount>1</UpgradeDomainCount>
<RoleList>
<Role>
<RoleName>vm002</RoleName>
<OsVersion>WA-GUEST-OS-1.18_201203-01</OsVersion>
<ConfigurationSets>
<ConfigurationSet i:type="NetworkConfigurationSet">
<ConfigurationSetType>NetworkConfiguration</ConfigurationSetType>
<InputEndpoints>
<InputEndpoint>
<Port>60657</Port>
<Protocol>tcp</Protocol>
<Vip>65.52.249.191</Vip>
</InputEndpoint>
</InputEndpoints>
<SubnetNames/>
</ConfigurationSet>
</ConfigurationSets>
</Role>
<Role i:type="PersistentVMRole">
<RoleName>role002</RoleName>
<OsVersion>WA-GUEST-OS-1.18_201203-01</OsVersion>
<RoleType>PersistentVMRole</RoleType>
<ConfigurationSets>
<ConfigurationSet i:type="NetworkConfigurationSet">
<ConfigurationSetType>NetworkConfiguration</ConfigurationSetType>
<InputEndpoints>
<InputEndpoint>
<LocalPort>22</LocalPort>
<Name>ssh</Name>
<Port>23</Port>
<Protocol>tcp</Protocol>
<Vip>65.52.249.191</Vip>
</InputEndpoint>
</InputEndpoints>
<SubnetNames/>
</ConfigurationSet>
</ConfigurationSets>
<DataVirtualHardDisks/>
<OSVirtualHardDisk>
<HostCaching>ReadWrite</HostCaching>
<DiskName>deployment001-role002-0-201241722728</DiskName>
<MediaLink>http://auxpreview104imagestore.blob.core.azure-preview.com/os-disks/disk002b</MediaLink>
<SourceImageName>SUSE__OpenSUSE64121-03192012-en-us-15GB</SourceImageName>
<OS>Linux</OS>
</OSVirtualHardDisk>
<RoleSize>Small</RoleSize>
</Role>
<Role i:type="PersistentVMRole">
<RoleName>role001</RoleName>
<OsVersion>WA-GUEST-OS-1.18_201203-01</OsVersion>
<RoleType>PersistentVMRole</RoleType>
<ConfigurationSets>
<ConfigurationSet i:type="NetworkConfigurationSet">
<ConfigurationSetType>NetworkConfiguration</ConfigurationSetType>
<InputEndpoints>
<InputEndpoint>
<LocalPort>22</LocalPort>
<Name>ssh</Name>
<Port>22</Port>
<Protocol>tcp</Protocol>
<Vip>65.52.249.191</Vip>
</InputEndpoint>
</InputEndpoints>
<SubnetNames/>
</ConfigurationSet>
</ConfigurationSets>
<DataVirtualHardDisks/>
<OSVirtualHardDisk>
<HostCaching>ReadWrite</HostCaching>
<DiskName>deployment001-role001-0-201241722113</DiskName>
<MediaLink>http://auxpreview104imagestore.blob.core.azure-preview.com/os-disks/disk001</MediaLink>
<SourceImageName>SUSE__OpenSUSE64121-03192012-en-us-15GB</SourceImageName>
<OS>Linux</OS>
</OSVirtualHardDisk>
<RoleSize>Small</RoleSize>
</Role>
</RoleList>
<SdkVersion>1.7</SdkVersion>
<Locked>false</Locked>
<RollbackAllowed>true</RollbackAllowed>
<CreatedTime>2012-04-17T22:01:10Z</CreatedTime>
<LastModifiedTime>2012-04-23T23:52:09Z</LastModifiedTime>
<ExtendedProperties/>
</Deployment>

Просмотреть файл

@ -0,0 +1 @@
<Deployment xmlns="http://schemas.microsoft.com/windowsazure" xmlns:i="http://www.w3.org/2001/XMLSchema-instance"><Name>testrequest</Name><DeploymentSlot>Production</DeploymentSlot><PrivateID>0f6204c7b38b457a913be856a23e3142</PrivateID><Status>Running</Status><Label>ZEdWemRHbHVkbUZzYVdSemRYTmw=</Label><Url>http://service002.cloudapp-preview.net/</Url><Configuration>PFNlcnZpY2VDb25maWd1cmF0aW9uIHhtbG5zOnhzaT0iaHR0cDovL3d3dy53My5vcmcvMjAwMS9YTUxTY2hlbWEtaW5zdGFuY2UiIHhtbG5zOnhzZD0iaHR0cDovL3d3dy53My5vcmcvMjAwMS9YTUxTY2hlbWEiIHhtbG5zPSJodHRwOi8vc2NoZW1hcy5taWNyb3NvZnQuY29tL1NlcnZpY2VIb3N0aW5nLzIwMDgvMTAvU2VydmljZUNvbmZpZ3VyYXRpb24iPg0KICA8Um9sZSBuYW1lPSJ2bTAxIj4NCiAgICA8SW5zdGFuY2VzIGNvdW50PSIxIiAvPg0KICA8L1JvbGU+DQo8L1NlcnZpY2VDb25maWd1cmF0aW9uPg==</Configuration><RoleInstanceList><RoleInstance><RoleName>vm01</RoleName><InstanceName>vm01</InstanceName><InstanceStatus>ReadyRole</InstanceStatus><InstanceUpgradeDomain>0</InstanceUpgradeDomain><InstanceFaultDomain>0</InstanceFaultDomain><InstanceSize>ExtraSmall</InstanceSize><InstanceStateDetails/><IpAddress>10.26.194.166</IpAddress><InstanceEndpoints><InstanceEndpoint><Name>SSH</Name><Vip>65.52.251.144</Vip><PublicPort>54047</PublicPort><LocalPort>22</LocalPort><Protocol>tcp</Protocol></InstanceEndpoint></InstanceEndpoints><PowerState>Started</PowerState><HostName>myVm</HostName></RoleInstance></RoleInstanceList><UpgradeDomainCount>1</UpgradeDomainCount><RoleList><Role i:type="PersistentVMRole"><RoleName>vm01</RoleName><OsVersion>WA-GUEST-OS-1.18_201203-01</OsVersion><RoleType>PersistentVMRole</RoleType><ConfigurationSets><ConfigurationSet i:type="NetworkConfigurationSet"><ConfigurationSetType>NetworkConfiguration</ConfigurationSetType><InputEndpoints><InputEndpoint><LocalPort>22</LocalPort><Name>SSH</Name><Port>54047</Port><Protocol>tcp</Protocol><Vip>65.52.251.144</Vip></InputEndpoint></InputEndpoints><SubnetNames/></ConfigurationSet></ConfigurationSets><DataVirtualHardDisks/><OSVirtualHardDisk><HostCaching>ReadWrite</HostCaching><DiskName>testrequest-vm01-0-2012423214252</DiskName><MediaLink>http://auxpreview104imagestore.blob.core.azure-preview.com/os-disks/disk004Test</MediaLink><SourceImageName>SUSE__OpenSUSE64121-03192012-en-us-15GB</SourceImageName><OS>Linux</OS></OSVirtualHardDisk><RoleSize>ExtraSmall</RoleSize></Role></RoleList><SdkVersion>1.7</SdkVersion><Locked>false</Locked><RollbackAllowed>false</RollbackAllowed><CreatedTime>2012-04-23T21:46:44Z</CreatedTime><LastModifiedTime>2012-04-23T21:56:47Z</LastModifiedTime><ExtendedProperties/></Deployment>

Просмотреть файл

@ -0,0 +1 @@
<Error xmlns="http://schemas.microsoft.com/windowsazure" xmlns:i="http://www.w3.org/2001/XMLSchema-instance"><Code>ResourceNotFound</Code><Message>No deployments were found.</Message></Error>

Просмотреть файл

@ -0,0 +1 @@
<Disks xmlns="http://schemas.microsoft.com/windowsazure" xmlns:i="http://www.w3.org/2001/XMLSchema-instance"><Disk><OS>Linux</OS><Location>Windows Azure Preview</Location><LogicalDiskSizeInGB>15</LogicalDiskSizeInGB><MediaLink>http://auxpreview104imagestore.blob.core.azure-preview.com/os-disks/disk104</MediaLink><Name>service002-role104-0-201257233812</Name><SourceImageName>SUSE__OpenSUSE64121-03192012-en-us-15GB</SourceImageName></Disk><Disk><OS>Linux</OS><Location>Windows Azure Preview</Location><LogicalDiskSizeInGB>15</LogicalDiskSizeInGB><MediaLink>http://auxpreview104imagestore.blob.core.azure-preview.com/os-disks/disk105</MediaLink><Name>service002-role105-0-201257235741</Name><SourceImageName>SUSE__OpenSUSE64121-03192012-en-us-15GB</SourceImageName></Disk><Disk><OS>Linux</OS><Location>Windows Azure Preview</Location><LogicalDiskSizeInGB>30</LogicalDiskSizeInGB><MediaLink>http://auxpreview104imagestore.blob.core.azure-preview.com/os-disks/disk106</MediaLink><Name>service002-role106-0-20125801047</Name><SourceImageName>OpenLogic__OpenLogic-CentOS-62-en-us-30GB</SourceImageName></Disk><Disk><OS>Linux</OS><Location>Windows Azure Preview</Location><LogicalDiskSizeInGB>15</LogicalDiskSizeInGB><MediaLink>http://auxpreview104imagestore.blob.core.azure-preview.com/os-disks/disk107</MediaLink><Name>service002-role107-0-20125814427</Name><SourceImageName>SUSE__OpenSUSE64121-03192012-en-us-15GB</SourceImageName></Disk><Disk><OS>Linux</OS><Location>Windows Azure Preview</Location><LogicalDiskSizeInGB>15</LogicalDiskSizeInGB><MediaLink>http://auxpreview104imagestore.blob.core.azure-preview.com/os-disks/disk108</MediaLink><Name>service002-role108-0-201258152913</Name><SourceImageName>SUSE__OpenSUSE64121-03192012-en-us-15GB</SourceImageName></Disk><Disk><OS>Linux</OS><Location>Windows Azure Preview</Location><LogicalDiskSizeInGB>15</LogicalDiskSizeInGB><MediaLink>http://auxpreview104imagestore.blob.core.azure-preview.com/os-disks/disk109</MediaLink><Name>service002-role109-0-201258165947</Name><SourceImageName>SUSE__OpenSUSE64121-03192012-en-us-15GB</SourceImageName></Disk><Disk><AttachedTo><DeploymentName>service002</DeploymentName><HostedServiceName>service002</HostedServiceName><RoleName>role119</RoleName></AttachedTo><OS>Linux</OS><Location>Windows Azure Preview</Location><LogicalDiskSizeInGB>30</LogicalDiskSizeInGB><MediaLink>http://auxpreview104imagestore.blob.core.azure-preview.com/os-disks/disk119</MediaLink><Name>service002-role119-0-201258172212</Name><SourceImageName>OpenLogic__OpenLogic-CentOS-62-en-us-30GB</SourceImageName></Disk><Disk><OS>Linux</OS><Location>Windows Azure Preview</Location><LogicalDiskSizeInGB>30</LogicalDiskSizeInGB><MediaLink>http://auxpreview104imagestore.blob.core.azure-preview.com/os-disks/disk120</MediaLink><Name>service002-role120-0-201258203045</Name><SourceImageName>OpenLogic__OpenLogic-CentOS-62-en-us-30GB</SourceImageName></Disk></Disks>

Просмотреть файл

@ -0,0 +1 @@
<HostedServices xmlns="http://schemas.microsoft.com/windowsazure" xmlns:i="http://www.w3.org/2001/XMLSchema-instance"><HostedService><Url>https://management-preview.core.windows-int.net/155a9851-88a8-49b4-98e4-58055f08f412/services/hostedservices/service001</Url><ServiceName>service001</ServiceName><HostedServiceProperties><Description>Explicitly created hosted service</Description><Location>Windows Azure Preview</Location><Label>c2VydmljZTAwMQ==</Label><Status>Created</Status><DateCreated>2012-04-17T21:56:23Z</DateCreated><DateLastModified>2012-04-17T22:01:08Z</DateLastModified><ExtendedProperties/></HostedServiceProperties></HostedService><HostedService><Url>https://management-preview.core.windows-int.net/155a9851-88a8-49b4-98e4-58055f08f412/services/hostedservices/service002</Url><ServiceName>service002</ServiceName><HostedServiceProperties><Description>Explicitly created hosted service</Description><Location>Windows Azure Preview</Location><Label>c2VydmljZTAwMg==</Label><Status>Created</Status><DateCreated>2012-04-17T22:27:08Z</DateCreated><DateLastModified>2012-04-23T21:42:47Z</DateLastModified><ExtendedProperties/></HostedServiceProperties></HostedService><HostedService><Url>https://management-preview.core.windows-int.net/155a9851-88a8-49b4-98e4-58055f08f412/services/hostedservices/service003</Url><ServiceName>service003</ServiceName><HostedServiceProperties><Description>Explicitly created hosted service</Description><Location>Windows Azure Preview</Location><Label>c2VydmljZTAwMw==</Label><Status>Created</Status><DateCreated>2012-04-19T20:17:26Z</DateCreated><DateLastModified>2012-04-19T20:17:25Z</DateLastModified><ExtendedProperties/></HostedServiceProperties></HostedService></HostedServices>

Просмотреть файл

@ -0,0 +1 @@
<Images xmlns="http://schemas.microsoft.com/windowsazure" xmlns:i="http://www.w3.org/2001/XMLSchema-instance"><OSImage><Category>Canonical</Category><Label>Ubuntu Server 12.04 20120519</Label><Name>CANONICAL__Canonical-Ubuntu-12-04-20120519-2012-05-19-en-us-30GB.vhd</Name><OS>Linux</OS><Eula>http://www.ubuntu.com/project/about-ubuntu/licensing</Eula><Description>Ubuntu Server 12.04 (Precise Pangolin) 20120519 Cloud Image</Description></OSImage><OSImage><Category>Microsoft</Category><Label>Windows Server 2008 R2 SP1, Nov 2011</Label><LogicalSizeInGB>30</LogicalSizeInGB><Name>MSFT__Windows-Server-2008-R2-SP1.11-29-2011</Name><OS>Windows</OS><Eula>http://www.microsoft.com</Eula><Description>Microsoft Windows Server 2008 R2 SP1</Description></OSImage><OSImage><Category>Microsoft</Category><Label>SQL Server 2012 Evaluation, Nov 2011</Label><LogicalSizeInGB>30</LogicalSizeInGB><Name>MSFT__Windows-Server-2008-R2-SP1-with-SQL-Server-2012-Eval.11-29-2011</Name><OS>Windows</OS><Eula>http://download.microsoft.com/download/A/A/7/AA73B8F4-5F4B-4C0B-94F4-FB238C92A916/ENU/SQL Server 2012 Evaluation.rtf</Eula><Description>Microsoft Windows 2008 R2 Service Pack 1 with SQL Server 2012 Evaluation Edition (64-bit). This version has licensing restrictions and cannot be used in production. Use of this version is limited to 6 months.</Description></OSImage><OSImage><Category>Microsoft</Category><Label>Windows Server 8 Beta, Mar 2012</Label><LogicalSizeInGB>30</LogicalSizeInGB><Name>MSFT__Windows-Server-8-Beta.en-us.30GB.2012-03-22</Name><OS>Windows</OS><Eula>http://msdn.microsoft.com/en-us/windows/apps/br229516</Eula><Description>The next release of Windows Server, Windows Server "8", offers businesses and hosting providers a scalable, dynamic, and multitenant-aware, cloud-optimized infrastructure. It securely connects across premises and allows IT Professionals to respond to business needs faster and more efficiently.</Description></OSImage><OSImage><Category>Microsoft</Category><Label>Windows Server 8 Beta, Feb 2012</Label><LogicalSizeInGB>40</LogicalSizeInGB><Name>MSFT__Windows-Server-8-Beta.2-17-2012</Name><OS>Windows</OS><Eula>http://www.microsoft.com</Eula><Description>The next release of Windows Server, Windows Server "8", offers businesses and hosting providers a scalable, dynamic, and multitenant-aware, cloud-optimized infrastructure. It securely connects across premises and allows IT Professionals to respond to business needs faster and more efficiently.</Description></OSImage><OSImage><Category>Microsoft</Category><Label>Windows Server 2008 R2 SP1, Mar 2012</Label><LogicalSizeInGB>30</LogicalSizeInGB><Name>MSFT__Windows-Server-2008-R2-SP1.en-us.30GB.2012-3-22</Name><OS>Windows</OS><Eula>http://msdn.microsoft.com/en-us/windows/apps/br229516</Eula><Description>Microsoft Windows 2008 R2 Service Pack 1 for IAAS</Description></OSImage><OSImage><Category>OpenLogic</Category><Label>CentOS 6.2 provided by OpenLogic</Label><Name>OpenLogic__OpenLogic-CentOS-62-20120509-en-us-30GB.vhd</Name><OS>Linux</OS><Eula>http://www.openlogic.com/azure/service-agreement.php</Eula><Description>This distribution of CentOS version 6.2 is provided by OpenLogic and contains an installation of the Basic Server packages.</Description></OSImage><OSImage><Category>SUSE</Category><Label>SUSE Linux Enterprise Server</Label><Name>SUSE__SUSE-Linux-Enterprise-Server-11SP2-20120521-en-us-30GB.vhd</Name><OS>Linux</OS><Eula>http://www.novell.com/licensing/eula/</Eula><Description>SUSE Linux Enterprise Server is a highly reliable, scalable, and secure server operating system, built to power mission-critical workloads in both physical and virtual environments. It is an affordable, interoperable, and manageable open source foundation. With it, enterprises can cost-effectively deliver core business services, enable secure networks, and simplify the management of their heterogeneous IT infrastructure, maximizing efficiency and value.</Description></OSImage><OSImage><Category>SUSE</Category><Label>OpenSUSE64-12.1-Beta</Label><Name>SUSE__OpenSUSE64121-03192012-en-us-15GB.vhd</Name><OS>Linux</OS><Eula>http://www.novell.com/licensing/eula/</Eula><Description>OpenSUSE Linux 64 Bits (IAAS M1 Preview)</Description></OSImage></Images>

Просмотреть файл

@ -0,0 +1,6 @@
<?xml version="1.0"?>
<Operation xmlns="http://schemas.microsoft.com/windowsazure" xmlns:i="http://www.w3.org/2001/XMLSchema-instance">
<ID>878c6cd7-73d1-4527-949e-44eb7451547c</ID>
<Status>Succeeded</Status>
<HttpStatusCode>200</HttpStatusCode>
</Operation>

55
spec/unit/deploys_list_spec.rb Executable file
Просмотреть файл

@ -0,0 +1,55 @@
require File.expand_path(File.dirname(__FILE__) + '/../spec_helper')
require File.expand_path(File.dirname(__FILE__) + '/query_azure_mock')
describe "deploys" do
include AzureSpecHelper
include QueryAzureMock
before 'setup connection' do
setup_query_azure_mock
end
specify {@connection.deploys.all.length.should be > 0}
it 'each deployment should have values' do
@connection.deploys.all.each do |deploy|
deploy.name.should_not be_nil
deploy.status.should_not be_nil
deploy.url.should_not be_nil
deploy.roles.length.should be > 0
end
end
it 'each role should have values' do
@connection.deploys.all.each do |deploy|
#describe_deploy deploy
deploy.roles.each do |role|
#describe_role role
role.name.should_not be_nil
role.status.should_not be_nil
role.size.should_not be_nil
role.ipaddress.should_not be_nil
role.sshport.should_not be_nil
role.sshipaddress.should_not be_nil
end
end
end
def describe_deploy(deploy)
puts '============================='
puts 'deployed service: ' + deploy.hostedservicename + ' deployment: ' + deploy.name
end
def describe_role(role)
puts 'role: ' + role.name
puts 'status: ' + role.status
puts 'size: ' + role.size
puts 'ip address: ' + role.ipaddress
puts 'ssh port: ' + role.sshport
puts 'ssh ip address: ' + role.sshipaddress
role.tcpports.each do |port|
puts ' tcp: ' + port['Name'] + ' ' + port['Vip'] + ' ' +
port['PublicPort'] + ' ' + port['LocalPort']
end
role.udpports.each do |port|
puts ' udp: ' + port['Name'] + ' ' + port['Vip'] + ' ' +
port['PublicPort'] + ' ' + port['LocalPort']
end
puts '============================='
end
end

44
spec/unit/disks_spec.rb Executable file
Просмотреть файл

@ -0,0 +1,44 @@
require File.expand_path(File.dirname(__FILE__) + '/../spec_helper')
require File.expand_path(File.dirname(__FILE__) + '/query_azure_mock')
describe "disks" do
include AzureSpecHelper
include QueryAzureMock
before 'setup connection' do
setup_query_azure_mock
end
context 'mock with actually retrieved values' do
it "should find strings" do
items = @connection.disks.all
items.length.should be > 1
items.each do |disk|
disk.name.should_not be_nil
end
end
it "should contain an attached disk" do
items = @connection.disks.all
count = 0;
items.each do |item|
if item.attached == true
count += 1
end
end
count.should == 1
end
it "should contain unattached disks" do
items = @connection.disks.all
count = 0;
items.each do |item|
if item.attached == false
count += 1
end
end
count.should == 7
end
it "should clear all unattached disks" do
@connection.disks.clear_unattached
@deletecount.should == 7
end
end
end

55
spec/unit/hosts_spec.rb Executable file
Просмотреть файл

@ -0,0 +1,55 @@
require File.expand_path(File.dirname(__FILE__) + '/../spec_helper')
require File.expand_path(File.dirname(__FILE__) + '/query_azure_mock')
describe "hosts" do
include AzureSpecHelper
include QueryAzureMock
before 'setup connection' do
setup_query_azure_mock
end
context 'get all hosts' do
specify {@connection.hosts.all.length.should be > 1}
it "entry fields should not be nil" do
items = @connection.hosts.all
items.each do |host|
host.name.should_not be_nil
host.url.should_not be_nil
host.label.should_not be_nil
host.dateCreated.should_not be_nil
host.description.should_not be_nil
host.location.should_not be_nil
host.dateModified.should_not be_nil
host.status.should_not be_nil
end
end
specify {@connection.hosts.exists("notExpectedName").should == false}
specify {@connection.hosts.exists("service001").should == true}
end
context 'create a new host' do
it 'using explicit parameters it should pass in expected body' do
params = {:hosted_service_name=>'service003', 'hosted_service_description'=>'Explicitly created hosted service', 'hosted_service_location'=>'Windows Azure Preview'}
host = @connection.hosts.create(params)
@postname.should == 'hostedservices'
@postverb.should == 'post'
Nokogiri::XML(@postbody).should be_equivalent_to(Nokogiri::XML readFile('create_host.xml'))
end
it 'using default parameters it should pass in expected body' do
params = {:hosted_service_name=>'service003'}
host = @connection.hosts.create(params)
@postname.should == 'hostedservices'
@postverb.should == 'post'
Nokogiri::XML(@postbody).should be_equivalent_to(Nokogiri::XML readFile('create_host.xml'))
end
end
context 'delete a host' do
it 'should pass in correct name, verb, and body' do
@connection.hosts.delete('service001');
@deletename.should == 'hostedservices/service001'
@deleteverb.should == 'delete'
@deletebody.should == nil
end
end
end

35
spec/unit/images_spec.rb Executable file
Просмотреть файл

@ -0,0 +1,35 @@
require File.expand_path(File.dirname(__FILE__) + '/../spec_helper')
require File.expand_path(File.dirname(__FILE__) + '/query_azure_mock')
describe "images" do
include AzureSpecHelper
include QueryAzureMock
before 'setup connection' do
setup_query_azure_mock
end
context 'mock with actually retrieved values' do
it "should find strings" do
items = @connection.images.all
items.length.should be > 1
items.each do |image|
image.category.should_not be_nil
image.label.should_not be_nil
image.name.should_not be_nil
image.os.should_not be_nil
image.eula.should_not be_nil
image.description.should_not be_nil
end
end
it "should contain a linux image" do
items = @connection.images.all
foundLinux = false
items.each do |item|
if item.os == 'Linux'
foundLinux = true
end
end
foundLinux.should == true
end
end
end

72
spec/unit/query_azure_mock.rb Executable file
Просмотреть файл

@ -0,0 +1,72 @@
module QueryAzureMock
def setup_query_azure_mock
@getname = ''
@getverb = ''
@getbody = ''
@postname = ''
@postverb = ''
@postbody = ''
@deletename = ''
@deleteverb = ''
@deletebody = ''
@deletecount = 0
params = {:azure_subscription_id => "155a9851-88a8-49b4-98e4-58055f08f412", :azure_pem_file => "AzureLinuxCert.pem",
:azure_host_name => "management-preview.core.windows-int.net",
:service_name => "hostedservices"}
@receivedXML = Nokogiri::XML ''
@connection = Azure::Connection.new(params)
@connection.stub(:query_azure) do |name, verb, body|
Chef::Log.info 'calling web service:' + name
if verb == 'get' || verb == nil
retval = ''
if name == 'images'
retval = Nokogiri::XML readFile('list_images.xml')
elsif name == 'disks'
retval = Nokogiri::XML readFile('list_disks.xml')
elsif name == 'hostedservices'
retval = Nokogiri::XML readFile('list_hosts.xml')
elsif name == 'hostedservices/service001/deploymentslots/Production'
retval = Nokogiri::XML readFile('list_deployments_for_service001.xml')
elsif name == 'hostedservices/service002/deploymentslots/Production'
retval = Nokogiri::XML readFile('list_deployments_for_service002.xml')
elsif name == 'hostedservices/service003/deploymentslots/Production'
retval = Nokogiri::XML readFile('list_deployments_for_service003.xml')
else
Chef::Log.warn 'unknown get value:' + name
end
@getname = name
@getverb = verb
@getbody = body
elsif verb == 'post'
if name == 'hostedservices'
retval = Nokogiri::XML readFile('post_success.xml')
@receivedXML = body
elsif name == 'hostedservices/unknown_yet/deployments'
retval = Nokogiri::XML readFile('post_success.xml')
@receivedXML = body
elsif name == 'hostedservices/service001/deployments/deployment001/roles'
retval = Nokogiri::XML readFile('post_success.xml')
@receivedXML = body
else
Chef::Log.warn 'unknown post value:' + name
end
@postname = name
@postverb = verb
@postbody = body
elsif verb == 'delete'
@deletename = name
@deleteverb = verb
@deletebody = body
@deletecount += 1
else
Chef::Log.warn 'unknown verb:' + verb
end
retval
end
end
end

82
spec/unit/roles_create_spec.rb Executable file
Просмотреть файл

@ -0,0 +1,82 @@
require File.expand_path(File.dirname(__FILE__) + '/../spec_helper')
require File.expand_path(File.dirname(__FILE__) + '/query_azure_mock')
describe "roles" do
include AzureSpecHelper
include QueryAzureMock
before do
setup_query_azure_mock
end
context 'delete a role' do
context 'when the role is not the only one in a deployment' do
it 'should pass in correct name, verb, and body' do
@connection.roles.delete('vm002');
@deletename.should == 'hostedservices/service001/deployments/deployment001/roles/vm002'
@deleteverb.should == 'delete'
@deletebody.should == nil
end
end
end
context 'delete a role' do
context 'when the role is the only one in a deployment' do
it 'should pass in correct name, verb, and body' do
@connection.roles.delete('vm01');
@deletename.should == 'hostedservices/service002/deployments/testrequest'
@deleteverb.should == 'delete'
@deletebody.should == nil
end
end
end
context 'create a new role' do
it 'should pass in expected body' do
submittedXML=Nokogiri::XML readFile('create_role.xml')
params = {
:hosted_service_name=>'service001',
:role_name=>'vm01',
:host_name=>'myVm',
:ssh_user=>'jetstream',
:ssh_password=>'jetstream1!',
:media_location_prefix=>'auxpreview104',
:os_disk_name=>'disk004Test',
:source_image=>'SUSE__OpenSUSE64121-03192012-en-us-15GB',
:role_size=>'ExtraSmall',
:tcp_endpoints=>'44:45,55:55',
:udp_endpoints=>'65:65,75'
}
deploy = @connection.deploys.create(params)
#this is a cheesy workaround to make equivalent-xml happy
# write and then re-read the xml
File.open(tmpFile('newRoleRcvd.xml'), 'w') {|f| f.write(@receivedXML) }
File.open(tmpFile('newRoleSbmt.xml'), 'w') {|f| f.write(submittedXML.to_xml) }
rcvd = Nokogiri::XML File.open(tmpFile('newRoleRcvd.xml'))
sbmt = Nokogiri::XML File.open(tmpFile('newRoleSbmt.xml'))
rcvd.should be_equivalent_to(sbmt).respecting_element_order.with_whitespace_intact
end
end
context 'create a new deployment' do
it 'should pass in expected body' do
submittedXML=Nokogiri::XML readFile('create_deployment.xml')
params = {
:hosted_service_name=>'unknown_yet',
:role_name=>'vm01',
:host_name=>'myVm',
:ssh_user=>'jetstream',
:ssh_password=>'jetstream1!',
:media_location_prefix=>'auxpreview104',
:os_disk_name=>'disk004Test',
:source_image=>'SUSE__OpenSUSE64121-03192012-en-us-15GB',
:role_size=>'ExtraSmall'
}
deploy = @connection.deploys.create(params)
#this is a cheesy workaround to make equivalent-xml happy
# write and then re-read the xml
File.open(tmpFile('newDeployRcvd.xml'), 'w') {|f| f.write(@receivedXML) }
File.open(tmpFile('newDeploySbmt.xml'), 'w') {|f| f.write(submittedXML.to_xml) }
rcvd = Nokogiri::XML File.open(tmpFile('newDeployRcvd.xml'))
sbmt = Nokogiri::XML File.open(tmpFile('newDeploySbmt.xml'))
rcvd.should be_equivalent_to(sbmt).respecting_element_order
end
end
end

32
spec/unit/roles_list_spec.rb Executable file
Просмотреть файл

@ -0,0 +1,32 @@
require File.expand_path(File.dirname(__FILE__) + '/../spec_helper')
require File.expand_path(File.dirname(__FILE__) + '/query_azure_mock')
describe "roles" do
include AzureSpecHelper
include QueryAzureMock
before do
setup_query_azure_mock
end
it 'show all roles' do
roles = @connection.roles.all
roles.each do |role|
role.name.should_not be_nil
end
roles.length.should == 4
end
specify {@connection.roles.exists('vm01').should == true}
specify {@connection.roles.exists('vm002').should == true}
specify {@connection.roles.exists('role001').should == true}
specify {@connection.roles.exists('role002').should == true}
specify {@connection.roles.exists('role002qqqqq').should == false}
it 'each role should have values' do
role = @connection.roles.find('vm01')
role.name.should_not be_nil
role.status.should_not be_nil
role.size.should_not be_nil
role.ipaddress.should_not be_nil
role.sshport.should_not be_nil
role.sshipaddress.should_not be_nil
end
end