package main import ( "bytes" "context" "encoding/json" "fmt" "io" "net/http" "github.com/hashicorp/terraform-plugin-sdk/v2/diag" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" ) // apiClient holds configuration and auth token for talking to the backend API. type apiClient struct { BaseURL string Token string } // loginRequest represents the request body for /login. type loginRequest struct { Username string `json:"username"` Password string `json:"password"` } // loginResponse represents the response body from /login. type loginResponse struct { Token string `json:"token"` } // Provider defines the vcluster Terraform provider. func Provider() *schema.Provider { return &schema.Provider{ Schema: map[string]*schema.Schema{ "base_url": { Type: schema.TypeString, Required: true, Description: "Base URL of vcluster API, e.g. http://localhost:8082", }, "username": { Type: schema.TypeString, Required: true, Description: "Username for login to vcluster API", }, "password": { Type: schema.TypeString, Required: true, Sensitive: true, Description: "Password for login to vcluster API", }, }, ResourcesMap: map[string]*schema.Resource{ "vcluster_cluster": resourceCluster(), }, ConfigureContextFunc: func(ctx context.Context, d *schema.ResourceData) (interface{}, diag.Diagnostics) { baseURL := d.Get("base_url").(string) username := d.Get("username").(string) password := d.Get("password").(string) client := &apiClient{ BaseURL: baseURL, } // Perform login to obtain token. reqBody, err := json.Marshal(loginRequest{ Username: username, Password: password, }) if err != nil { return nil, diag.FromErr(err) } req, err := http.NewRequestWithContext(ctx, http.MethodPost, fmt.Sprintf("%s/login", baseURL), bytes.NewReader(reqBody)) if err != nil { return nil, diag.FromErr(err) } req.Header.Set("Content-Type", "application/json") resp, err := http.DefaultClient.Do(req) if err != nil { return nil, diag.FromErr(err) } defer resp.Body.Close() if resp.StatusCode < 200 || resp.StatusCode >= 300 { b, _ := io.ReadAll(resp.Body) return nil, diag.Errorf("login failed: %s: %s", resp.Status, string(b)) } var lr loginResponse if err := json.NewDecoder(resp.Body).Decode(&lr); err != nil { return nil, diag.FromErr(err) } if lr.Token == "" { return nil, diag.Errorf("login succeeded but no token returned") } client.Token = lr.Token return client, nil }, } }