Azure / azure-sdk-for-ruby

Ruby SDK for Azure Resource Manager: build and manage your Azure cloud infrastructure (Compute, Virtual Networks, Storage, etc...) using Ruby.
MIT License
275 stars 246 forks source link

Unable to set content of TxtRecord #2775

Closed nickthecook closed 1 year ago

nickthecook commented 4 years ago

Hi,

I'm using the Ruby SDK for Azure, and I'm trying to create a TXT record in an existing DNS Zone, with specific content.

My code will create a TXT record, but the "value" field is empty:

image

Here is the code I'm using to create the TxtRecord object:

# frozen_string_literal: true

require "azure_mgmt_resources"
require 'azure_mgmt_dns'

class TxtRecord
  def put
    # https://github.com/Azure/azure-sdk-for-ruby/blob/master/management/azure_mgmt_resources/lib/2019-07-01/generated/azure_mgmt_resources/resources.rb#L602
    client.resources.create_or_update(
      "dns-dev-nick",
      'Microsoft.Network',
      "dnszones/example.com",
      'TXT',
      "_acme_challenge",
      '2017-10-01',
      parameters
    ).properties
  end

  private

  def parameters
    ::Azure::Dns::Mgmt::V2017_10_01::Models::RecordSetUpdateParameters.new.tap do |parameters|
      parameters.record_set = record_set
    end
  end

  def record_set
    ::Azure::Dns::Mgmt::V2017_10_01::Models::RecordSet.new.tap do |record_set|
      record_set.txt_records = [record]
    end
  end

  def record
    ::Azure::Dns::Mgmt::V2017_10_01::Models::TxtRecord.new.tap do |txt_record|
      txt_record.value = ["record content here"]
    end
  end

  def client
    @client ||= ::Azure::Resources::Profiles::Latest::Mgmt::Client.new(options)
  end

  def options
    {
      credentials: credentials,
      subscription_id: subscription_id
    }
  end

  def credentials
    MsRest::TokenCredentials.new(provider)
  end

  def provider
    MsRestAzure::ApplicationTokenProvider.new(
      ENV['AZURE_TENANT_ID'],
      ENV['AZURE_CLIENT_ID'],
      ENV['AZURE_CLIENT_SECRET']
    )
  end

  def subscription_id
    ENV['AZURE_SUBSCRIPTION_ID']
  end
end

TxtRecord.new.put

I adapted code from this example, but made some changes to the packages I'm using because I couldn't load Azure::ARM from any of the gems I tried.

Can you tell me how to create a TXT record with specific content? Any help would be appreciated.

nickthecook commented 4 years ago

Also, I have tried with a String as the value, but it looks from this code like it's looking for an array of String:

https://github.com/Azure/azure-sdk-for-ruby/blob/master/management/azure_mgmt_dns/lib/2017-10-01/generated/azure_mgmt_dns/models/txt_record.rb

nickthecook commented 4 years ago

I still haven't found a solution for this.

Can anyone provide some insight as to why the code above produces a TXT record with an empty value?

mmyyrroonn commented 4 years ago

@nickthecook Hi. Based on my knowledge, the model you build is used for this client within dns module instead of the resource module. The model they need are different. Please use this client instead.

https://github.com/Azure/azure-sdk-for-ruby/blob/6e278aa6155adb615a3e17ef84e4e773c3c16ac5/management/azure_mgmt_dns/lib/2017-10-01/generated/azure_mgmt_dns/record_sets.rb#L192

nickthecook commented 4 years ago

@MyronFanQiu Thanks for the tip.

I've updated to use that class, but I still get a blank TXT record, same as in the screenshot in the issue description. Code follows.

I get this response:

#<Azure::Dns::Mgmt::V2017_10_01::Models::RecordSet:0x00007fc16a0e69c8
  @txt_records=[],
  @id="/subscriptions/f92fa2f4-15bf-4ee8-b107-cb57ddf08fd9/resourceGroups/dns-dev-nick/providers/Microsoft.Network/dnszones/example.com/TXT/_acme_challenge",
  @name="_acme_challenge",
  @type="Microsoft.Network/dnszones/TXT",
  @etag="f1867752-beec-41be-b39c-ed1b4761f168", @ttl=0,
  @fqdn="_acme_challenge.example.com."
