top of page

Śledź nasze wpisy w social media

  • Instagram
  • Facebook
  • Twitter
  • LinkedIn
  • YouTube

Moduł w terraform do importu konfiguracji domeny z OVH

  • Zdjęcie autora: Piotr Kośka
    Piotr Kośka
  • 13 wrz 2025
  • 13 minut(y) czytania
Moduł w terraform

Decydując się na zarządzanie infrastrukturą za pomocą Terraforma musimy wybrać czy robimy to za pomocą IaC (deklarujemy nasza infrastrukturę w kodzie), czy zamierzamy dalej robić to ręcznie. Ponieważ zmiany ręczne w miedzy czasie działania naszej infrastruktury na bazie terraforma może prowadzić do dryftu konfiguracyjnego.


Ten artykuł będzie o stworzeniu modułu który, ułatwi nam zarządzanie infrastrukturą DNS w OVH. Jednocześnie ten artykuł jest reklamom kursu mojego autorstwa który, już niedługo będzie dostępny. Kurs ten jest przeznaczony dla osób które, zaczynają przygodę z terraformem i chcą podnieść rownież swoja wiedzę na temat terraform. Zatem zaczynamy.


Podstawy naszego modułu do Domain OVH


Zanim zaczniemy musimy ustaliś podstawy. Po pierwsze w naszym module bedziemy bazować na dwóch resorces:


  1. ovh_domain_zone_record

  2. ovh_domain_name_servers


Pracując z ovh_domain_zone_record musimy zwrócić uwagę na informację którą, sam dostawca OVH umieszcza nam w tym zasobie:


Warning
The Change in text format feature available in the web console will update the ovh_domain_zone_record ids if you use it. Hence if you have created your records with terraform, you will get some record has been deleted errors. The workaround is to terraform import all the records with the updated ids and to stop to mix web console and terraform.

Poniżej wyjaśniam dlaczego ostrzeżenie z dokumentacji providera OVH ma krytyczne znaczenie i co dokładnie się dzieje, gdy wprowadzisz zmiany w strefie poza Terraformem, zwłaszcza przy użyciu opcji Change in text format w panelu OVH.



Dlaczego to ważne


Jak Terraform „wiąże” zasoby z rzeczywistością


  • Każdy zasób w stanie Terraform jest powiązany z konkretnym identyfikatorem (ID) zasobu w systemie docelowym.

  • Dla ovh_domain_zone_record provider posługuje się ID rekordu DNS nadawanym przez OVH. To ID jest kluczowe: Terraform odtwarza rzeczywistość właśnie na jego podstawie, a nie na podstawie treści rekordu (target/TTL itd.).

    → Gdy ID w OVH się zmieni, a stan Terraform nadal wskazuje stare ID, Terraform uważa, że „tego” zasobu już nie ma.



Co robi „Change in text format” w panelu OVH


  • To przełącznik w konsoli DNS OVH, który zmienia sposób zapisu treści (np. TXT) — m.in. cudzysłowy, łączenie/rozdzielanie na segmenty, itp. (czyli format prezentacji treści). W praktyce ta operacja może skończyć się utworzeniem nowego rekordu po stronie OVH (z nowym ID) zamiast „edytowaniem” istniejącego. 

  • Sama społeczność/problemy w repo providera OVH odnotowują przypadki, w których ID rekordów DNS „zmieniały się” po operacjach wykonanych spoza Terraformu, co prowadziło do potrzeby ręcznego dostosowania stanu (a niekiedy edycji/podmiany ID w state). 



