Skip to content

Commit

Permalink
adding in IAP Tunnel API to the beta provider (hashicorp#687)
Browse files Browse the repository at this point in the history
Signed-off-by: Modular Magician <[email protected]>
  • Loading branch information
modular-magician authored and rileykarson committed May 8, 2019
1 parent 11825db commit c45e5fe
Show file tree
Hide file tree
Showing 6 changed files with 561 additions and 0 deletions.
9 changes: 9 additions & 0 deletions google-beta/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ import (
file "google.golang.org/api/file/v1beta1"
"google.golang.org/api/iam/v1"
iamcredentials "google.golang.org/api/iamcredentials/v1"
iap "google.golang.org/api/iap/v1beta1"
cloudlogging "google.golang.org/api/logging/v2"
"google.golang.org/api/option"
"google.golang.org/api/pubsub/v1"
Expand Down Expand Up @@ -88,6 +89,7 @@ type Config struct {
clientStorage *storage.Service
clientSqlAdmin *sqladmin.Service
clientIAM *iam.Service
clientIAP *iap.Service
clientServiceMan *servicemanagement.APIService
clientServiceUsage *serviceusage.Service
clientBigQuery *bigquery.Service
Expand Down Expand Up @@ -254,6 +256,13 @@ func (c *Config) LoadAndValidate() error {
}
c.clientIamCredentials.UserAgent = userAgent

log.Printf("[INFO] Instantiating IAP Client...")
c.clientIAP, err = iap.NewService(context, option.WithHTTPClient(client))
if err != nil {
return err
}
c.clientIAP.UserAgent = userAgent

log.Printf("[INFO] Instantiating Google Cloud Service Management Client...")
c.clientServiceMan, err = servicemanagement.NewService(context, option.WithHTTPClient(client))
if err != nil {
Expand Down
189 changes: 189 additions & 0 deletions google-beta/iam_iap_tunnel_instance.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,189 @@
package google

import (
"fmt"
"strconv"
"strings"

"github.com/hashicorp/errwrap"
"github.com/hashicorp/terraform/helper/schema"
"google.golang.org/api/cloudresourcemanager/v1"
iap "google.golang.org/api/iap/v1beta1"
)

var IamIapTunnelInstanceSchema = map[string]*schema.Schema{
"instance": {
Type: schema.TypeString,
Required: true,
ForceNew: true,
},

"project": {
Type: schema.TypeString,
Optional: true,
Computed: true,
ForceNew: true,
},

"zone": {
Type: schema.TypeString,
Optional: true,
Computed: true,
ForceNew: true,
},
}

type IapTunnelInstanceIamUpdater struct {
project string
zone string
instance string
projectNumber string
Config *Config
}

func NewIapTunnelInstanceIamUpdater(d *schema.ResourceData, config *Config) (ResourceIamUpdater, error) {
project, err := getProject(d, config)
if err != nil {
return nil, err
}

res, err := config.clientResourceManager.Projects.Get(project).Do()
if err != nil {
return nil, err
}

//The IAP API currently doesn't work when using a projectId. When hitting the endpoint with a projectId instead
//of a projectNumber, the backend returns a 400 error, saying that it is an invalid argument. We abstract away
//this implementation detail from the consumer, and allow consumers to work with projectIds, which is consistent
//with other resources. However, that means we have to maintain/lookup the projectNumber from the projectID
//inside this provider plugin.
projectNumber := strconv.FormatInt(res.ProjectNumber, 10)

zone, err := getZone(d, config)
if err != nil {
return nil, err
}

return &IapTunnelInstanceIamUpdater{
project: project,
projectNumber: projectNumber,
zone: zone,
instance: d.Get("instance").(string),
Config: config,
}, nil
}

func IapTunnelInstanceIdParseFunc(d *schema.ResourceData, config *Config) error {
parts := strings.Split(d.Id(), "/")
var fv *ZonalFieldValue
if len(parts) == 3 {
// {project}/{zone}/{name} syntax
fv = &ZonalFieldValue{
Project: parts[0],
Zone: parts[1],
Name: parts[2],
resourceType: "instances",
}
} else if len(parts) == 2 {
// /{zone}/{name} syntax
project, err := getProject(d, config)
if err != nil {
return err
}
fv = &ZonalFieldValue{
Project: project,
Zone: parts[0],
Name: parts[1],
resourceType: "instances",
}
} else {
// We either have a name or a full self link, so use the field helper
var err error
fv, err = ParseInstanceFieldValue(d.Id(), d, config)
if err != nil {
return err
}
}

d.Set("project", fv.Project)
d.Set("zone", fv.Zone)
d.Set("instance", fv.Name)

res, err := config.clientResourceManager.Projects.Get(fv.Project).Do()
if err != nil {
return err
}

projectNumber := strconv.FormatInt(res.ProjectNumber, 10)

// Explicitly set the id so imported resources have the same ID format as non-imported ones.
d.SetId(fmt.Sprintf("projects/%s/iap_tunnel/zones/%s/instances/%s", projectNumber, fv.Zone, fv.Name))
return nil
}

func (u *IapTunnelInstanceIamUpdater) GetResourceIamPolicy() (*cloudresourcemanager.Policy, error) {
req := &iap.GetIamPolicyRequest{}

p, err := u.Config.clientIAP.V1beta1.GetIamPolicy(fmt.Sprintf("projects/%s/iap_tunnel/zones/%s/instances/%s", u.projectNumber, u.zone, u.instance), req).Do()

if err != nil {
return nil, errwrap.Wrapf(fmt.Sprintf("Error retrieving IAM policy for %s: {{err}}", u.DescribeResource()), err)
}

cloudResourcePolicy, err := iapToResourceManagerPolicy(p)

if err != nil {
return nil, errwrap.Wrapf(fmt.Sprintf("Invalid IAM policy for %s: {{err}}", u.DescribeResource()), err)
}

return cloudResourcePolicy, nil
}

func (u *IapTunnelInstanceIamUpdater) SetResourceIamPolicy(policy *cloudresourcemanager.Policy) error {
iapPolicy, err := resourceManagerToIapPolicy(policy)

if err != nil {
return errwrap.Wrapf(fmt.Sprintf("Invalid IAM policy for %s: {{err}}", u.DescribeResource()), err)
}

req := &iap.SetIamPolicyRequest{
Policy: iapPolicy,
}
_, err = u.Config.clientIAP.V1beta1.SetIamPolicy(fmt.Sprintf("projects/%s/iap_tunnel/zones/%s/instances/%s", u.projectNumber, u.zone, u.instance), req).Do()

if err != nil {
return errwrap.Wrapf(fmt.Sprintf("Error setting IAM policy for %s: {{err}}", u.DescribeResource()), err)
}

return nil
}

func (u *IapTunnelInstanceIamUpdater) GetResourceId() string {
return fmt.Sprintf("projects/%s/iap_tunnel/zones/%s/instances/%s", u.projectNumber, u.zone, u.instance)
}

func (u *IapTunnelInstanceIamUpdater) GetMutexKey() string {
return fmt.Sprintf("iap-tunnel-instance-%s-%s-%s", u.projectNumber, u.zone, u.instance)
}

func (u *IapTunnelInstanceIamUpdater) DescribeResource() string {
return fmt.Sprintf("IAP Tunnel Instance %s/%s/%s", u.projectNumber, u.zone, u.instance)
}

func resourceManagerToIapPolicy(p *cloudresourcemanager.Policy) (*iap.Policy, error) {
out := &iap.Policy{}
err := Convert(p, out)
if err != nil {
return nil, errwrap.Wrapf("Cannot convert a resourcemanager policy to am IAP policy: {{err}}", err)
}
return out, nil
}

func iapToResourceManagerPolicy(p *iap.Policy) (*cloudresourcemanager.Policy, error) {
out := &cloudresourcemanager.Policy{}
err := Convert(p, out)
if err != nil {
return nil, errwrap.Wrapf("Cannot convert an IAP policy to a resourcemanager policy: {{err}}", err)
}
return out, nil
}
3 changes: 3 additions & 0 deletions google-beta/provider.go
Original file line number Diff line number Diff line change
Expand Up @@ -208,6 +208,9 @@ func ResourceMapWithErrors() (map[string]*schema.Resource, error) {
"google_folder_iam_member": ResourceIamMemberWithImport(IamFolderSchema, NewFolderIamUpdater, FolderIdParseFunc),
"google_folder_iam_policy": ResourceIamPolicyWithImport(IamFolderSchema, NewFolderIamUpdater, FolderIdParseFunc),
"google_folder_organization_policy": resourceGoogleFolderOrganizationPolicy(),
"google_iap_tunnel_instance_iam_binding": ResourceIamBindingWithImport(IamIapTunnelInstanceSchema, NewIapTunnelInstanceIamUpdater, IapTunnelInstanceIdParseFunc),
"google_iap_tunnel_instance_iam_member": ResourceIamMemberWithImport(IamIapTunnelInstanceSchema, NewIapTunnelInstanceIamUpdater, IapTunnelInstanceIdParseFunc),
"google_iap_tunnel_instance_iam_policy": ResourceIamPolicyWithImport(IamIapTunnelInstanceSchema, NewIapTunnelInstanceIamUpdater, IapTunnelInstanceIdParseFunc),
"google_logging_billing_account_sink": resourceLoggingBillingAccountSink(),
"google_logging_billing_account_exclusion": ResourceLoggingExclusion(BillingAccountLoggingExclusionSchema, NewBillingAccountLoggingExclusionUpdater, billingAccountLoggingExclusionIdParseFunc),
"google_logging_metric": resourceLoggingMetric(),
Expand Down
Loading

0 comments on commit c45e5fe

Please sign in to comment.