>

It's challenging trying to use the code to work backwards, because of the auto-generated ReST API wrappers. Any idea what I need to pass as parameters to the create_or_update call to get @txt_records to have some content?


# frozen_string_literal: true

require "azure_mgmt_resources"
require 'azure_mgmt_dns'

class TxtRecord
  def put
    # https://github.com/Azure/azure-sdk-for-ruby/blob/master/management/azure_mgmt_resources/lib/2019-07-01/generated/azure_mgmt_resources/resources.rb#L602
    puts record_set_client.create_or_update(
      "dns-dev-nick",
      "example.com",
      "_acme_challenge",
      'TXT',
      parameters
    ).inspect
  end

  private

  def parameters
    ::Azure::Dns::Mgmt::V2017_10_01::Models::RecordSetUpdateParameters.new.tap do |parameters|
      parameters.record_set = record_set
    end
  end

  def record_set
    ::Azure::Dns::Mgmt::V2017_10_01::Models::RecordSet.new.tap do |record_set|
      record_set.txt_records = [record]
    end
  end

  def record
    ::Azure::Dns::Mgmt::V2017_10_01::Models::TxtRecord.new.tap do |txt_record|
      txt_record.value = ["record content here"]
    end
  end

  def record_set_client
    @record_set_client ||= Azure::Dns::Mgmt::V2017_10_01::RecordSets.new(client)
  end

  def client
    @client ||= begin
      new_client = ::Azure::Dns::Mgmt::V2017_10_01::DnsManagementClient.new(credentials, nil, nil)
      new_client.subscription_id = subscription_id

      new_client
    end
  end

  def credentials
    MsRest::TokenCredentials.new(provider)
  end

  def provider
    MsRestAzure::ApplicationTokenProvider.new(
      ENV['AZURE_TENANT_ID'],
      ENV['AZURE_CLIENT_ID'],
      ENV['AZURE_CLIENT_SECRET']
    )
  end

  def subscription_id
    ENV['AZURE_SUBSCRIPTION_ID']
  end
end

TxtRecord.new.put
mmyyrroonn commented 4 years ago

This should be redundant. You can check the source code to see which type are needed.

  def parameters
    ::Azure::Dns::Mgmt::V2017_10_01::Models::RecordSetUpdateParameters.new.tap do |parameters|
      parameters.record_set = record_set
    end
  end
nickthecook commented 4 years ago

It seems to needs a RecordSet. What did you think was redundant about this, specifically?

mmyyrroonn commented 4 years ago

https://github.com/Azure/azure-sdk-for-ruby/blob/6e278aa6155adb615a3e17ef84e4e773c3c16ac5/management/azure_mgmt_dns/lib/2017-10-01/generated/azure_mgmt_dns/record_sets.rb#L210

They type of parameter should be RecordSet directly instead of RecordSetUpdateParameters.

nickthecook commented 4 years ago

Unfortunately, if I pass a RecordSet directly, and not as part of a RecordSetUpdateParameters, I get an (MsRestAzure::AzureOperationError):

{
  "message": "MsRestAzure::AzureOperationError",
  "request": {
    "base_uri": "https://management.azure.com",
    "path_template": "subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/Microsoft.Network/dnsZones/{zoneName}/{recordType}/{relativeRecordSetName}",
    "method": "put",
    "path_params": {
      "resourceGroupName": "dns-dev-nick",
      "zoneName": "example.com",
      "recordType": "TXT",
      "subscriptionId": "f92fa2f4-15bf-4ee8-b107-cb57ddf08fd9"
    },
    "skip_encoding_path_params": {
      "relativeRecordSetName": "_acme_challenge"
    },
    "query_params": {
      "api-version": "2017-10-01"
    },
    "skip_encoding_query_params": null,
    "headers": {
      "Content-Type": "application/json; charset=utf-8",
      "Accept": "application/json",
      "accept-language": "en-US",
      "x-ms-client-request-id": "c0150381-e345-499a-acfb-1e9cc32b6c5e"
    },
    "body": "{\"properties\":{\"TXTRecords\":[{\"value\":[\"record content here\"]}]}}",
    "middlewares": [
      [
        "MsRest::RetryPolicyMiddleware",
        {
          "times": 3,
          "retry": 0.02
        }
      ],
      [
        "cookie_jar"
      ]
    ],
    "log": null
  },
  "response": {
    "body": "{\"code\":\"BadRequest\",\"message\":\"The request was invalid.\"}",
    "headers": {
      "cache-control": "private",
      "content-length": "58",
      "content-type": "application/json; charset=utf-8",
      "x-content-type-options": "nosniff",
      "strict-transport-security": "max-age=31536000; includeSubDomains",
      "x-ms-request-id": "c0150381-e345-499a-acfb-1e9cc32b6c5e",
      "server": "Microsoft-IIS/10.0",
      "x-powered-by": "ASP.NET",
      "x-ms-ratelimit-remaining-subscription-resource-requests": "11999",
      "x-ms-correlation-request-id": "edec4395-2e95-413d-9fec-7be2740aae8d",
      "x-ms-routing-request-id": "CANADACENTRAL:20200519T194426Z:edec4395-2e95-413d-9fec-7be2740aae8d",
      "date": "Tue, 19 May 2020 19:44:25 GMT"
    },
    "status": 400
  }
}
nickthecook commented 4 years ago

