Skip to content
This repository was archived by the owner on Jan 11, 2023. It is now read-only.
Merged
Show file tree
Hide file tree
Changes from 5 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
65 changes: 43 additions & 22 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,41 @@ Note: x64 Ruby for Windows is known to have some compatibility issues.

# Getting Started with Azure Resource Manager Usage (Preview)

## Prerequisite

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think would place this section after the "Install the rubygem packages" section, as that one provides context on authentication. Then we can talk about how to set this for usage in the packages.'


In order to use the Azure SDK, you must supply the following values to the Azure SDK:

* Tenant Id
* Client Id
* Subscription Id
* Client Secret

You could pass the above values in the following ways:

### Option 1 - Environment Variables
You can set the (above) values using the following environment variables:

* AZURE_TENANT_ID
* AZURE_CLIENT_ID
* AZURE_SUBSCRIPTION_ID
* AZURE_CLIENT_SECRET

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

can we put simple instructions on how to set them in mac and windows? (I think we had this before)

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done


### Option 2 - Options Hash
You can set the (above) values using the options hash:

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we need to give context on what the options hash is - for example "the options hash getting passed as parameter when constructing a client for the service/profile"

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done


```ruby
options = {
tenant_id: 'YOUR TENANT ID',
client_id: 'YOUR CLIENT ID',
client_secret: 'YOUR CLIENT SECRET',
subscription_id: 'YOUR SUBSCRIPTION ID'
}
```

### Option 3 - Combination of Environment Variables & Options Hash

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

what's the recommendation for the case in which the user wants to create credentials themselves? either from TokenProvider or MSITokenProvider? if they were to pass them in the hash, they would still need to pass in the 4 values specified above? so if credentials are passed, there are 5 values required for the hash?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done

You can set the (above) values using a combination of environment variables and options hash. The values mentioned in the options hash will take precedence over the environment variables.


## Install the rubygem packages

You can install the azure rubygem packages directly.
Expand Down Expand Up @@ -150,14 +185,10 @@ The following lines should be used to instantiate a profile client:

```ruby
# Provide credentials
provider = MsRestAzure::ApplicationTokenProvider.new(
ENV['AZURE_TENANT_ID'],
ENV['AZURE_CLIENT_ID'],
ENV['AZURE_CLIENT_SECRET'])
credentials = MsRest::TokenCredentials.new(provider)

options = {
credentials: credentials,
tenant_id: ENV['AZURE_TENANT_ID'],
client_id: ENV['AZURE_CLIENT_ID'],
client_secret: ENV['AZURE_CLIENT_SECRET'],
subscription_id: ENV['AZURE_SUBSCRIPTION_ID']
}

Expand Down Expand Up @@ -195,14 +226,10 @@ The following lines should be used to instantiate a profile client:

```ruby
# Provide credentials
provider = MsRestAzure::ApplicationTokenProvider.new(
ENV['AZURE_TENANT_ID'],
ENV['AZURE_CLIENT_ID'],
ENV['AZURE_CLIENT_SECRET'])
credentials = MsRest::TokenCredentials.new(provider)

