tools/ipam-autopilot/provider/ipam/resources/resource_ip_range.go (214 lines of code) (raw):
// Copyright 2021 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package resources
import (
"bytes"
"context"
"encoding/json"
"fmt"
"io/ioutil"
"net/http"
"os"
"github.com/GoogleCloudPlatform/professional-services/terraform-provider-ipam-autopilot/ipam/config"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
"golang.org/x/oauth2/google"
"google.golang.org/api/idtoken"
)
func ResourceIpRange() *schema.Resource {
return &schema.Resource{
Create: resourceCreate,
Read: resourceRead,
//Update: resourceUpdate,
Delete: resourceDelete,
Schema: map[string]*schema.Schema{
"name": {
Type: schema.TypeString,
Required: true,
ForceNew: true,
},
"range_size": {
Type: schema.TypeInt,
Required: true,
ForceNew: true,
},
"parent": {
Type: schema.TypeString,
Optional: true,
ForceNew: true,
},
"domain": {
Type: schema.TypeString,
Optional: true,
ForceNew: true,
},
"cidr": {
Type: schema.TypeString,
Optional: true,
Computed: true,
ForceNew: true,
},
},
}
}
func resourceCreate(d *schema.ResourceData, meta interface{}) error {
config := meta.(config.Config)
range_size := d.Get("range_size").(int)
parent := d.Get("parent").(string)
name := d.Get("name").(string)
domain := d.Get("domain").(string)
cidr := d.Get("cidr").(string)
url := fmt.Sprintf("%s/ranges", config.Url)
var postBody []byte
var err error
if parent == "" {
postBody, err = json.Marshal(map[string]interface{}{
"range_size": range_size,
"name": name,
"domain": domain,
"cidr": cidr,
})
if err != nil {
return fmt.Errorf("failed marshalling json: %v", err)
}
} else {
postBody, err = json.Marshal(map[string]interface{}{
"range_size": range_size,
"name": name,
"domain": domain,
"parent": parent,
"cidr": cidr,
})
if err != nil {
return fmt.Errorf("failed marshalling json: %v", err)
}
}
fmt.Printf("%s", string(postBody))
responseBody := bytes.NewBuffer(postBody)
accessToken, err := getIdentityToken()
if err != nil {
return fmt.Errorf("unable to retrieve access token: %v", err)
}
req, err := http.NewRequest("POST", url, responseBody)
if err != nil {
return fmt.Errorf("failed creating request: %v", err)
}
req.Header.Set("Authorization", fmt.Sprintf("Bearer %s", accessToken))
req.Header.Set("Content-Type", "application/json")
client := &http.Client{}
resp, err := client.Do(req)
if err != nil {
return fmt.Errorf("failed creating range: %v", err)
}
defer resp.Body.Close()
if resp.StatusCode == 200 {
body, err := ioutil.ReadAll(resp.Body)
if err != nil {
return fmt.Errorf("unable to read response: %v", err)
}
response := map[string]interface{}{}
err = json.Unmarshal(body, &response)
if err != nil {
return fmt.Errorf("unable to unmarshal response body: %v", err)
}
d.SetId(fmt.Sprintf("%d", int(response["id"].(float64))))
d.Set("cidr", response["cidr"].(string))
return nil
} else {
body, err := ioutil.ReadAll(resp.Body)
if err != nil {
return fmt.Errorf("failed creating range status_code=%d, status=%s", resp.StatusCode, resp.Status)
}
return fmt.Errorf("failed creating range status_code=%d, status=%s,body=%s", resp.StatusCode, resp.Status, string(body))
}
}
func resourceRead(d *schema.ResourceData, meta interface{}) error {
config := meta.(config.Config)
url := fmt.Sprintf("%s/ranges/%s", config.Url, d.Id())
req, err := http.NewRequest("GET", url, nil)
if err != nil {
return fmt.Errorf("failed creating request: %v", err)
}
accessToken, err := getIdentityToken()
if err != nil {
return fmt.Errorf("unable to retrieve access token: %v", err)
}
req.Header.Set("Authorization", fmt.Sprintf("Bearer %s", accessToken))
client := &http.Client{}
resp, err := client.Do(req)
if err != nil {
return fmt.Errorf("failed querying range: %v", err)
}
defer resp.Body.Close()
if resp.StatusCode == 200 {
body, err := ioutil.ReadAll(resp.Body)
if err != nil {
return fmt.Errorf("unable to read response: %v", err)
}
response := map[string]interface{}{}
err = json.Unmarshal(body, &response)
if err != nil {
return fmt.Errorf("unable to unmarshal response body: %v", err)
}
d.SetId(fmt.Sprintf("%d", int(response["id"].(float64))))
d.Set("cidr", response["cidr"].(string))
return nil
} else {
body, err := ioutil.ReadAll(resp.Body)
if err != nil {
return fmt.Errorf("failed reading range status_code=%d, status=%s", resp.StatusCode, resp.Status)
}
return fmt.Errorf("failed reading range status_code=%d, status=%s,body=%s", resp.StatusCode, resp.Status, string(body))
}
}
func resourceDelete(d *schema.ResourceData, meta interface{}) error {
config := meta.(config.Config)
url := fmt.Sprintf("%s/ranges/%s", config.Url, d.Id())
client := &http.Client{}
req, err := http.NewRequest("DELETE", url, nil)
if err != nil {
return fmt.Errorf("failed creating release request: %v", err)
}
accessToken, err := getIdentityToken()
if err != nil {
return fmt.Errorf("unable to retrieve access token: %v", err)
}
req.Header.Set("Authorization", fmt.Sprintf("Bearer %s", accessToken))
resp, err := client.Do(req)
if err != nil {
return fmt.Errorf("failed releasing range: %v", err)
}
if resp.StatusCode == 200 {
return nil
} else {
body, err := ioutil.ReadAll(resp.Body)
if err != nil {
return fmt.Errorf("failed releasing range status_code=%d, status=%s", resp.StatusCode, resp.Status)
}
return fmt.Errorf("failed releasing range status_code=%d, status=%s,body=%s", resp.StatusCode, resp.Status, string(body))
}
}
func getIdentityToken() (string, error) {
if os.Getenv("GCP_IDENTITY_TOKEN") != "" {
return os.Getenv("GCP_IDENTITY_TOKEN"), nil
}
ctx := context.Background()
audience := "http://ipam-autopilot.com"
ts, err := idtoken.NewTokenSource(ctx, audience)
if err != nil {
if err.Error() != `idtoken: credential must be service_account, found "authorized_user"` {
return "", err
}
gts, err := google.DefaultTokenSource(ctx)
if err != nil {
return "", err
}
token, err := gts.Token()
if err != nil {
return "", err
}
identityToken := token.Extra("id_token").(string)
return identityToken, nil
}
token, err := ts.Token()
if err != nil {
return "", err
}
return token.AccessToken, nil
}