CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/pypi-azure-mgmt-dns

Microsoft Azure DNS Management Client Library for Python

Pending

Quality

Pending

Does it follow best practices?

Impact

Pending

No eval scenarios have been run

Overview
Eval results
Files

dns-record-sets.mddocs/

DNS Record Set Management

Complete CRUD operations for DNS record sets supporting all major DNS record types (A, AAAA, CAA, CNAME, MX, NS, PTR, SOA, SRV, TXT) with conditional updates and batch operations. Record sets group multiple DNS records of the same type and name within a DNS zone.

Record Set Operations

Create or Update Record Set

Creates a new DNS record set or updates an existing one with the specified records.

def create_or_update(
    self,
    resource_group_name: str,
    zone_name: str,
    relative_record_set_name: str,
    record_type: Union[str, RecordType],
    parameters: Union[RecordSet, IO[bytes]],
    if_match: Optional[str] = None,
    if_none_match: Optional[str] = None,
    **kwargs: Any
) -> RecordSet:
    """
    Create or update a DNS record set.
    
    Args:
        resource_group_name: Name of the resource group containing the zone
        zone_name: Name of the DNS zone
        relative_record_set_name: Name relative to zone (use "@" for apex records)
        record_type: Type of DNS record (A, AAAA, CNAME, etc.)
        parameters: Record set configuration with DNS records
        if_match: ETag value for conditional updates
        if_none_match: Set to "*" to prevent overwriting
        
    Returns:
        RecordSet: The created or updated record set
        
    Raises:
        HttpResponseError: If the operation fails
    """

Usage Examples:

from azure.mgmt.dns.models import RecordSet, ARecord, CnameRecord, MxRecord, RecordType

# Create an A record set with multiple IP addresses
a_record_set = RecordSet(
    ttl=300,
    a_records=[
        ARecord(ipv4_address="192.0.2.1"),
        ARecord(ipv4_address="192.0.2.2")
    ]
)

result = dns_client.record_sets.create_or_update(
    resource_group_name="my-rg",
    zone_name="example.com",
    relative_record_set_name="www",
    record_type=RecordType.A,
    parameters=a_record_set
)

# Create a CNAME record
cname_record_set = RecordSet(
    ttl=3600,
    cname_record=CnameRecord(cname="www.example.com")
)

dns_client.record_sets.create_or_update(
    resource_group_name="my-rg",
    zone_name="example.com",
    relative_record_set_name="blog",
    record_type=RecordType.CNAME,
    parameters=cname_record_set
)

# Create MX records for email
mx_record_set = RecordSet(
    ttl=3600,
    mx_records=[
        MxRecord(preference=10, exchange="mail1.example.com"),
        MxRecord(preference=20, exchange="mail2.example.com")
    ]
)

dns_client.record_sets.create_or_update(
    resource_group_name="my-rg",
    zone_name="example.com",
    relative_record_set_name="@",  # Apex record
    record_type=RecordType.MX,
    parameters=mx_record_set
)

Update Record Set

Updates specific properties of an existing record set without replacing the entire record set.

def update(
    self,
    resource_group_name: str,
    zone_name: str,
    relative_record_set_name: str,
    record_type: Union[str, RecordType],
    parameters: Union[RecordSet, IO[bytes]],
    if_match: Optional[str] = None,
    **kwargs: Any
) -> RecordSet:
    """
    Update properties of an existing DNS record set.
    
    Args:
        resource_group_name: Name of the resource group containing the zone
        zone_name: Name of the DNS zone
        relative_record_set_name: Name of the record set
        record_type: Type of DNS record
        parameters: Record set with updated properties
        if_match: ETag value for conditional updates
        
    Returns:
        RecordSet: The updated record set
        
    Raises:
        HttpResponseError: If the record set is not found
    """

Delete Record Set

Permanently deletes a DNS record set and all its records.

