Terraform 0.11 - Writing Custom Providers

कस्टम प्रदाता लेखन




terraform

कस्टम प्रदाता लेखन

टेराफॉर्म में, एक प्रदाता एक अपस्ट्रीम एपीआई का तार्किक अमूर्त है। यह मार्गदर्शिका बताती है कि टेराफॉर्म के लिए एक कस्टम प्रदाता कैसे बनाया जाए।

क्यूं कर?

कस्टम टेराफ़ॉर्म प्रदाता को लिखने के कुछ संभावित कारण हैं, जैसे:

  • एक आंतरिक निजी क्लाउड जिसकी कार्यक्षमता या तो मालिकाना है या जो ओपन सोर्स समुदाय को लाभ नहीं पहुंचाएगा।

  • एक "प्रगति में काम" प्रदाता को वापस योगदान देने से पहले स्थानीय स्तर पर परीक्षण किया जा रहा है।

  • किसी मौजूदा प्रदाता का विस्तार

स्थानीय सेटअप

Terraform एक प्लगइन मॉडल का समर्थन करता है, और सभी प्रदाता वास्तव में प्लगइन्स हैं। प्लगइन्स को गो बायनेरिज़ के रूप में वितरित किया जाता है। यद्यपि तकनीकी रूप से किसी अन्य भाषा में एक प्लगइन लिखना संभव है, लगभग सभी टेराफॉर्म प्लग इन गो में लिखे गए हैं। गो स्थापित करने और कॉन्फ़िगर करने के बारे में अधिक जानकारी के लिए, कृपया गोलांग इंस्टॉलेशन गाइड पर जाएं

यह पोस्ट गोलंग और बुनियादी प्रोग्रामिंग अवधारणाओं के साथ परिचितता मानता है।

एक अनुस्मारक के रूप में, टेराफॉर्म के सभी मुख्य प्रदाता खुले स्रोत हैं। जब अटक जाते हैं या उदाहरण खोजते हैं, तो कृपया मदद के लिए मुक्त स्रोत प्रदाताओं को संदर्भित करने के लिए स्वतंत्र महसूस करें।

प्रदाता योजना

प्रारंभ करने के लिए, एक फ़ाइल बनाएँ, जिसका नाम provider.go । यह प्रदाता की जड़ है और इसमें निम्नलिखित बॉयलरप्लेट कोड शामिल होना चाहिए:

package main

import (
        "github.com/hashicorp/terraform/helper/schema"
)

func Provider() *schema.Provider {
        return &schema.Provider{
                ResourcesMap: map[string]*schema.Resource{},
        }
}

helper/schema लाइब्रेरी टेराफ़ॉर्म कोर का हिस्सा है। यह कई जटिलताओं का सार करता है और प्रदाताओं के बीच स्थिरता सुनिश्चित करता है। ऊपर दिया गया उदाहरण एक खाली प्रदाता को परिभाषित करता है (कोई संसाधन नहीं हैं)।

*schema.Provider प्रकार प्रदाता के गुणों का वर्णन करता है जिसमें शामिल हैं:

  • कॉन्फ़िगरेशन कुंजी यह स्वीकार करता है
  • संसाधनों का समर्थन करता है
  • कॉन्फ़िगर करने के लिए कोई भी कॉलबैक

प्लगइन का निर्माण

गो को एक main.go फ़ाइल की आवश्यकता होती है, जो बाइनरी के निर्माण के दौरान डिफ़ॉल्ट निष्पादन योग्य होती है। चूंकि Terraform प्लगइन्स को गो बायनेरिज़ के रूप में वितरित किया जाता है, इसलिए इस एंट्री-पॉइंट को निम्नलिखित कोड के साथ परिभाषित करना महत्वपूर्ण है:

package main

import (
        "github.com/hashicorp/terraform/plugin"
        "github.com/hashicorp/terraform/terraform"
)

func main() {
        plugin.Serve(&plugin.ServeOpts{
                ProviderFunc: func() terraform.ResourceProvider {
                        return Provider()
                },
        })
}

यह एक वैध, निष्पादन योग्य गो बाइनरी का उत्पादन करने के लिए मुख्य कार्य स्थापित करता है। मुख्य फ़ंक्शन की सामग्री टेराफ़ॉर्म के plugin लाइब्रेरी का उपभोग करती है। यह लाइब्रेरी टेराफॉर्म कोर और प्लगइन के बीच सभी संचार से संबंधित है।