Co się stanie, jeśli zignorujesz to ostrzeżenie


  1. Plan/Apply kończy się błędami o „usuniętych” rekordach

    Podczas terraform plan/apply provider próbuje odczytać rekord o starym ID. Ponieważ w OVH po zmianie formatu powstał nowy rekord z nowym ID, odczyt starego ID zwróci „nie ma takiego rekordu”.

    Objawy:


    • komunikaty w stylu record has been deleted / resource not found,

    • plan pokazuje usunięcie starego i utworzenie nowego, mimo że treściowo rekord już istnieje w OVH (tylko z innym ID).


  2. Ryzyko duplikatów i „flappingu” konfiguracji

    Jeśli Terraform spróbuje „odtworzyć” rekord z configu (bo nie znalazł starego ID), a w OVH już istnieje „taki sam” rekord (tylko z nowym ID), możesz dostać:


    • duplikaty (dwa bardzo podobne wpisy),

    • błędy o „istniejącym już rekordzie”,

    • „thrash” — ciągłe różnice w planie, bo panel mógł też przeformatować TXT (np. cudzysłowy, podział na segmenty).

    • (Dodatkowo znane są niuanse TTL w OVH: domyślny TTL bywa reprezentowany jako 0, co w niektórych wersjach providera powodowało nieoczekiwane różnice/duplikaty, jeśli pomieszać UI i Terraform. To inny, ale pokrewny objaw miksowania narzędzi.) 


  3. Niestabilne pipeline’y i incydenty


    • CI/CD z terraform plan zaczyna regularnie failować, bo stan nie zgadza się z rzeczywistością.

    • Dla krytycznych rekordów (np. MX/DMARC/DKIM) błędne rekreacje/duplikaty potrafią skutkować opóźnieniami/awariami poczty czy problemami z weryfikacjami domeny.



Dlaczego samo „porównanie treści” nie wystarcza


Nawet jeśli Twój HCL (np. w naszym module) tworzy ten sam rekord (ten sam subdomain, fieldtype, target), Terraform nadal „widzi” zasób przez pryzmat ID zdalnego. Zmiana ID poza Terraformem = dryf stanu (state drift). Dopóki nie „nauczysz” Terraformu nowego ID, plan/aplikacja będą się wykładać lub generować niechciane zmiany. To nie jest „bug w module” — to fundamentalna cecha działania Terraformu.



Zalecany workflow (bezpieczny)



  1. Zasada „single source of truth”

    Strefą zarządzasz albo w 100% przez Terraform, albo ręcznie w panelu — ale nie jednym i drugim równocześnie. Zwłaszcza nie używaj w panelu opcji Change in text format dla rekordów zarządzanych już przez Terraform.

  2. Jeśli musisz zmienić coś w panelu (np. pilny hotfix):


    • Zapisz, które rekordy zmieniono (panel/Historia lub API).

    • Zaktualizuj stan Terraform tak, aby wskazywał nowe ID tych rekordów:


      • najprościej: terraform import pod adres Twojego zasobu (w module adres będzie miał postać module.<mod>.ovh_domain_zone_record.<name>[...]). Składnię i użycie importu znajdziesz w oficjalnym dokumencie CLI. 

      • jeżeli rekordów jest bardzo dużo, skorzystaj z narzędzi/skryptów do masowego importu (np. community tools generujące kod i skrypty importu na bazie API OVH). 


    • Gdyby brakowało precyzyjnych danych o nowych ID albo import wciąż nie „siadał”, niektórzy radzą sobie przez ręczną korektę pliku stanu (ostateczność) lub całkowitą rekreację rekordów przez Terraform (czyściutko, ale z przerwą/usunięciem istniejących wpisów). Przypadki takie są opisywane w issue trackerze providera. 


  3. Utrzymuj spójny format danych w kodzie


    • Dla TXT trzymaj się jednego sposobu zapisu (np. zawsze cudzysłowy w JSON-ie: "\"v=spf1 ...\""), żeby uniknąć różnic formatu z UI.

    • Unikaj „kliknięcia” Change in text format — ta opcja potrafi wprowadzić różny layout wartości TXT (np. segmentację), co z kolei prowokuje Terraform do zmian.





Szybka checklista, gdy widzisz „record has been deleted”



  1. terraform plan pokazuje, że rekord „zniknął”, ale w panelu dalej go widzisz → ID się zmieniło.

  2. Ustal nowe ID (przez API/inspekcję, narzędzia pomocnicze).

  3. terraform state rm <ADDRESS> (jeśli chcesz odpiąć stary wpis ze stanu).

  4. terraform import <ADDRESS> <NEW_ID> – wprowadź nowe ID do stanu. 

  5. terraform plan — plan powinien być czysty (albo pokazać już tylko merytoryczne różnice).