def delete(
    self,
    resource_group_name: str,
    zone_name: str,
    relative_record_set_name: str,
    record_type: Union[str, RecordType],
    if_match: Optional[str] = None,
    **kwargs: Any
) -> None:
    """
    Delete a DNS record set.
    
    Args:
        resource_group_name: Name of the resource group containing the zone
        zone_name: Name of the DNS zone
        relative_record_set_name: Name of the record set
        record_type: Type of DNS record
        if_match: ETag value for conditional deletion
        
    Raises:
        HttpResponseError: If the record set is not found
    """

Usage Example:

# Delete a specific record set
dns_client.record_sets.delete(
    resource_group_name="my-rg",
    zone_name="example.com",
    relative_record_set_name="old-service",
    record_type=RecordType.A
)

Get Record Set

Retrieves a specific DNS record set and its records.

def get(
    self,
    resource_group_name: str,
    zone_name: str,
    relative_record_set_name: str,
    record_type: Union[str, RecordType],
    **kwargs: Any
) -> RecordSet:
    """
    Get a specific DNS record set.
    
    Args:
        resource_group_name: Name of the resource group containing the zone
        zone_name: Name of the DNS zone
        relative_record_set_name: Name of the record set
        record_type: Type of DNS record
        
    Returns:
        RecordSet: The DNS record set with all its records
        
    Raises:
        HttpResponseError: If the record set is not found
    """

List Record Sets

Lists DNS record sets within a zone, with options to filter by type.

def list_by_dns_zone(
    self,
    resource_group_name: str,
    zone_name: str,
    top: Optional[int] = None,
    recordsetnamesuffix: Optional[str] = None,
    **kwargs: Any
) -> ItemPaged[RecordSet]:
    """
    List all record sets in a DNS zone.
    
    Args:
        resource_group_name: Name of the resource group containing the zone
        zone_name: Name of the DNS zone
        top: Maximum number of record sets to return
        recordsetnamesuffix: Filter by record set name suffix
        
    Returns:
        ItemPaged[RecordSet]: Paginated list of record sets
    """

def list_by_type(
    self,
    resource_group_name: str,
    zone_name: str,
    record_type: Union[str, RecordType],
    top: Optional[int] = None,
    recordsetnamesuffix: Optional[str] = None,
    **kwargs: Any
) -> ItemPaged[RecordSet]:
    """
    List record sets of a specific type in a DNS zone.
    
    Args:
        resource_group_name: Name of the resource group containing the zone
        zone_name: Name of the DNS zone
        record_type: Type of DNS record to filter by
        top: Maximum number of record sets to return
        recordsetnamesuffix: Filter by record set name suffix
        
    Returns:
        ItemPaged[RecordSet]: Paginated list of record sets
    """

def list_all_by_dns_zone(
    self,
    resource_group_name: str,
    zone_name: str,
    top: Optional[int] = None,
    record_set_name_suffix: Optional[str] = None,
    **kwargs: Any
) -> ItemPaged[RecordSet]:
    """
    Alternative endpoint for listing all record sets in a zone.
    
    Args:
        resource_group_name: Name of the resource group containing the zone
        zone_name: Name of the DNS zone
        top: Maximum number of record sets to return
        record_set_name_suffix: Filter by record set name suffix
        
    Returns:
        ItemPaged[RecordSet]: Paginated list of record sets
    """

Usage Examples:

# List all record sets in a zone
all_records = dns_client.record_sets.list_by_dns_zone(
    resource_group_name="my-rg",
    zone_name="example.com"
)
for record_set in all_records:
    print(f"{record_set.name} ({record_set.type}) - TTL: {record_set.ttl}")

# List only A records
a_records = dns_client.record_sets.list_by_type(
    resource_group_name="my-rg",
    zone_name="example.com",
    record_type=RecordType.A
)
for record_set in a_records:
    print(f"A record: {record_set.name} -> {[r.ipv4_address for r in record_set.a_records]}")

# List records with name suffix filtering
web_records = dns_client.record_sets.list_by_dns_zone(
    resource_group_name="my-rg",
    zone_name="example.com",
    recordsetnamesuffix="web"  # Matches "web", "web1", "webapp", etc.
)

DNS Record Types

A Records (IPv4 Addresses)