अगला, गो टूलकिन का उपयोग करके प्लगइन का निर्माण करें:

$ go build -o terraform-provider-example

आउटपुट नाम ( -o ) बहुत महत्वपूर्ण है । के प्रारूप में प्लगइन्स के लिए टेराफॉर्म खोजता है:

terraform-<TYPE>-<NAME>

ऊपर के मामले में, प्लगइन "प्रदाता" और नाम "उदाहरण" का है।

चीजों को सही तरीके से सत्यापित करने के लिए, बस बनाए गए बाइनरी को निष्पादित करें:

$ ./terraform-provider-example
This binary is a plugin. These are not meant to be executed directly.
Please execute the program that consumes these plugins, which will
load any plugins automatically

यह टेराफ़ॉर्म प्लगइन के लिए मूल परियोजना संरचना और मचान है। पुनर्प्राप्त करने के लिए, फ़ाइल संरचना है:

.
├── main.go
└── provider.go

संसाधनों को परिभाषित करना

टेराफॉर्म प्रदाता संसाधनों का प्रबंधन करते हैं। एक प्रदाता एक अपस्ट्रीम एपीआई का एक अमूर्त हिस्सा है, और एक संसाधन उस प्रदाता का एक घटक है। एक उदाहरण के रूप में, AWS प्रदाता aws_instance और aws_elastic_ip का समर्थन करता है। DNSimple dnsimple_record का समर्थन करता है। fastly_service का समर्थन करता है। आइए हमारे काल्पनिक प्रदाता के लिए एक संसाधन जोड़ें।

एक सामान्य सम्मेलन के रूप में, Terraform प्रदाताओं ने प्रत्येक संसाधन को अपनी फ़ाइल में रखा, संसाधन के नाम पर, संसाधन_ के साथ उपसर्ग किया। एक example_server बनाने के लिए, यह resource_server.go सम्मेलन द्वारा होगा:

package main

import (
        "github.com/hashicorp/terraform/helper/schema"
)

func resourceServer() *schema.Resource {
        return &schema.Resource{
                Create: resourceServerCreate,
                Read:   resourceServerRead,
                Update: resourceServerUpdate,
                Delete: resourceServerDelete,

                Schema: map[string]*schema.Schema{
                        "address": &schema.Schema{
                                Type:     schema.TypeString,
                                Required: true,
                        },
                },
        }
}

यह schema.Resource का उपयोग करता है। schema.Resource प्रकार । यह संरचना संसाधन के लिए डेटा स्कीमा और CRUD संचालन को परिभाषित करती है। संसाधन बनाने के लिए इन गुणों को परिभाषित करना एकमात्र आवश्यक चीज है।

ऊपर दिए गए स्कीमा एक तत्व, "address" को परिभाषित करता है, जो एक आवश्यक स्ट्रिंग है। टेराफॉर्म के स्कीमा स्वचालित रूप से सत्यापन और टाइपिंग कास्टिंग को लागू करता है।

इसके बाद चार "फ़ील्ड" परिभाषित हैं - Create , Read , Update और Delete । संसाधन के कार्यशील होने के लिए Create , Read और Delete कार्य आवश्यक हैं। अन्य कार्य हैं, लेकिन ये केवल आवश्यक हैं। Terraform खुद को हैंडल करता है कि किस फ़ंक्शन को कॉल करना है और किस डेटा के साथ। संसाधन की स्कीमा और वर्तमान स्थिति के आधार पर, टेराफॉर्म यह निर्धारित कर सकता है कि क्या उसे एक नया संसाधन बनाने की जरूरत है, एक मौजूदा अपडेट करें या नष्ट करें।

चार संरचनात्मक क्षेत्रों में से प्रत्येक एक फ़ंक्शन को इंगित करता है। हालांकि यह तकनीकी रूप से संसाधन स्कीमा में सभी कार्यों को इनलाइन करने के लिए संभव है, सबसे अच्छा अभ्यास प्रत्येक फ़ंक्शन को अपनी विधि में खींचने का आदेश देता है। यह परीक्षण और पठनीयता दोनों के लिए अनुकूलन करता है। अब उन स्टब्स में भरें, मेथड सिग्नेचर पर पूरा ध्यान दें।