TL;DR


  • Nie mieszaj panelu OVH i Terraformu dla tych samych rekordów – w szczególności nie używaj „Change in text format” dla rekordów zarządzanych przez Terraform. To może zmienić ID rekordu po stronie OVH. 

  • Zmienione ID = dryf stanu → Terraform melduje „rekord usunięty”/„stworzyć nowy” i potrafi generować duplikaty lub błędy.

  • Jeśli już tak się stało: zrób import nowych ID (terraform import) zamiast pozwalać Terraformowi „na ślepo” tworzyć nowe wpisy. 

  • Dodatkowo unikaj innych rozjazdów formatu (np. TTL 0 vs domyślny TTL), bo to też potrafi powodować niechciane różnice po miksowaniu UI i code.



Tworzymy nasz moduł terraform


Nasz moduł będzie bazował na zasobach ovh_domain_zone_record i ovh_domain_name_servers. Pierwszy zasób pozwala na dodanie naszych rekordów w naszym DNS. Drugi pozwala na ustawienia naszych adresów serverów DNS które mogą zarządzać tą domeną - czyli możemy zrobić transfer domeny na inny zewnętrzny server który będzie zarządzał tą domeną. omówmy sobie każdy z tych zasobów.



Jak działa ovh_domain_zone_record


ovh_domain_zone_record to elementarny zasób do tworzenia/aktualizacji pojedynczego rekordu DNS w strefie zarządzanej przez OVH.


Najważniejsze argumenty:


  • zone (string, wymagany) – nazwa strefy DNS (np. example.com).

  • subdomain (string, wymagany) – etykieta/host; może być pustym stringiem "" dla rekordu w apex (gołej domeny).

  • fieldtype (string, wymagany) – typ rekordu (np. A, MX, TXT, …).

  • target (string, wymagany) – wartość rekordu (format zależy od typu; np. IP/FQDN/ciąg TXT).

  • ttl (number, opcjonalny) – TTL rekordu; musi być ≥ 60 (w nowszej dokumentacji SDK Pulumi dla OVH, która bazuje na tym samym API, jest to wyraźnie opisane). 



Zachowania i pułapki charakterystyczne dla OVH:


  • MX: priorytet należy podać w target, np. "10 mx1.example.com." (to cecha API/OVH; nie ma oddzielnego pola na priorytet).

  • TXT: trzymaj konsekwentny format (cudzysłowy), aby uniknąć „wiecznych” diffów planu.

  • TTL: w części scenariuszy domyślny TTL bywa reprezentowany po stronie OVH jako 0, co historycznie prowadziło do duplikatów/rozjazdów, gdy miesza się panel i Terraform (opis problemu w issue providera). 

  • Zmiany w panelu (UI) a ID rekordu: użycie w panelu opcji typu „plain text / Change in text format” może nadać rekordom nowe ID, przez co Terraform widzi „usunięto” i „trzeba utworzyć nowy”. Zalecenie: albo w 100% zarządzasz przez Terraform, albo – jeśli już zmieniono w UI – wykonujesz terraform import z nowymi ID i nie mieszasz narzędzi dalej. (To zachowanie jest potwierdzone na issue trackrze providera). 




Jakie typy rekordów możesz dodać (OVH)



OVH pozwala tworzyć standardowe rekordy DNS (zgodne z RFC) używane w praktyce. Poniżej lista z krótkim opisem i wskazówkami dot. target. (W nawiasach — co zwykle wpisujesz w target.)


Adresowe / aliasy / delegacje


  • A – IPv4 (np. 203.0.113.10).

  • AAAA – IPv6 (np. 2001:db8::10).

  • CNAME – alias do FQDN zakończonego kropką (np. host.example.net.).

  • NS – delegacja do autorytatywnego serwera nazw (FQDN z kropką, np. ns1.example.net.).

  • DNAME – alias całej gałęzi (deleguje wszystkie subdomeny na nowy sufiks). OVH opisuje DNAME w swoich materiałach dla stref. 

  • PTR – wskazanie nazwy kanonicznej (używany gł. w strefach reverse).



Poczta / usługi / tekst


  • MX – serwer(y) pocztowe z priorytetem w target (np. "10 mx1.example.net.").

  • SRV – lokalizator usługi; target to FQDN usługi (pozostałe parametry SRV określane są w implementacji po stronie API/providera; w praktyce w UI/CLI podajesz dodatkowe pola jak port/waga/prio).

  • TXT – dane tekstowe (SPF/DKIM/DMARC i inne polityki/atesty przechowuj jako TXT). OVH przewodniki konsekwentnie opisują SPF/DKIM/DMARC przez TXT