options = {
credentials: credentials,
tenant_id: ENV['AZURE_TENANT_ID'],
client_id: ENV['AZURE_CLIENT_ID'],
client_secret: ENV['AZURE_CLIENT_SECRET'],
subscription_id: ENV['AZURE_SUBSCRIPTION_ID']
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

would our guidelines from before profile changes not work for initializing credentials, I believe we were doing:

 provider = MsRestAzure::ApplicationTokenProvider.new(
        ENV['AZURE_TENANT_ID'],
        ENV['AZURE_CLIENT_ID'],
        ENV['AZURE_CLIENT_SECRET'])
    credentials = MsRest::TokenCredentials.new(provider)
    @client = Azure::ARM::Resources::ResourceManagementClient.new(credentials)
    @client.subscription_id = @subscription_id

If so, should we leave them as they were, just updating the namespace for ResourceManagementClient? so we demonstrate the minimum change?

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

BTW, after this PR is done, we'd need to re-update the samples that were updated with the last release too.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The detailed explanation would be that we always want the user (of the SDK) to provide us with the tenant_id, client_id, client_secret and subscription_id. There is no escaping that. The credentials is just a derived value from these. The user may or may not provide it.

But, when you think about it, why would a user want to provide a derived value when he/she is supplying the original values anyway? That is the reason, I am updating the examples in readme and removed the credentials. But, if a user wants to provide it, then he is free to do that.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So... Credentials are not a bad thing to provide. This abstraction allows any token provider to be used.

Expand All @@ -226,8 +253,7 @@ purchase_plan_obj = Azure::Compute::Profiles::Latest::Mgmt::Models::PurchasePlan

## Usage of Individual gem using using specific api-version

In the previous section, we used the profile associated with individual gem. In the current section, we could use the
version directly.
In the previous section, we used the profile associated with individual gem. In the current section, we could use the version directly.

### Install

Expand All @@ -248,14 +274,9 @@ provider = MsRestAzure::ApplicationTokenProvider.new(
ENV['AZURE_CLIENT_SECRET'])
credentials = MsRest::TokenCredentials.new(provider)

options = {
credentials: credentials,
subscription_id: ENV['AZURE_SUBSCRIPTION_ID']
}

# Target client for 2016_03_30 version of Compute
compute_client = Azure::Compute::Mgmt::V2016_03_30::ComputeManagementClient.new(credentials)
compute_client.subscription_id = subscription_id
compute_client.subscription_id = ENV['AZURE_SUBSCRIPTION_ID']
```

The compute client could be used to access operations and models:
Expand Down
6 changes: 6 additions & 0 deletions Rakefile
Original file line number Diff line number Diff line change
Expand Up @@ -172,6 +172,9 @@ namespace :arm do
# bundle exec ruby profile_generator_client.rb --dir_metadata=dir_metadata.json --profile=profiles.json
command = "#{get_base_profile_generation_cmd}#{get_profile_spec_files_folder}/#{PROFILE_METADATA[:azure_sdk]}"
execute_and_stream(command)

FileUtils.cp("#{__dir__}/generators/profilegen/src/resources/common/configurable.rb", "#{__dir__}/azure_sdk/lib/common/configurable.rb")
FileUtils.cp("#{__dir__}/generators/profilegen/src/resources/common/default.rb", "#{__dir__}/azure_sdk/lib/common/default.rb")
end

desc 'Regen individual profiles'
Expand All @@ -183,6 +186,9 @@ namespace :arm do
# bundle exec ruby profile_generator_client.rb --dir_metadata=dir_metadata.json --profile=authorization_profiles.json
command = "#{get_base_profile_generation_cmd}#{get_profile_spec_files_folder}/#{profile_spec_file}"
execute_and_stream(command)

FileUtils.cp("#{__dir__}/generators/profilegen/src/resources/common/configurable.rb", "#{__dir__}/management/#{sdk}/lib/profiles/common/configurable.rb")
FileUtils.cp("#{__dir__}/generators/profilegen/src/resources/common/default.rb", "#{__dir__}/management/#{sdk}/lib/profiles/common/default.rb")
end
end
end
Expand Down
29 changes: 20 additions & 9 deletions azure_sdk/lib/common/configurable.rb
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,8 @@
# Copyright (c) Microsoft Corporation. All rights reserved.
# Licensed under the MIT License. See License.txt in the project root for license information.

module Azure::ARM
# The Azure::ARM::Configurable module provides basic configuration for Azure ARM activities.
module Azure::Common
# The Azure::Common::Configurable module provides basic configuration for Azure activities.
module Configurable
# @return [String] Azure tenant id (also known as domain).
attr_accessor :tenant_id
Expand All @@ -25,11 +25,11 @@ module Configurable

class << self
#
# List of configurable keys for {Azure::ARM::Client}.
# List of configurable keys for {Azure::Common::Client}.
# @return [Array] of option keys.
#
def keys
@keys ||= [:tenant_id, :client_id, :client_secret, :subscription_id, :active_directory_settings, :credentials]
@keys ||= [:tenant_id, :client_id, :client_secret, :subscription_id, :active_directory_settings]
end
end

Expand All @@ -45,11 +45,14 @@ def configure
# This will also creates MsRest::TokenCredentials to be used for subsequent Azure Resource Manager clients.
#
def reset!(options = {})
Azure::ARM::Configurable.keys.each do |key|
default_value = Azure::ARM::Default.options[key]
Azure::Common::Configurable.keys.each do |key|
default_value = Azure::Common::Default.options[key]
instance_variable_set(:"@#{key}", options.fetch(key, default_value))
end

default_value = get_credentials(self.tenant_id, self.client_id, self.client_secret, self.active_directory_settings)
instance_variable_set(:"@credentials", options.fetch(:credentials, default_value))

self
end

Expand All @@ -62,12 +65,20 @@ def config
#
# configures configurable options to default values
#
def setup_options
def setup_default_options
opts = {}
Azure::ARM::Configurable.keys.map do |key|
opts[key] = Azure::ARM::Default.options[key]
Azure::Common::Configurable.keys.map do |key|
opts[key] = Azure::Common::Default.options[key]
end
opts[:credentials] = get_credentials(opts[:tenant_id], opts[:client_id], opts[:client_secret], opts[:active_directory_settings])
opts
end

def get_credentials(tenant_id, client_id, client_secret, active_directory_settings)
MsRest::TokenCredentials.new(
MsRestAzure::ApplicationTokenProvider.new(
tenant_id, client_id, client_secret, active_directory_settings))
end

end
end
15 changes: 2 additions & 13 deletions azure_sdk/lib/common/default.rb
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,7 @@
# Copyright (c) Microsoft Corporation. All rights reserved.
# Licensed under the MIT License. See License.txt in the project root for license information.

module Azure::ARM
# Default configuration options for {Azure::ARM.Client}
module Azure::Common
module Default
class << self
#
Expand Down Expand Up @@ -38,16 +37,6 @@ def subscription_id
ENV['AZURE_SUBSCRIPTION_ID']
end

#
# Default Azure credentials to authorize HTTP requests made by the service client.
# @return [MsRest::ServiceClientCredentials] Azure credentials to authorize HTTP requests made by the service client.
#
def credentials
MsRest::TokenCredentials.new(
MsRestAzure::ApplicationTokenProvider.new(
self.tenant_id, self.client_id, self.client_secret, self.active_directory_settings))
end

#
# Default Azure Active Directory Service Settings.
# @return [MsRestAzure::ActiveDirectoryServiceSettings] Azure Active Directory Service Settings.
Expand All @@ -61,7 +50,7 @@ def active_directory_settings
# @return [Hash] Configuration options.
#
def options
Hash[Azure::ARM::Configurable.keys.map{|key| [key, send(key)]}]
Hash[Azure::Common::Configurable.keys.map { |key| [key, send(key)]}]
end
end
end
Expand Down
6 changes: 3 additions & 3 deletions azure_sdk/lib/latest/latest_profile_client.rb
Original file line number Diff line number Diff line change
Expand Up @@ -68,13 +68,13 @@ module Azure::Profiles::Latest::Mgmt
# Client class for the Latest profile SDK.
#
class Client
include Azure::ARM::Configurable
include Azure::Common::Configurable

attr_reader :analysis_services, :authorization, :automation, :batch, :billing, :cdn, :cognitive_services, :commerce, :compute, :consumption, :container_instance, :container_registry, :container_service, :customer_insights, :data_lake_analytics, :data_lake_store, :dev_test_labs, :dns, :event_grid, :event_hub, :features, :graph, :iot_hub, :key_vault, :links, :locks, :logic, :machine_learning, :managed_applications, :marketplace_ordering, :media_services, :mobile_engagement, :monitor, :network, :notification_hubs, :operational_insights, :policy, :power_bi_embedded, :recovery_services, :recovery_services_backup, :recovery_services_site_recovery, :redis, :relay, :resources, :resources_management, :scheduler, :search, :server_management, :service_bus, :service_fabric, :sql, :stor_simple8000_series, :storage, :stream_analytics, :subscriptions, :traffic_manager, :web

def initialize(options = {})
if options.is_a?(Hash) && options.length == 0
@options = setup_options
@options = setup_default_options
else
@options = options
end
Expand Down Expand Up @@ -142,7 +142,7 @@ def initialize(options = {})

def credentials
if @credentials.nil?
self.active_directory_settings ||= Azure::ARM::Default.active_directory_settings
self.active_directory_settings ||= Azure::Common::Default.active_directory_settings

@credentials = MsRest::TokenCredentials.new(
MsRestAzure::ApplicationTokenProvider.new(
Expand Down
6 changes: 3 additions & 3 deletions azure_sdk/lib/v2017_03_09/v2017_03_09_profile_client.rb
Original file line number Diff line number Diff line change
Expand Up @@ -20,13 +20,13 @@ module Azure::Profiles::V2017_03_09::Mgmt
# Client class for the V2017_03_09 profile SDK.
#
class Client
include Azure::ARM::Configurable
include Azure::Common::Configurable

attr_reader :storage, :network, :compute, :features, :links, :locks, :policy, :resources, :subscriptions

def initialize(options = {})
if options.is_a?(Hash) && options.length == 0
@options = setup_options
@options = setup_default_options
else
@options = options
end
Expand All @@ -46,7 +46,7 @@ def initialize(options = {})

def credentials
if @credentials.nil?
self.active_directory_settings ||= Azure::ARM::Default.active_directory_settings
self.active_directory_settings ||= Azure::Common::Default.active_directory_settings

@credentials = MsRest::TokenCredentials.new(
MsRestAzure::ApplicationTokenProvider.new(
Expand Down
86 changes: 86 additions & 0 deletions generators/profilegen/src/resources/common/configurable.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
# encoding: utf-8
# Copyright (c) Microsoft Corporation. All rights reserved.
# Licensed under the MIT License. See License.txt in the project root for license information.

module Azure::Common
# The Azure::Common::Configurable module provides basic configuration for Azure activities.
module Configurable
# @return [String] Azure tenant id (also known as domain).
attr_accessor :tenant_id

# @return [String] Azure client id.
attr_accessor :client_id

# @return [String] Azure secret key.
attr_accessor :client_secret

# @return [String] Azure subscription id.
attr_accessor :subscription_id

# @return [MsRestAzure::ActiveDirectoryServiceSettings] Azure active directory service settings.
attr_accessor :active_directory_settings

# @return [MsRest::ServiceClientCredentials] credentials to authorize HTTP requests made by the service client.
attr_accessor :credentials

class << self
#
# List of configurable keys for {Azure::Common::Client}.
# @return [Array] of option keys.
#
def keys
@keys ||= [:tenant_id, :client_id, :client_secret, :subscription_id, :active_directory_settings]
end
end

#
# Set configuration options using a block.
#
def configure
yield self
end

#
# Resets the configurable options to provided options or defaults.
# This will also creates MsRest::TokenCredentials to be used for subsequent Azure Resource Manager clients.
#
def reset!(options = {})
Azure::Common::Configurable.keys.each do |key|
default_value = Azure::Common::Default.options[key]
instance_variable_set(:"@#{key}", options.fetch(key, default_value))
end

fail ArgumentError, 'tenant_id is nil' if self.tenant_id.nil?

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

can we give an indication on how to fix it? set the env vars or pass it in options?

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

also maybe match the message from

fail ArgumentError, 'Tenant id cannot be nil' if tenant_id.nil?

fail ArgumentError, 'client_id is nil' if self.client_id.nil?
fail ArgumentError, 'client_secret is nil' if self.client_secret.nil?
fail ArgumentError, 'subscription_id is nil' if self.subscription_id.nil?
fail ArgumentError, 'active_directory_settings is nil' if self.active_directory_settings.nil?

@veronicagg veronicagg Oct 26, 2017

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

could this be nil at this point? this is not something we're asking the user to pass in, right?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Technically, yes. They will not be nil. I just wanted to be cautious that one of our users intentionally passing nil value for active_directory_settings in the options hash.


default_value = MsRest::TokenCredentials.new(
MsRestAzure::ApplicationTokenProvider.new(
self.tenant_id, self.client_id, self.client_secret, self.active_directory_settings))

instance_variable_set(:"@credentials", options.fetch(:credentials, default_value))

self
end

def config
self
end

private

#
# configures configurable options to default values
#
def setup_default_options
opts = {}
Azure::Common::Configurable.keys.map do |key|
opts[key] = Azure::Common::Default.options[key]
end

opts
end
end
end
Loading