func resourceServerCreate(d *schema.ResourceData, m interface{}) error {
        return nil
}

func resourceServerRead(d *schema.ResourceData, m interface{}) error {
        return nil
}

func resourceServerUpdate(d *schema.ResourceData, m interface{}) error {
        return nil
}

func resourceServerDelete(d *schema.ResourceData, m interface{}) error {
        return nil
}

अंत में, इस नए संसाधन को पंजीकृत करने के लिए प्रदाता स्कीमा को provider.go में अपडेट करें।

func Provider() *schema.Provider {
        return &schema.Provider{
                ResourcesMap: map[string]*schema.Resource{
                        "example_server": resourceServer(),
                },
        }
}

प्लगइन का निर्माण और परीक्षण करें। सब कुछ के रूप में संकलित किया जाना चाहिए, हालांकि सभी संचालन एक सेशन नहीं हैं।

$ go build -o terraform-provider-example

$ ./terraform-provider-example
This binary is a plugin. These are not meant to be executed directly.
Please execute the program that consumes these plugins, which will
load any plugins automatically

लेआउट अब इस तरह दिखता है:

.
├── main.go
├── provider.go
├── resource_server.go
└── terraform-provider-example

प्रदाता को आमंत्रित करना

पिछले अनुभागों ने शेल के माध्यम से प्रदाता को सीधे चलाना दिखाया, जो चेतावनी संदेश को आउटपुट करता है जैसे:

This binary is a plugin. These are not meant to be executed directly.
Please execute the program that consumes these plugins, which will
load any plugins automatically

Terraform plugins को सीधे Terraform द्वारा निष्पादित किया जाना चाहिए। इसका परीक्षण करने के लिए, वर्किंग डायरेक्टरी (प्लगिन मौजूद होने की जगह) में एक main.tf बनाएं।

resource "example_server" "my-server" {}

जब यह कॉन्फ़िगरेशन फ़ाइलों को पार्स करता है, तो Terraform स्वचालित रूप से प्रदाताओं को पता चलता है। यह केवल तब होता है जब init कमांड निष्पादित होता है। Terraform वर्तमान स्थानीय निर्देशिका सहित Discovery प्रक्रिया के माध्यम से प्रदाताओं के मिलान के लिए खोज करेगा। हमारे नए संकलित प्रदाता को खोजने के लिए terraform init चलाएं:

$ terraform init

Initializing provider plugins...

Terraform has been successfully initialized!

You may now begin working with Terraform. Try running "terraform plan" to see
any changes that are required for your infrastructure. All Terraform commands
should now work.

If you ever set or change modules or backend configuration for Terraform,
rerun this command to reinitialize your working directory. If you forget, other
commands will detect it and remind you to do so if necessary.

अब terraform plan अंजाम दें:

$ terraform plan

1 error(s) occurred:

* example_server.my-server: "address": required field is not set

यह पुष्टि करता है कि टेराफ़ॉर्म सही तरीके से हमारे प्लगइन को काम सौंप रहा है और हमारी मान्यता के अनुसार काम कर रहा है। संसाधन में address फ़ील्ड जोड़कर सत्यापन त्रुटि को ठीक करें:

resource "example_server" "my-server" {
  address = "1.2.3.4"
}

सत्यापन को सत्यापित करने के लिए terraform plan निष्पादित कर रहा है:

Refreshing Terraform state in-memory prior to plan...
The refreshed state will be used to calculate this plan, but will not be
persisted to local or remote state storage.


------------------------------------------------------------------------

An execution plan has been generated and is shown below.
Resource actions are indicated with the following symbols:
  + create

Terraform will perform the following actions:

  + example_server.my-server
      id:      <computed>
      address: "1.2.3.4"


Plan: 1 to add, 0 to change, 0 to destroy.

------------------------------------------------------------------------

terraform apply करना संभव है, लेकिन यह एक नो-ऑप होगा क्योंकि सभी संसाधन विकल्प वर्तमान में कोई कार्रवाई नहीं करते हैं।

क्रिएट इम्प्लीमेंट करें

संसाधन_server.go में वापस, क्रिएट फ़ंक्शनलिटी लागू करें:

func resourceServerCreate(d *schema.ResourceData, m interface{}) error {
        address := d.Get("address").(string)
        d.SetId(address)
        return nil
}

यह schema.ResourceData API कॉन्फ़िगरेशन में उपयोगकर्ता द्वारा प्रदान किए गए "address" का मान प्राप्त करने के लिए schema.ResourceData API का उपयोग करता है। गो के काम करने के तरीके के कारण, हमें इसे स्ट्रिंग में टाइप करना होगा। यह एक सुरक्षित ऑपरेशन है, हालांकि, चूंकि हमारे स्कीमा की गारंटी है, यह एक स्ट्रिंग प्रकार होगा।

इसके बाद, यह SetId , एक अंतर्निहित फ़ंक्शन का उपयोग करता है, पते पर संसाधन की आईडी सेट करने के लिए। एक गैर-रिक्त आईडी का अस्तित्व टेराफॉर्म को बताता है कि एक संसाधन बनाया गया था। यह आईडी कोई भी स्ट्रिंग मान हो सकता है, लेकिन ऐसा मान होना चाहिए जिसका उपयोग संसाधन को फिर से पढ़ने के लिए किया जा सके।

अंत में, हमें बाइनरी को फिर से भरना चाहिए और टेराफॉर्म को निर्देश देना चाहिए कि इसे रीएरनेटिव terraform init इनिट द्वारा पुन: terraform init । यह केवल इसलिए आवश्यक है क्योंकि हमने कोड को संशोधित किया है और बाइनरी को फिर से जोड़ दिया है, और यह अब प्रत्येक ऑपरेशन के लिए समान बायनेरिज़ का उपयोग करने के लिए आंतरिक हैश टेराफॉर्म के उपयोग से मेल नहीं खाता है।

terraform init चलाएं, और फिर terraform plan चलाएं।

$ go build -o terraform-provider-example
$ terraform init
# ...
$ terraform plan

+ example_server.my-server
    address: "1.2.3.4"


Plan: 1 to add, 0 to change, 0 to destroy.

जब आप terraform apply करते हैं तो terraform apply पुष्टि की मांग करेगा। अपना उदाहरण सर्वर बनाने और उसे राज्य के लिए प्रतिबद्ध करने के लिए yes दर्ज करें:

$ terraform apply

An execution plan has been generated and is shown below.
Resource actions are indicated with the following symbols:
  + create

Terraform will perform the following actions:

  + example_server.my-server
      id:      <computed>
      address: "1.2.3.4"


Plan: 1 to add, 0 to change, 0 to destroy.

Do you want to perform these actions?
  Terraform will perform the actions described above.
  Only 'yes' will be accepted to approve.

  Enter a value: yes

example_server.my-server: Creating...
  address: "" => "1.2.3.4"
example_server.my-server: Creation complete after 0s (ID: 1.2.3.4)

चूंकि SetId ऑपरेशन ने SetId उपयोग किया, टेराफॉर्म का मानना ​​है कि संसाधन सफलतापूर्वक बनाया गया है। terraform plan चलाकर इसे सत्यापित करें।

$ terraform plan
Refreshing Terraform state in-memory prior to plan...
The refreshed state will be used to calculate this plan, but will not be
persisted to local or remote state storage.

example_server.my-server: Refreshing state... (ID: 1.2.3.4)

------------------------------------------------------------------------

No changes. Infrastructure is up-to-date.

This means that Terraform did not detect any differences between your
configuration and real physical resources that exist. As a result, no
actions need to be performed.

फिर से, SetId को कॉल करने के SetId , टेराफॉर्म का मानना ​​है कि संसाधन बनाया गया था। जब plan चलती है, तो Terraform ठीक से निर्धारित करता है कि लागू करने के लिए कोई परिवर्तन नहीं हैं।

इस व्यवहार को सत्यापित करने के लिए, address फ़ील्ड का मान बदलें और terraform plan फिर से चलाएँ। आपको इस तरह आउटपुट देखना चाहिए:

$ terraform plan
Refreshing Terraform state in-memory prior to plan...
The refreshed state will be used to calculate this plan, but will not be
persisted to local or remote state storage.

example_server.my-server: Refreshing state... (ID: 1.2.3.4)