Bezpieczeństwo / klucze / certyfikaty


  • CAA – autoryzacja CA (określa, które CA mogą wystawiać certy dla domeny). OVH opisuje to w kontekście rekordów strefowych. 

  • SSHFP – odcisk klucza SSH hosta (ułatwia weryfikację klucza).

  • TLSA – DANE: powiązanie certyfikatu/publicznego klucza TLS z nazwą w DNS.



Telefonia / geolokalizacja / inne


  • NAPTR – przepisywanie nazw (VoIP/SIP itp.).

  • LOC – lokalizacja geograficzna (szer./dług./wys.).



Uwaga o nowszych typach (HTTPS/SVCB): społeczność OVH zgłasza chęć wsparcia HTTPS/SVCB i wynika z tego, że na dziś (wg publicznych wątków) nie są one jeszcze obsługiwane na serwerach nazw OVH. Planując je, licz się z ograniczeniami. 

Kontekst i podstawy DNS wg OVH – przewodniki i strony wsparcia OVH wyjaśniają ogólne typy rekordów (A/AAAA, MX, CNAME, TXT itp.) i ich zastosowania w strefie. To dobry punkt odniesienia, jeśli konfigurujesz strefę pierwszy raz lub migrujesz. 



Praktyczne wskazówki do fieldtype/target


  • FQDN-y w target (CNAME/MX/NS/SRV/DNAME) zapisuj z kropką końcową (np. mail.example.net.).

  • MX: wpisuj „prio spacja host.”, np. "10 mx1.example.net.".

  • TXT: dla poprawnego porównywania stanu używaj konsekwentnych cudzysłowów (np. "\"v=spf1 include:_spf.google.com -all\"").

  • TTL: trzymaj się wartości ≥ 60 (wprost wymóg w aktualnych materiałach SDK Pulumi dla OVH). 




Import/stan i miksowanie narzędzi


  • Jeśli ktoś kliknie w panelu (np. zmiana „text format”) i rekordy dostaną nowe ID, Terraform zacznie widzieć „usunięcia/utworzenia”. Rozwiązanie: terraform import dla dotkniętych rekordów i nie mieszać dalej UI z IaC. 





Co robi ovh_domain_name_servers



Zasób służy nie do dodawania rekordów DNS w strefie, ale do ustawienia autorytatywnych serwerów nazw (NS) dla domeny w rejestrze OVH.

To operacja na poziomie rejestracji domeny, a nie samej strefy DNS. W praktyce:


  • Wskazujesz listę nazw hostów NS, które mają obsługiwać Twoją domenę (np. dns104.ovh.net, ns104.ovh.net).

  • Dla własnych serwerów nazw w tej samej domenie (tzw. child NS, np. ns1.example.com) możesz (a często musisz) podać glue IP (IPv4/IPv6), aby rejestr mógł je rozwiązać bez „kurzej/kanapki” zależności. To nie jest rekord A/AAAA w strefie, tylko rekord glue trzymany w rejestrze domeny. Wyjaśnienie, czym jest glue: „Glue record is used to define the IP address of a name server, to allow the domain to be resolved if the name server is under the same domain.” 



Technicznie provider wykorzystuje endpoint /nameServers/update OVH API — ta funkcja została dostarczona w PR implementującym ten zasób w providerze. 



Kluczowe argumenty zasobu



Minimalny przykład z testów providera wygląda tak:

resource "ovh_domain_name_servers" "this" {
  domain = "example.com"

  server { host = "dns104.ovh.net" }
  server { host = "ns104.ovh.net"  }
}

Dla child NS (Twoje własne serwery w obrębie tej samej domeny) dodajesz ip:

resource "ovh_domain_name_servers" "custom" {
  domain = "example.com"

  # własne, „child” NS z glue
  server { host = "ns1.example.com" ip = "192.0.2.53"   } # IPv4
  server { host = "ns2.example.com" ip = "2001:db8::53" } # IPv6
}

To, że zasób przyjmuje bloki server { host, ip? } oraz że działa per-domain, wynika z implementacji testów i opisu PR dla tego zasobu. 



Co dokładnie możesz „dodać/ustawić” z punktu widzenia OVH