class ARecord:
    """IPv4 address record."""
    ipv4_address: str  # IPv4 address (e.g., "192.0.2.1")

Usage:

from azure.mgmt.dns.models import RecordSet, ARecord

record_set = RecordSet(
    ttl=300,
    a_records=[
        ARecord(ipv4_address="192.0.2.1"),
        ARecord(ipv4_address="192.0.2.2")
    ]
)

AAAA Records (IPv6 Addresses)

class AaaaRecord:
    """IPv6 address record."""
    ipv6_address: str  # IPv6 address (e.g., "2001:db8::1")

CNAME Records (Canonical Names)

class CnameRecord:
    """Canonical name record (alias)."""
    cname: str  # Target domain name

Usage:

from azure.mgmt.dns.models import RecordSet, CnameRecord

cname_record_set = RecordSet(
    ttl=3600,
    cname_record=CnameRecord(cname="target.example.com")
)

MX Records (Mail Exchange)

class MxRecord:
    """Mail exchange record for email routing."""
    preference: int  # Priority (lower numbers have higher priority)
    exchange: str    # Mail server hostname

NS Records (Name Servers)

class NsRecord:
    """Name server record."""
    nsdname: str  # Name server domain name

TXT Records (Text Data)

class TxtRecord:
    """Text record for arbitrary text data."""
    value: List[str]  # List of text strings (each ≤255 characters)

Usage:

from azure.mgmt.dns.models import RecordSet, TxtRecord

txt_record_set = RecordSet(
    ttl=300,
    txt_records=[
        TxtRecord(value=["v=spf1 include:_spf.google.com ~all"]),
        TxtRecord(value=["google-site-verification=abc123..."])
    ]
)

SRV Records (Service Discovery)

class SrvRecord:
    """Service record for service discovery."""
    priority: int  # Priority (lower is higher priority)
    weight: int    # Weight for load balancing among same priority
    port: int      # Service port number
    target: str    # Target hostname

PTR Records (Reverse DNS)

class PtrRecord:
    """Pointer record for reverse DNS lookups."""
    ptrdname: str  # Target domain name

SOA Records (Start of Authority)

class SoaRecord:
    """Start of Authority record (zone metadata)."""
    host: str           # Primary name server
    email: str          # Administrator email (dots replaced with @)
    serial_number: int  # Zone serial number
    refresh_time: int   # Refresh interval (seconds)
    retry_time: int     # Retry interval (seconds)
    expire_time: int    # Expiration time (seconds)
    minimum_ttl: int    # Minimum TTL for negative caching

CAA Records (Certificate Authority Authorization)

class CaaRecord:
    """Certificate Authority Authorization record."""
    flags: int  # Flags (typically 0 or 128 for critical)
    tag: str    # Property tag ("issue", "issuewild", "iodef")
    value: str  # Property value (CA domain or URL)

Usage:

from azure.mgmt.dns.models import RecordSet, CaaRecord

caa_record_set = RecordSet(
    ttl=3600,
    caa_records=[
        CaaRecord(flags=0, tag="issue", value="letsencrypt.org"),
        CaaRecord(flags=0, tag="issue", value="digicert.com"),
        CaaRecord(flags=128, tag="iodef", value="mailto:security@example.com")
    ]
)

Record Set Data Model

RecordSet Class

class RecordSet:
    """
    Represents a DNS record set within a zone.
    
    A record set groups multiple DNS records of the same type and name.
    """
    
    # Read-only properties
    id: str                       # Azure resource ID
    name: str                     # Record set name relative to zone
    type: str                     # Record set type (e.g., "Microsoft.Network/dnszones/A")
    etag: str                     # ETag for concurrency control
    fqdn: str                     # Fully qualified domain name (read-only)
    
    # Configurable properties
    ttl: int                      # Time-to-live in seconds (1-2147483647)
    metadata: Dict[str, str]      # Custom metadata key-value pairs
    target_resource: SubResource  # Reference to Azure resource (for alias records)
    
    # Record type specific arrays (only one should be populated)
    a_records: List[ARecord]                    # IPv4 address records
    aaaa_records: List[AaaaRecord]              # IPv6 address records
    caa_records: List[CaaRecord]                # Certificate authority records
    cname_record: CnameRecord                   # Canonical name (single record)
    mx_records: List[MxRecord]                  # Mail exchange records
    ns_records: List[NsRecord]                  # Name server records
    ptr_records: List[PtrRecord]                # Pointer records
    soa_record: SoaRecord                       # Start of authority (single record)
    srv_records: List[SrvRecord]                # Service records
    txt_records: List[TxtRecord]                # Text records