------------------------------------------------------------------------

An execution plan has been generated and is shown below.
Resource actions are indicated with the following symbols:
  ~ update in-place

Terraform will perform the following actions:

  ~ example_server.my-server
      address: "1.2.3.4" => "5.6.7.8"


Plan: 0 to add, 1 to change, 0 to destroy.

------------------------------------------------------------------------

Note: You didn't specify an "-out" parameter to save this plan, so Terraform
can't guarantee that exactly these actions will be performed if
"terraform apply" is subsequently run.

Terraform परिवर्तन का पता लगाता है और एक ~ उपसर्ग के साथ एक भिन्न को प्रदर्शित करता है, यह देखते हुए कि संसाधन नए बनाए जाने के बजाय संसाधन को संशोधित किया जाएगा।

परिवर्तनों को लागू terraform apply लिए रन terraform apply करें। Terraform फिर से पुष्टि के लिए संकेत देगा:

$ terraform apply
example_server.my-server: Refreshing state... (ID: 1.2.3.4)

An execution plan has been generated and is shown below.
Resource actions are indicated with the following symbols:
  ~ update in-place

Terraform will perform the following actions:

  ~ example_server.my-server
      address: "1.2.3.4" => "5.6.7.8"


Plan: 0 to add, 1 to change, 0 to destroy.

Do you want to perform these actions?
  Terraform will perform the actions described above.
  Only 'yes' will be accepted to approve.

  Enter a value: yes

example_server.my-server: Modifying... (ID: 1.2.3.4)
  address: "1.2.3.4" => "5.6.7.8"
example_server.my-server: Modifications complete after 0s (ID: 1.2.3.4)

Apply complete! Resources: 0 added, 1 changed, 0 destroyed.

चूंकि हमने Update फ़ंक्शन को लागू नहीं किया है, आप परिवर्तनों की रिपोर्ट करने के लिए terraform plan ऑपरेशन की अपेक्षा करेंगे, लेकिन ऐसा नहीं होता है! Update कार्यान्वयन के बिना हमारे परिवर्तन कैसे जारी थे?

त्रुटि से निपटने और आंशिक स्थिति

पहले हमारा Update ऑपरेशन सफल हुआ और एक खाली फ़ंक्शन परिभाषा के साथ नए राज्य को जारी रखा। वर्तमान अद्यतन फ़ंक्शन को याद करें:

func resourceServerUpdate(d *schema.ResourceData, m interface{}) error {
        return nil
}

return nil टेराफॉर्म को बताता है कि अपडेट ऑपरेशन त्रुटि के बिना सफल रहा। टेराफॉर्म यह मानता है कि त्रुटि के बिना लागू किए गए किसी भी परिवर्तन का अर्थ है। इस वजह से, हमारे राज्य ने अपडेट किया और टेराफॉर्म का मानना ​​है कि आगे कोई बदलाव नहीं हुआ है।

इसे दूसरे तरीके से कहने के लिए: यदि कोई कॉलबैक कोई त्रुटि नहीं देता है, तो टेराफॉर्म स्वचालित रूप से सफलतापूर्वक लागू किए गए पूरे अंतर को मान लेता है, अंतिम स्थिति में विलय को मर्ज कर देता है और इसे बनाए रखता है।

फ़ंक्शंस को कभी भी जानबूझकर panic नहीं करना चाहिए या os.Exit देना चाहिए। बाहर os.Exit - हमेशा एक त्रुटि लौटाएं।

वास्तव में, यह इससे थोड़ा अधिक जटिल है। उस परिदृश्य की कल्पना करें जहां हमारे अपडेट फ़ंक्शन को दो अलग-अलग फ़ील्ड्स को अपडेट करना है, जिनके लिए दो अलग-अलग एपीआई कॉल की आवश्यकता है। पहला API कॉल सफल होने पर हम क्या करते हैं लेकिन दूसरा विफल हो जाता है? हम टेराफॉर्म को ठीक से कैसे बताएं कि केवल आधा अंतर ही बना रहे? यह एक आंशिक स्थिति के रूप में जाना जाता है, और इनको ठीक से लागू करना एक अच्छी तरह से व्यवहार करने वाले प्रदाता के लिए महत्वपूर्ण है।

