initial deliverable from the contractor.
This commit is contained in:
Коммит
3e5a887b07
Двоичный файл не отображается.
|
@ -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
|
||||
|
|
@ -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)
|
|
@ -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
|
|
@ -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.
|
|
@ -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
|
|
@ -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
|
Двоичный файл не отображается.
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
||||
|
Двоичный файл не отображается.
|
@ -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
|
|
@ -0,0 +1,7 @@
|
|||
module Knife
|
||||
module Azure
|
||||
VERSION = "0.5.11"
|
||||
MAJOR, MINOR, TINY = VERSION.split('.')
|
||||
end
|
||||
end
|
||||
|
|
@ -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 don’t support plugins:
|
||||
|
||||
gem install chef
|
||||
This plugin is distributed as a Ruby Gem. To install it, run:
|
||||
|
||||
gem install knife-azure
|
||||
Depending on your system’s 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.
|
|
@ -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
|
|
@ -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
|
||||
|
|
@ -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
|
|
@ -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>
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
||||
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
Загрузка…
Ссылка в новой задаче