Record Types Enumeration

class RecordType(str, Enum):
    """Supported DNS record types."""
    A = "A"           # IPv4 address
    AAAA = "AAAA"     # IPv6 address
    CAA = "CAA"       # Certificate Authority Authorization
    CNAME = "CNAME"   # Canonical name
    MX = "MX"         # Mail exchange
    NS = "NS"         # Name server
    PTR = "PTR"       # Pointer (reverse DNS)
    SOA = "SOA"       # Start of authority
    SRV = "SRV"       # Service record
    TXT = "TXT"       # Text record

Advanced Scenarios

Conditional Updates with ETags

Use ETags to prevent conflicting updates when multiple clients modify the same record set:

# Get current record set with ETag
record_set = dns_client.record_sets.get(
    resource_group_name="my-rg",
    zone_name="example.com",
    relative_record_set_name="api",
    record_type=RecordType.A
)

# Modify the record set
record_set.a_records.append(ARecord(ipv4_address="192.0.2.100"))

# Update with ETag to prevent conflicts
try:
    updated_record_set = dns_client.record_sets.create_or_update(
        resource_group_name="my-rg",
        zone_name="example.com",
        relative_record_set_name="api",
        record_type=RecordType.A,
        parameters=record_set,
        if_match=record_set.etag
    )
    print("Update successful")
except HttpResponseError as e:
    if e.status_code == 412:
        print("Conflict: Record set was modified by another client")

Batch Operations

Process multiple record sets efficiently:

from concurrent.futures import ThreadPoolExecutor
from azure.mgmt.dns.models import RecordSet, ARecord, RecordType

def create_record_set(name, ip_address):
    record_set = RecordSet(
        ttl=300,
        a_records=[ARecord(ipv4_address=ip_address)]
    )
    
    return dns_client.record_sets.create_or_update(
        resource_group_name="my-rg",
        zone_name="example.com",
        relative_record_set_name=name,
        record_type=RecordType.A,
        parameters=record_set
    )

# Create multiple record sets in parallel
record_configs = [
    ("web1", "192.0.2.10"),
    ("web2", "192.0.2.11"),
    ("web3", "192.0.2.12")
]

with ThreadPoolExecutor(max_workers=5) as executor:
    results = list(executor.map(lambda config: create_record_set(*config), record_configs))

print(f"Created {len(results)} record sets")

Error Handling

from azure.core.exceptions import HttpResponseError

try:
    record_set = dns_client.record_sets.create_or_update(
        resource_group_name="my-rg",
        zone_name="example.com",
        relative_record_set_name="test",
        record_type=RecordType.A,
        parameters=RecordSet(ttl=300, a_records=[ARecord(ipv4_address="192.0.2.1")])
    )
except HttpResponseError as e:
    if e.status_code == 400:
        print("Bad request: Check record set configuration")
    elif e.status_code == 404:
        print("Zone not found")
    elif e.status_code == 409:
        print("Conflict: Record set already exists (when using if_none_match)")
    elif e.status_code == 412:
        print("Precondition failed: ETag mismatch")
    else:
        print(f"Unexpected error: {e.status_code} - {e.message}")

Common error scenarios:

  • 400 Bad Request: Invalid record configuration or malformed data
  • 404 Not Found: DNS zone doesn't exist
  • 409 Conflict: Record set exists when using if_none_match="*"
  • 412 Precondition Failed: ETag mismatch when using conditional updates

Install with Tessl CLI

npx tessl i tessl/pypi-azure-mgmt-dns

docs

dns-record-sets.md

dns-resource-references.md

dns-zones.md

index.md

tile.json