यहाँ टेराफ़ॉर्म में राज्य अद्यतन के नियम हैं। ध्यान दें कि इस कॉलबैक में हमने चर्चा नहीं की है, पूर्णता के लिए।

  • यदि SetId का उपयोग किए बिना ID सेट के साथ या बिना त्रुटि के कॉलबैक रिटर्न SetId , तो संसाधन को बनाया नहीं जाना माना जाता है, और कोई भी राज्य सहेजा नहीं जाता है।

  • यदि कॉलबैक बिना किसी त्रुटि और आईडी के सेट करता है, तो संसाधन बनाया गया है और इसके साथ सभी स्थिति को सहेज लिया गया है। दोहराते हुए क्योंकि यह महत्वपूर्ण है: यदि कोई त्रुटि है, लेकिन आईडी सेट है, तो राज्य पूरी तरह से सहेजा गया है।

  • यदि Update कॉलबैक त्रुटि के साथ या उसके बिना देता है, तो पूर्ण स्थिति सहेजी जाती है। यदि आईडी रिक्त हो जाती है, तो संसाधन नष्ट हो जाता है (भले ही अपडेट के भीतर, हालांकि यह त्रुटि परिदृश्यों को छोड़कर नहीं होना चाहिए)।

  • यदि कॉलबैक बिना किसी त्रुटि के लौटाता है, तो संसाधन नष्ट हो जाता है, और सभी स्थिति निकाल दी जाती है।

  • यदि कॉलबैक को Destroy त्रुटि होती है, तो संसाधन को अभी भी मौजूद माना जाता है, और सभी पूर्व स्थिति संरक्षित है।

  • यदि आंशिक मोड (अगला कवर किया गया है), जब कोई निर्माण या अद्यतन लौटाया जाता है, तो केवल स्पष्ट रूप से सक्षम कॉन्फ़िगरेशन कुंजियाँ बनी रहती हैं, जिसके परिणामस्वरूप आंशिक स्थिति होती है।

आंशिक मोड एक ऐसा मोड है जिसे कॉलबैक द्वारा सक्षम किया जा सकता है जो टेराफॉर्म को बताता है कि यह आंशिक स्थिति के लिए संभव है। जब यह मोड सक्षम हो जाता है, तो प्रदाता को टेराफ़ॉर्म को स्पष्ट रूप से बताना होगा कि क्या जारी रखना सुरक्षित है और क्या नहीं।

यहाँ अद्यतन फ़ंक्शन के साथ आंशिक मोड का एक उदाहरण है:

func resourceServerUpdate(d *schema.ResourceData, m interface{}) error {
        // Enable partial state mode
        d.Partial(true)

        if d.HasChange("address") {
                // Try updating the address
                if err := updateAddress(d, m); err != nil {
                        return err
                }

                d.SetPartial("address")
        }

        // If we were to return here, before disabling partial mode below,
        // then only the "address" field would be saved.

        // We succeeded, disable partial mode. This causes Terraform to save
        // all fields again.
        d.Partial(false)

        return nil
}

नोट - यह कोड तब से संकलित नहीं होगा क्योंकि कोई updateAddress नहीं है। आप आंशिक राज्य के साथ खेलने के लिए इस फ़ंक्शन के डमी संस्करण को लागू कर सकते हैं। इस उदाहरण के लिए, इस दस्तावेज़ के उदाहरण में आंशिक स्थिति का ज्यादा मतलब नहीं है। यदि updateAddress को विफल करना था, तो पता फ़ील्ड अपडेट नहीं की जाएगी।

नष्ट करना लागू करना

Destroy कॉलबैक वास्तव में ऐसा लगता है जैसे - यह संसाधन को नष्ट करने के लिए कहा जाता है। इस ऑपरेशन को संसाधन पर किसी भी स्थिति को अपडेट नहीं करना चाहिए। d.SetId("") को कॉल करना आवश्यक नहीं है, क्योंकि कोई भी गैर-त्रुटि रिटर्न मान मानता है कि संसाधन सफलतापूर्वक हटा दिया गया था।

func resourceServerDelete(d *schema.ResourceData, m interface{}) error {
  // d.SetId("") is automatically called assuming delete returns no errors, but
  // it is added here for explicitness.
        d.SetId("")
        return nil
}

