commit fa1eb2cf5873764ff01a5257470a898a3be10a44 Author: Jeff Mendoza Date: Thu Jan 30 12:06:08 2014 -0800 Initial commit. diff --git a/README.md b/README.md new file mode 100644 index 0000000..f64b03c --- /dev/null +++ b/README.md @@ -0,0 +1,220 @@ +Description +=========== + +This cookbook provides resources and providers to create an manage +Windows Azure components. Currently supported resources are: + +* Storage Accounts ('azure_storage_account') +* Blob Storage Containers ('azure_storage_container') +* SQL Azure Servers ('azure_sql_db_server') + +**Note** This cookbook uses the `azure` RubyGem to interact with the + Azure API. This gem requires `nokogiri` which requires compiling + native extensions, which means build tools are required. + +Requirements +============ + +Requires Chef 0.7.10 or higher for Lightweight Resource and Provider +support. Chef 0.8+ is recommended. While this cookbook can be used in +`chef-solo` mode, to gain the most flexibility, we recommend using +`chef-client` with a Chef Server. + +A Windows Azure account is required. The Management Certificate and +Subscriptoin ID are used to authenticate with Azure. + +Azure Credentials +=============== + +In order to manage Azure components, authentication credentials need +to be available to the node. There are a number of ways to handle +this, such as node attributes or roles. We recommend storing these in +a databag (Chef 0.8+), and loading them in the recipe where the +resources are needed. + +DataBag recommendation: + + % knife data bag show azure main + { + "id": "main", + "management_certificate": "YOUR PEM FILE CONTENTS", + "subscription_id": "YOUR SUBSCRIPTION ID" + } + +This can be loaded in a recipe with: + + azure = data_bag_item("azure", "main") + +And to access the values: + + azure['management_certificate'] + azure['subscription_id'] + +We'll look at specific usage below. + +Recipes +======= + +default.rb +---------- + +The default recipe installs the `azure` RubyGem, which this cookbook +requires in order to work with the Azure API. Make sure that the azure +recipe is in the node or role `run_list` before any resources from +this cookbook are used. + + "run_list": [ + "recipe[azure]" + ] + +The `gem_package` is created as a Ruby Object and thus installed +during the Compile Phase of the Chef run. + +Resources and Providers +======================= + +This cookbook provides three resources and corresponding providers. + +## storage_account.rb + + +Manage Azure Storage Accounts with this resource. + +Actions: + +* `create` - create a new storage account +* `delete` - delete the specified storage account + +Attribute Parameters: + +* `management_certificate` - PEM file contents of Azure management + certificate, required. +* `subscription_id` - ID of Azure subscription, required. +* `management_endpoint` - Endpoint for Azure API, defaults to + `management.core.windows.net`. +* `location` - Azure location to create storate account. Either + location or affinity group are required. +* `affinity_group_name` - Affinity group to create account in. Either + location or affinity group are required. +* `geo_replication_enabled` - True or false, defaults to true. + +## storage_container.rb + +Manage Azure Blob Containers with this resource + +Actions: + +* `create` - create a new container +* `delete` - delete the specified container + +Attribute Parameters: + +* `storage_account` - Account to create container in, required. +* `access_key` - Access key for storage account, required. + +## sql_db_server.rb + +Actions: + +* `create` - create a new server. Use the Azure location as the `name` + of the storage account. The server name is autogenerated. + +Attribute Parameters: + +* `management_certificate` - PEM file contents of Azure management + certificate, required. +* `subscription_id` - ID of Azure subscription, required. +* `management_endpoint` - Endpoint for Azure API, defaults to + `management.database.windows.net`. +* `login` - Desired admin login for db server, required. +* `password` - Desired admin password for db server, required. +* `server_name` - This attribute is set by the provider, and can be + used by consuming recipies. + +Usage +===== + +The following examples assume that the recommended data bag item has +been created and that the following has been included at the top of +the recipe where they are used. + + include_recipe "azure" + azure = data_bag_item("azure", "main") + +## azure_storage_accouint + +This will create an account named `new-account` in the `West US` +location. + + azure_storage_account 'new-account' do + management_certificate azure['management_certificate'] + subscription_id azure['subscription_id'] + location 'West US' + action :create + end + +This will create an account named `new-account` in the existing +`my-ag` affinity group. + + azure_storage_account 'new-account' do + management_certificate azure['management_certificate'] + subscription_id azure['subscription_id'] + affinity_group_name 'my-ag' + action :create + end + +## azure_storage_container + +This will create a container named `my-node` within the storage +account `my-account`. + + azure_storage_container 'my-node' do + storage_account 'my-account' + access_key azure['access_key'] + action :create + end + +## azure_sql_db_server + +This will create a db server in the location `West US` with the login +`admin` and password `password`. + + azure_sql_db_server 'West US' do + management_certificate azure['management_certificate'] + subscription_id azure['subscription_id'] + login 'admin' + password 'password' + action :create + end + +Here is an example of how you might retrieve the generated server +name. + + file '/etc/db_server_info' do + content lazy { + db2 = resources("azure_sql_db_server[West US]") + "Url: https://#{db2.server_name}.database.windows.net" + } + mode 0600 + action :create + end + + +License and Author +================== + +* Author:: Jeff Mendoza () + +Copyright (c) Microsoft Open Technologies, Inc. + +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. diff --git a/attributes/default.rb b/attributes/default.rb new file mode 100644 index 0000000..3d3a6e9 --- /dev/null +++ b/attributes/default.rb @@ -0,0 +1,17 @@ +# Author Jeff Mendoza (jemendoz@microsoft.com) +#------------------------------------------------------------------------- +# Copyright (c) Microsoft Open Technologies, Inc. +# +# 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. +#-------------------------------------------------------------------------- + +default['azure']['azure_gem_version'] = "0.6.0" diff --git a/libraries/azure.rb b/libraries/azure.rb new file mode 100644 index 0000000..575818d --- /dev/null +++ b/libraries/azure.rb @@ -0,0 +1,51 @@ +# Author Jeff Mendoza (jemendoz@microsoft.com) +#------------------------------------------------------------------------- +# Copyright (c) Microsoft Open Technologies, Inc. +# +# 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 Azure + module Cookbook + + def setup_management_service + begin + require 'azure' + rescue LoadError + Chef::Log.error("Missing gem 'azure'. Use the default azure recipe to install it first.") + end + mc = Tempfile.new(['mc', '.pem']) + mc.chmod(0600) + mc.write(new_resource.management_certificate) + mc.close + Azure.configure do |config| + config.management_certificate = mc.path + config.subscription_id = new_resource.subscription_id + config.management_endpoint = new_resource.management_endpoint + end + mc + end + + def setup_storage_service + begin + require 'azure' + rescue LoadError + Chef::Log.error("Missing gem 'azure'. Use the default azure recipe to install it first.") + end + Azure.configure do |config| + config.storage_account_name = new_resource.storage_account + config.storage_access_key = new_resource.access_key + end + end + + end +end diff --git a/metadata.rb b/metadata.rb new file mode 100644 index 0000000..252f26d --- /dev/null +++ b/metadata.rb @@ -0,0 +1,24 @@ +# Author Jeff Mendoza (jemendoz@microsoft.com) +#------------------------------------------------------------------------- +# Copyright (c) Microsoft Open Technologies, Inc. +# +# 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. +#-------------------------------------------------------------------------- + +name "azure" +maintainer "Microsoft Open Technologies, Inc." +maintainer_email "jemendoz@microsoft.com" +license "Apache 2.0" +description "LWRPs for managing Azure resources" +long_description IO.read(File.join(File.dirname(__FILE__), 'README.md')) +version "0.1.0" +recipe "azure", "Installs the azure gem during compile time" diff --git a/providers/sql_db_server.rb b/providers/sql_db_server.rb new file mode 100644 index 0000000..a841b2b --- /dev/null +++ b/providers/sql_db_server.rb @@ -0,0 +1,42 @@ +# Author Jeff Mendoza (jemendoz@microsoft.com) +#------------------------------------------------------------------------- +# Copyright (c) Microsoft Open Technologies, Inc. +# +# 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. +#-------------------------------------------------------------------------- + +include Azure::Cookbook + +action :create do + mc = setup_management_service + + sms = Azure::SqlDatabaseManagementService.new + + locs = [] + sms.list_servers.each { |srv| locs.push(srv.location) } + + if locs.include?(new_resource.location) + Chef::Log.debug("DB in #{new_resource.location} already exists.") + sms.list_servers.each do |srv| + if srv.location == new_resource.location + @new_resource.server_name(srv.name) + end + end + else + Chef::Log.debug("Creating DB in #{new_resource.location}.") + server = sms.create_server(new_resource.login, new_resource.password, new_resource.location) + @new_resource.server_name(server.name) + Chef::Log.debug("Created DB #{server.name}.") + sms.set_sql_server_firewall_rule(server.name, 'chef-node') + end + mc.unlink +end diff --git a/providers/storage_account.rb b/providers/storage_account.rb new file mode 100644 index 0000000..ff9b0c9 --- /dev/null +++ b/providers/storage_account.rb @@ -0,0 +1,56 @@ +# Author Jeff Mendoza (jemendoz@microsoft.com) +#------------------------------------------------------------------------- +# Copyright (c) Microsoft Open Technologies, Inc. +# +# 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. +#-------------------------------------------------------------------------- + +include Azure::Cookbook + +action :create do + mc = setup_management_service + + sms = Azure::StorageManagementService.new + + if sms.get_storage_account(new_resource.name) + Chef::Log.debug("Storage account #{new_resource.name} already exists.") + else + + if new_resource.location.nil? && new_resource.affinity_group_name.nil? + raise "Must provide either location or affinity group." + end + + #otherwise create + sa_opts = { :location => new_resource.location, + :affinity_group_name => new_resource.affinity_group_name, + :geo_replication_enabled => new_resource.geo_replication_enabled, }; + Chef::Log.debug("Creating storage account #{new_resource.name}.") + sms.create_storage_account(new_resource.name, sa_opts) + end + mc.unlink +end + +action :delete do + mc = setup_management_service + + sms = Azure::StorageManagementService.new + + unless sms.get_storage_account(new_resource.name) + Chef::Log.debug("Storage account #{new_resource.name} already deleted.") + else + + #otherwise delete + Chef::Log.debug("Deleting storage account #{new_resource.name}.") + sms.delete_storage_account(new_resource.name) + end + mc.unlink +end diff --git a/providers/storage_container.rb b/providers/storage_container.rb new file mode 100644 index 0000000..a9fbbc1 --- /dev/null +++ b/providers/storage_container.rb @@ -0,0 +1,51 @@ +# Author Jeff Mendoza (jemendoz@microsoft.com) +#------------------------------------------------------------------------- +# Copyright (c) Microsoft Open Technologies, Inc. +# +# 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. +#-------------------------------------------------------------------------- + +include Azure::Cookbook + +action :create do + setup_storage_service + + bms = Azure::BlobService.new + cont_names = [] + bms.list_containers.each do |cont| + cont_names.push(cont.name) + end + + if cont_names.include?(new_resource.name) + Chef::Log.debug("Blob container #{new_resource.name} already exists.") + else + Chef::Log.debug("Creating blob container #{new_resource.name}.") + bms.create_container(new_resource.name) + end +end + +action :delete do + setup_storage_service + + bms = Azure::BlobService.new + cont_names = [] + bms.list_containers.each do |cont| + cont_names.push(cont.name) + end + + if cont_names.include?(new_resource.name) + Chef::Log.debug("Deleting blob container #{new_resource.name}.") + bms.delete_container(new_resource.name) + else + Chef::Log.debug("Blob container #{new_resource.name} does not exist.") + end +end diff --git a/recipes/default.rb b/recipes/default.rb new file mode 100644 index 0000000..8a66c73 --- /dev/null +++ b/recipes/default.rb @@ -0,0 +1,22 @@ +# Author Jeff Mendoza (jemendoz@microsoft.com) +#------------------------------------------------------------------------- +# Copyright (c) Microsoft Open Technologies, Inc. +# +# 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. +#-------------------------------------------------------------------------- + +chef_gem 'azure' do + version node['azure']['azure_gem_version'] + action :install +end + +require 'azure' diff --git a/resources/sql_db_server.rb b/resources/sql_db_server.rb new file mode 100644 index 0000000..3227c5a --- /dev/null +++ b/resources/sql_db_server.rb @@ -0,0 +1,31 @@ +# Author Jeff Mendoza (jemendoz@microsoft.com) +#------------------------------------------------------------------------- +# Copyright (c) Microsoft Open Technologies, Inc. +# +# 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. +#-------------------------------------------------------------------------- + +actions :create + +attribute :management_certificate, :kind_of => String, :required => true +attribute :subscription_id, :kind_of => String, :required => true +attribute :management_endpoint, :kind_of => String, :default => 'https://management.database.windows.net:8443/' +attribute :location, :kind_of => String, :name_attribute => true +attribute :login, :kind_of => String, :required => true +attribute :password, :kind_of => String, :required => true + +attribute :server_name, :kind_of => String + +def initialize(*args) + super + @action = :create +end diff --git a/resources/storage_account.rb b/resources/storage_account.rb new file mode 100644 index 0000000..14cc137 --- /dev/null +++ b/resources/storage_account.rb @@ -0,0 +1,29 @@ +# Author Jeff Mendoza (jemendoz@microsoft.com) +#------------------------------------------------------------------------- +# Copyright (c) Microsoft Open Technologies, Inc. +# +# 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. +#-------------------------------------------------------------------------- + +actions :create, :delete + +attribute :management_certificate, :kind_of => String, :required => true +attribute :subscription_id, :kind_of => String, :required => true +attribute :management_endpoint, :kind_of => String, :default => 'management.core.windows.net' +attribute :location, :kind_of => String +attribute :affinity_group_name, :kind_of => String +attribute :geo_replication_enabled, :kind_of => [TrueClass, FalseClass], :default => true + +def initialize(*args) + super + @action = :create +end diff --git a/resources/storage_container.rb b/resources/storage_container.rb new file mode 100644 index 0000000..13fbfd9 --- /dev/null +++ b/resources/storage_container.rb @@ -0,0 +1,25 @@ +# Author Jeff Mendoza (jemendoz@microsoft.com) +#------------------------------------------------------------------------- +# Copyright (c) Microsoft Open Technologies, Inc. +# +# 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. +#-------------------------------------------------------------------------- + +actions :create, :delete + +attribute :storage_account, :kind_of => String, :required => true +attribute :access_key, :kind_of => String, :required => true + +def initialize(*args) + super + @action = :create +end