W ramach każdego server { ... }:


  • host (wymagane) – FQDN serwera nazw (np. ns1.example.com, dns104.ovh.net).

  • ip (opcjonalne) – glue IPv4 lub IPv6 dla child NS (jeśli host leży pod tą samą domeną co domain). To nie jest zwykły rekord A/AAAA; to wpis w rejestrze domeny (glue), używany tylko do bootstrapu rozwiązywania nazw. 



Uwaga: dla TLD bywają restrykcje/specyfika aktualizacji glue (np. wątki dot. .eu), więc gdy automat zgłasza błąd, to bywa ograniczenie po stronie rejestru/TLD, a nie Terraformu. 


Import i praktyka użycia



  • Import zasobu zwykle odbywa się po domenie (w module bywa to indeksowane jako [0], bo zasób jest tworzony warunkowo). W Twoim przykładzie:


import {
  to = module.zone_asdevops_cloud.ovh_domain_name_servers.this[0]
  id = "asdevops.cloud"
}


  • Jeśli wcześniej klikałeś w panelu i zmieniłeś NS/glue, a chcesz wrócić do IaC, po prostu zaimportuj aktualny stan (domena ⇒ aktualne NS) i dalej zmieniaj już tylko kodem.



Dobre praktyki i ostrzeżenia (OVH)


  1. Nie mieszaj panelu OVH i Terraformu dla tych samych ustawień NS (analogicznie do rekordów DNS: UI potrafi zmienić identyfikatory/kształt danych i wprowadzić dryf stanu). Jeśli musisz coś zmienić „na szybko” w UI, terraform import po fakcie i zarządzaj dalej kodem. (Ten sam motyw przewija się w dokumentacji/issue-trackerze providera). 

  2. Glue tylko gdy potrzebne: podawaj ip dla child NS (ns1.example.com dla example.com). Jeśli używasz zewnętrznych NS (np. nsX.ovh.net), nie dodawaj glue. Wyjaśnienie sensu glue — patrz doc OVH. 

  3. Cierpliwość i TLD: zmiany NS/glue propagują się na poziomie rejestru i mogą podlegać politykom TLD (czas, walidacje, blokady). W przypadku błędów specyficznych dla TLD (np. .eu) to może być problem po stronie rejestru




Kiedy używać ovh_domain_name_servers, a kiedy ovh_domain_zone_record


  • ovh_domain_name_servers – gdy zmieniasz autorytatywne NS domeny i ewentualnie definiujesz glue IP dla child NS.

  • ovh_domain_zone_record – gdy zarządzasz rekordami w samej strefie (A, AAAA, MX, TXT, CNAME, SRV, …). To zupełnie inny poziom (DNS content vs. delegacja).

    Przypominam: ustawienia NS w rejestrze nie dodają rekordów A/AAAA w strefie — jeśli utrzymujesz własne serwery NS, musisz też zadbać o ich rekordy A/AAAA w odpowiedniej strefie.



version.tf — wymagania i provider


Cel pliku: zdefiniowanie minimalnych wersji Terraform i providera OVH, tak by moduł działał deterministycznie.


  • Wymusza providera:


terraform {
  required_providers {
    ovh = {
      source  = "ovh/ovh"
      version = "2.7.0"
    }
  }
  required_version = ">= 1.3"
}

  • Dzięki temu:

    • nie zaskoczą Cię breaking changes w nowszych ovh/ovh,

    • konfiguracja jest powtarzalna w CI/CD.



variables.tf — interfejs modułu (wejścia)


Cel pliku: zdefiniowanie wszystkich zmiennych, które użytkownik modułu może (lub musi) podać.