नष्ट फ़ंक्शन को हमेशा उस मामले को संभालना चाहिए जहां संसाधन पहले से ही नष्ट हो सकता है (मैन्युअल रूप से, उदाहरण के लिए)। यदि संसाधन पहले से ही नष्ट हो गया है, तो यह एक त्रुटि नहीं लौटानी चाहिए। यह टेराफ़ॉर्म उपयोगकर्ताओं को टेराफ़ॉर्म को तोड़ने के बिना संसाधनों को मैन्युअल रूप से हटाने की अनुमति देता है। प्रदाता को पुन: व्यवस्थित और पुन: व्यवस्थित करें:

$ go build -o terraform-provider-example
$ terraform init
#...

संसाधन को नष्ट terraform destroy लिए terraform destroy को नष्ट करें।

$ terraform destroy
example_server.my-server: Refreshing state... (ID: 5.6.7.8)

An execution plan has been generated and is shown below.
Resource actions are indicated with the following symbols:
  - destroy

Terraform will perform the following actions:

  - example_server.my-server


Plan: 0 to add, 0 to change, 1 to destroy.

Do you really want to destroy?
  Terraform will destroy all your managed infrastructure, as shown above.
  There is no undo. Only 'yes' will be accepted to confirm.

  Enter a value: yes

example_server.my-server: Destroying... (ID: 5.6.7.8)
example_server.my-server: Destruction complete after 0s

Destroy complete! Resources: 1 destroyed.

कार्यान्वयन को पढ़ें

Read कॉलबैक का उपयोग स्थानीय स्थिति को वास्तविक स्थिति (अपस्ट्रीम) के साथ सिंक करने के लिए किया जाता है। इसे टेराफॉर्म द्वारा विभिन्न बिंदुओं पर कहा जाता है और इसे केवल-पढ़ने के लिए ऑपरेशन होना चाहिए। इस कॉलबैक को कभी भी वास्तविक संसाधन को संशोधित नहीं करना चाहिए।

यदि आईडी को रिक्त करने के लिए अपडेट किया गया है, तो यह टेराफॉर्म को बताता है कि संसाधन अब मौजूद नहीं है (शायद यह बैंड से बाहर नष्ट हो गया था)। कॉलबैक को नष्ट करने की तरह, Read फंक्शन को इस मामले को इनायत से संभालना चाहिए।

func resourceServerRead(d *schema.ResourceData, m interface{}) error {
  client := m.(*MyClient)

  // Attempt to read from an upstream API
  obj, ok := client.Get(d.Id())

  // If the resource does not exist, inform Terraform. We want to immediately
  // return here to prevent further processing.
  if !ok {
    d.SetId("")
    return nil
  }

  d.Set("address", obj.Address)
  return nil
}

अगला कदम

यह मार्गदर्शिका प्रदाता फ्रेमवर्क का उपयोग करके टेराफॉर्म प्रदाता को लागू करने के लिए स्कीमा और संरचना को कवर करती है। अगले चरणों के रूप में, उदाहरण के लिए आंतरिक प्रदाताओं को देखें। टेराफॉर्म में परीक्षण प्रदाताओं के लिए एक पूर्ण ढांचा भी शामिल है।

सामान्य नियम

समर्पित अपस्ट्रीम लाइब्रेरी

नए उपयोगकर्ताओं द्वारा की जाने वाली सबसे बड़ी गलतियों में से एक क्लाइंट लाइब्रेरी को टेराफॉर्म कार्यान्वयन के साथ भ्रमित करने की कोशिश है। टेराफॉर्म को हमेशा एक स्वतंत्र क्लाइंट लाइब्रेरी का उपभोग करना चाहिए जो अपस्ट्रीम के साथ संचार करने के लिए मुख्य तर्क को लागू करता है। प्रदाता में ही इस प्रकार के तर्क को लागू करने का प्रयास न करें।

डाटा के स्रोत

यहां स्पष्ट रूप से चर्चा नहीं की गई है, लेकिन डेटा स्रोत संसाधनों का एक विशेष सबसेट हैं जो केवल-पढ़ने के लिए हैं। उन्हें नियमित संसाधनों की तुलना में पहले हल किया जाता है और टेराफॉर्म के प्रक्षेप के हिस्से के रूप में उपयोग किया जा सकता है।