I can pass the TxtRecord object directly in the create_or_update method call, but the TXT record body is still empty when the record is created in Azure; same as when I pass the RecordSetUpdateParameters.

mmyyrroonn commented 4 years ago

Unfortunately, if I pass a RecordSet directly, and not as part of a RecordSetUpdateParameters, I get an (MsRestAzure::AzureOperationError):

{
  "message": "MsRestAzure::AzureOperationError",
  "request": {
    "base_uri": "https://management.azure.com",
    "path_template": "subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/Microsoft.Network/dnsZones/{zoneName}/{recordType}/{relativeRecordSetName}",
    "method": "put",
    "path_params": {
      "resourceGroupName": "dns-dev-nick",
      "zoneName": "example.com",
      "recordType": "TXT",
      "subscriptionId": "f92fa2f4-15bf-4ee8-b107-cb57ddf08fd9"
    },
    "skip_encoding_path_params": {
      "relativeRecordSetName": "_acme_challenge"
    },
    "query_params": {
      "api-version": "2017-10-01"
    },
    "skip_encoding_query_params": null,
    "headers": {
      "Content-Type": "application/json; charset=utf-8",
      "Accept": "application/json",
      "accept-language": "en-US",
      "x-ms-client-request-id": "c0150381-e345-499a-acfb-1e9cc32b6c5e"
    },
    "body": "{\"properties\":{\"TXTRecords\":[{\"value\":[\"record content here\"]}]}}",
    "middlewares": [
      [
        "MsRest::RetryPolicyMiddleware",
        {
          "times": 3,
          "retry": 0.02
        }
      ],
      [
        "cookie_jar"
      ]
    ],
    "log": null
  },
  "response": {
    "body": "{\"code\":\"BadRequest\",\"message\":\"The request was invalid.\"}",
    "headers": {
      "cache-control": "private",
      "content-length": "58",
      "content-type": "application/json; charset=utf-8",
      "x-content-type-options": "nosniff",
      "strict-transport-security": "max-age=31536000; includeSubDomains",
      "x-ms-request-id": "c0150381-e345-499a-acfb-1e9cc32b6c5e",
      "server": "Microsoft-IIS/10.0",
      "x-powered-by": "ASP.NET",
      "x-ms-ratelimit-remaining-subscription-resource-requests": "11999",
      "x-ms-correlation-request-id": "edec4395-2e95-413d-9fec-7be2740aae8d",
      "x-ms-routing-request-id": "CANADACENTRAL:20200519T194426Z:edec4395-2e95-413d-9fec-7be2740aae8d",
      "date": "Tue, 19 May 2020 19:44:25 GMT"
    },
    "status": 400
  }
}

This should be correct. Based on the example provided by service team, please try to provide ttl as well. If you still cannot see the value, I would add service attention to invite correct person to help you.

kurtzeborn commented 1 year ago

Thank you for your interest in Azure SDKs. As detailed in this retirement announcement, this repo is no longer supported as of December 31st 2021. Please find the up-to-date list of languages and services supported with Azure SDKs here: https://aka.ms/azsdk