Najważniejsze zmienne:


  1. zone (string, wymagane)

    „Nazwa strefy DNS” – np. example.com, asdevops.cloud.

    To trafia wprost do zasobów tworzących rekordy i serwery nazw.

  2. records (lista obiektów, domyślnie [])

    Lista rekordów DNS w HCL. Każdy element powinien mieć min.:

    • fieldtype (np. A, CNAME, MX, TXT, NS, …),

    • subdomain (np. "" dla apex, www dla hosta),

    • target (adres IP / FQDN / wartość TXT itd.),

    • ttl (liczba; 0 oznacza domyślny TTL po stronie OVH).

      Dodatkowe pole priority (jeśli użyjesz) służy tylko do budowy klucza unikalności przy scalaniu – przydaje się gdy chcesz mieć kilka wpisów tego samego typu pod tym samym subdomain (np. wiele TXT).


  3. records_jsonencoded (string, domyślnie null)

    Alternatywny sposób przekazania rekordów: string będący jsonencode([...]).

    W module ta lista jest zdekodowana i łączona z records.

  4. domain_name_servers (map(string), domyślnie null)

    Deklaratywne ustawienie serwerów nazw domeny (na poziomie rejestru, nie strefy).

    Schemat: {"nsX.example.com" = "GLUE_IP"}.

    • Klucz = host FQDN (może mieć kropkę końcową).

    • Wartość = glue IP (IPv4/IPv6) lub puste (""/null) jeśli glue nie jest potrzebne.

    • Walidacje w pliku:

      • Klucze (hosty) muszą być FQDN (regex dla domeny).

      • Wartości (IP) muszą być null, "", IPv4 lub **IPv6.   Tu zastosowano trik z cidrhost(”${ip}/32”,0)icidrhost(”${ip}/128”,0)` by bezpiecznie zweryfikować IPv4/IPv6.


Po co walidacje?

Aby złapać literówki/nieprawidłowy format wcześnie (na etapie terraform validate/plan), a nie dopiero jako błąd API OVH.




locals.tf — przetwarzanie wejść (normalizacja)


Cel pliku: przygotowanie danych wejściowych do wygodnego użycia w main.tf.


Definicje:


  1. servers_map = coalesce(var.domain_name_servers, {})


    • Zamienia null na pustą mapę {} — dzięki temu dalsze operacje są prostsze.


  2. server_list = [ for host, ip in local.servers_map : { host = host, ip = ip == "" ? null : ip } ]


    • Normalizacja glue IP: puste stringi "" są zamieniane na null.

      To ważne, bo argument ip w zasobie serwerów nazw jest opcjonalny — jeśli jest null, zostanie pominięty i provider nie będzie próbował ustawiać glue.

    • Efekt końcowy to lista obiektów {host, ip}, gotowa do iteracji.



Znaczenie tych locals:


  • „Odczulają” resztę kodu na null/puste wartości,

  • Przygotowują dane pod czytelne for_each w zasobach,

  • Utrzymują rozdział odpowiedzialności: walidacja w variables.tf, normalizacja w locals.tf.




main.tf — logika i zasoby


Cel pliku: utworzenie rekordów strefy oraz ewentualnie ustawienie serwerów nazw (NS) na poziomie rejestru domeny.



1) Lokalne przetworzenie rekordów


W main.tf znajdziesz lokalne konstrukcje:

locals {
  records    = concat(var.records, try(jsondecode(var.records_jsonencoded), []))
  recordsets = {
    for rs in local.records :
      "${rs.subdomain}-${rs.fieldtype}-${try(rs.priority, 0)}" => rs
  }
}

  • records — połączenie dwóch źródeł rekordów: HCL (records) + JSON (records_jsonencoded).

    try(jsondecode(...), []) zabezpiecza przed null/pustą wartością.

  • recordsets — mapa rekordów, gdzie kluczem jest stabilny identyfikator:

{subdomain}-{fieldtype}-{priority|0}

  • To:

    • zapobiega duplikatom,

    • pozwala sterować „wieloma” TXT/MX itp. przez różną priority,

    • daje stabilność planów i minimalizuje zmiany (for_each lubi stabilne klucze!).





2) Tworzenie rekordów DNS w strefie (content)


resource "ovh_domain_zone_record" "this" {
  for_each  = local.recordsets

  zone      = var.zone
  subdomain = each.value.subdomain
  fieldtype = each.value.fieldtype
  target    = each.value.target
  ttl       = each.value.ttl
}

  • Dlaczego for_each?

    Bo chcesz odwzorować N rekordów wynikających z wejść. for_each tworzy po jednym zasobie na każdy element mapy recordsets.

    Dzięki temu:

    • Terraform ma stabilne adresy zasobów (kluczem jest Twój identyfikator),

    • zmiany w pojedynczych rekordach nie „tasują” pozostałych,

    • plany są przewidywalne (ta sama kolejność, brak przypadkowych rekreacji „całości”).


  • O czym pamiętać:

    • OVH oczekuje np. dla MX priorytetu w target: "10 mx1.example.com.", więc priority w obiekcie to tylko element klucza, nie trafia do providera.

    • Dla CNAME/MX/NS/SRV/DNAME — target jako FQDN z kropką końcową (np. mail.example.com.).

    • Dla TXT — cudzysłowy ("\"v=spf1 ...\""), by uniknąć różnic formatu.



3) (Jeśli jest w tym module) Ustawianie serwerów nazw (delegacja + glue)


Na podstawie locals.server_list zwykle buduje się zasób:

resource "ovh_domain_name_servers" "this" {
  count  = length(local.server_list) > 0 ? 1 : 0
  domain = var.zone

  dynamic "server" {
    for_each = local.server_list
    content {
      host = server.value.host
      ip   = server.value.ip # null → argument pominięty (opcjonalny)
    }
  }
}

  • count warunkowo tworzy zasób tylko wtedy, gdy faktycznie podałeś jakiekolwiek serwery nazw.

  • dynamic "server" iteruje po przygotowanej liście {host, ip}.

  • Jeśli ip = null, provider pominie glue (co jest poprawne dla zewnętrznych NS, np. dns10.ovh.net).

  • To jest inna warstwa niż rekordy strefy: zmieniasz autorytatywne NS domeny w rejestrze.


Uwaga: w Twoim main.tf widziałem punktowe fragmenty i komentarze; powyżej pokazuję pełną, kanoniczną formę, zgodną z tym jak przygotowują dane locals.tf i jakie walidacje są w variables.tf.


Jak pliki się łączą (przepływ danych)


  1. Użytkownik podaje wartości w module (np. zone, records, records_jsonencoded, domain_name_servers).

  2. variables.tf — przyjmuje te dane, waliduje (FQDN, IP), ustawia domyślne ([], null).

  3. locals.tf — normalizuje dane dla NS:

    • null → {},

    • "" → null (dla glue),

    • buduje server_list pod wygodną iterację.


  4. main.tf:

    • scala rekordy (records + records_jsonencoded → locals.records),

    • buduje kluczowaną mapę recordsets → stabilne ID dla for_each,

    • tworzy N × ovh_domain_zone_record (content),

    • opcjonalnie tworzy ovh_domain_name_servers z dynamicznymi server blokami (delegacja/glue).


  5. version.tf — zapewnia, że wszystko wyżej działa na spójnych wersjach narzędzi.



Dlaczego for_each (i klucze) są tak ważne


  • for_each + stabilny klucz ("${subdomain}-${fieldtype}-${try(priority,0)}") gwarantują:

    • Idempotencję: Terraform rozpoznaje „który rekord jest który” po Twoim kluczu, więc nie „przemapowuje” przypadkowo zasobów,

    • Minimalny diff: zmiana jednego wpisu nie powoduje rekreacji pozostałych,

    • Możliwość wielu rekordów tego samego typu pod tym samym subdomain (np. kilka TXT) — rozróżniasz je przez priority w kluczu (to tylko identyfikator w module; do OVH idzie target z właściwą treścią).


Gdyby użyć count i listy, każde przesunięcie elementu w liście mogłoby wywołać kaskadę rekreacji. Mapa + for_each eliminuje ten problem.

Podsumowanie ról


  • version.tf — „kontrola wersji”: trzyma nas na właściwych wersjach Terraform i providera.

  • variables.tf — „API modułu”: definicje wejść + walidacje (FQDN/IP) dla bezpieczeństwa.

  • locals.tf — „adapter”: normalizacja danych do prostego, powtarzalnego kształtu (listy {host, ip}).

  • main.tf — „silnik”:

    • scala i deduplikuje rekordy (records + records_jsonencoded → recordsets),

    • tworzy rekordy strefy z for_each,

    • opcjonalnie ustawia serwery nazw domeny (delegacja/glue) w trybie deklaratywnym.


Podsumowanie



Wykorzystanie modułu z przykładem możesz obejrzeć tu:




Tak jak pisałem cały artykuł jest mała reklamą mojego kursu który, jest dostępny do zakupu na stronie https://grupadm.pl/kursy/terraform/


Zapraszam. Piotr Kośka

Komentarze


Śledź nasze wpisy w social media

  • Instagram
  • Facebook
  • Twitter
  • LinkedIn
  • YouTube

Poznaj terraform jedno z najepszych narzedzi do zarządzania infrastrukturą w kodzie (IaC) - w kursie tym przeprowadzam Cię przez proces instalacji i konfiguracji tego narzędzia.

bottom of page