Write a Google GCP client with Go
In this article I will explain the mechanics of writing a client for Google GCP, pretty similar like gcloud
.
The purpose is to not write a full-featured client (that would make no sense, since you can use gcloud
already) but to learn the how to communicate with Google’s GCP API using Go.
Such a pkg
can be useful in small projects where you need to talk to Google GCP API, like the OpenShift’s GCP Operator.
Writing a Kubernetes operator for Google GCP, you need to teach your controllers to do basic CRUD (Create, Read, Update, Destroy) operations on the Google cloud.
Having an individual project (like this one) it make your developer-life easier, since for testing your communication with Google, you wont have to setup any environment or CRDs.
Create the struct
First of all we need to create the struct that represents the type of our client.
Since we are going to interact with Google GCP cloud, pick a relevant name, for example we are going to name it GoogleGCPClient
.
Later we have to read how to setup authentication and authorization.
Authentication identifies who you are, and authorization determines what you can do. Grab a coffee and start reading this article
Create A Service Account
In the Cloud Console, go to the Create service account key page.
From the Service Account list, select New service account
In the Service account name field, enter a name.
From the Role list, select Project > Owner.
Click Create. A JSON file that contains your key downloads to your computer.
I have saved this file to my $HOME
directory and named it mypersonalgcpjsonkey.json
.
Pass the credentials
// Credentials
var projectID = "hidden-howl-252922" // Your ProjectID, replace it with yours
var jsonPath = filepath.Join(os.Getenv("HOME"), "mypersonalgcpjsonkey.json") // path to your JSON file, replace it with yours
Client for Cloud Resource Manager
The package cloudresourcemanager provides access to the (Cloud Resource Manager API)[https://cloud.google.com/resource-manager/docs]. It is used to create, read, and update metadata for Google Cloud Platform resource containers.
package main
import (
"context"
"log"
"os"
"path/filepath"
"google.golang.org/api/cloudresourcemanager/v1"
"google.golang.org/api/option"
)
// Credentials
var projectID = "hidden-howl-252922" // Your ProjectID
var jsonPath = filepath.Join(os.Getenv("HOME"), "mypersonalgcpjsonkey.json") // path to your JSON file
func main() {
ctx := context.Background()
cloudresourcemanagerService, err := cloudresourcemanager.NewService(ctx, option.WithCredentialsFile(jsonPath))
if err != nil {
log.Fatal(err)
}
log.Println(cloudresourcemanagerService.BasePath)
}
As a verification that our credentials work, this will print the following:
2020/03/12 23:38:57 https://cloudresourcemanager.googleapis.com/
Client for the IAM
IAM lets admins to authorize who can take actions on specific resources. The who part is obviously our ServiceAccount. The actions part, is a primitive role, the project’s Owner. For that we will use the iam package that provides access to the Identity and Access Management (IAM) API.
package main
import (
"context"
"log"
"os"
"path/filepath"
"google.golang.org/api/cloudresourcemanager/v1"
"google.golang.org/api/iam/v1"
"google.golang.org/api/option"
)
// Credentials
var projectID = "hidden-howl-252922" // Your ProjectID
var jsonPath = filepath.Join(os.Getenv("HOME"), "mypersonalgcpjsonkey.json") // path to your JSON file
func main() {
ctx := context.Background()
// Client for Cloud Resource Manager
cloudresourcemanagerService, err := cloudresourcemanager.NewService(ctx, option.WithCredentialsFile(jsonPath))
if err != nil {
log.Fatal(err)
}
log.Println(cloudresourcemanagerService.BasePath)
// Client for IAM
iamService, err := iam.NewService(ctx, option.WithCredentialsFile(jsonPath))
if err != nil {
log.Fatal(err)
}
log.Println(iamService.BasePath)
}
For verification purposes this is going to print:
2020/03/12 23:45:45 https://cloudresourcemanager.googleapis.com/
2020/03/12 23:45:45 https://iam.googleapis.com/
Client for Service Infrastructure Management
Service Infrastructure is Google’s foundational platform for creating, managing, and consuming APIs and services. It is used by Google APIs, Google Cloud APIs, and Cloud Endpoints. Service Infrastructure provides a wide range of features to service consumers and service producers, including authentication, authorization, auditing, rate limiting, billing, logging, and monitoring.
We are going to use the servicemanagement package which provides access to the Service Management API.
package main
import (
"context"
"log"
"os"
"path/filepath"
"google.golang.org/api/cloudresourcemanager/v1"
"google.golang.org/api/iam/v1"
"google.golang.org/api/option"
"google.golang.org/api/servicemanagement/v1"
)
// Credentials
var projectID = "hidden-howl-252922" // Your ProjectID
var jsonPath = filepath.Join(os.Getenv("HOME"), "mypersonalgcpjsonkey.json") // path to your JSON file
func main() {
ctx := context.Background()
// Client for Cloud Resource Manager
cloudresourcemanagerService, err := cloudresourcemanager.NewService(ctx, option.WithCredentialsFile(jsonPath))
if err != nil {
log.Fatal(err)
}
log.Println(cloudresourcemanagerService.BasePath)
// Client for IAM
iamService, err := iam.NewService(ctx, option.WithCredentialsFile(jsonPath))
if err != nil {
log.Fatal(err)
}
log.Println(iamService.BasePath)
// Client for Service Infrastructure Manager
servicemanagementService, err := servicemanagement.NewService(ctx, option.WithCredentialsFile(jsonPath))
if err != nil {
log.Fatal(err)
}
log.Println(servicemanagementService.BasePath)
}
For verification:
2020/03/12 23:53:11 https://cloudresourcemanager.googleapis.com/
2020/03/12 23:53:11 https://iam.googleapis.com/
2020/03/12 23:53:11 https://servicemanagement.googleapis.com/
Client for Cloud Billing
A Cloud Billing account defines who pays for a given set of Google Cloud resources, and you can link the account to one or more projects. Your project usage is charged to the linked Cloud Billing account. To use Google Cloud services, you must have a valid Cloud Billing account linked to your project. You must have a valid Cloud Billing account even if you are in your free trial period or if you choose to only use Google Cloud resources that are covered by the Always Free program.
We will use the cloudbilling package which provides access to the Cloud Billing API.
package main
import (
"context"
"log"
"os"
"path/filepath"
"google.golang.org/api/cloudbilling/v1"
"google.golang.org/api/cloudresourcemanager/v1"
"google.golang.org/api/iam/v1"
"google.golang.org/api/option"
"google.golang.org/api/servicemanagement/v1"
)
// Credentials
var projectID = "hidden-howl-252922" // Your ProjectID
var jsonPath = filepath.Join(os.Getenv("HOME"), "mypersonalgcpjsonkey.json") // path to your JSON file
func main() {
ctx := context.Background()
// Client for Cloud Resource Manager
cloudresourcemanagerService, err := cloudresourcemanager.NewService(ctx, option.WithCredentialsFile(jsonPath))
if err != nil {
log.Fatal(err)
}
log.Println(cloudresourcemanagerService.BasePath)
// Client for IAM
iamService, err := iam.NewService(ctx, option.WithCredentialsFile(jsonPath))
if err != nil {
log.Fatal(err)
}
log.Println(iamService.BasePath)
// Client for Service Infrastructure Manager
servicemanagementService, err := servicemanagement.NewService(ctx, option.WithCredentialsFile(jsonPath))
if err != nil {
log.Fatal(err)
}
log.Println(servicemanagementService.BasePath)
// Client for Cloud Billing
cloudbillingService, err := cloudbilling.NewService(ctx, option.WithCredentialsFile(jsonPath))
if err != nil {
log.Fatal(err)
}
log.Println(cloudbillingService.BasePath)
}
Client for Cloud DNS
The Google Cloud DNS is reliable, resilient and it provides low-latency DNS serving from Google’s worldwide network. You can publish your domain names by using Google’s infrastructure for production-quality, high-volume DNS services. Google’s global network of anycast name servers provide reliable, low-latency, authoritative name lookups for your domains from anywhere in the world.
For that we will use the dns package.
package main
import (
"context"
"log"
"os"
"path/filepath"
"google.golang.org/api/cloudbilling/v1"
"google.golang.org/api/cloudresourcemanager/v1"
"google.golang.org/api/dns/v1"
"google.golang.org/api/iam/v1"
"google.golang.org/api/option"
"google.golang.org/api/servicemanagement/v1"
)
// Credentials
var projectID = "hidden-howl-252922" // Your ProjectID
var jsonPath = filepath.Join(os.Getenv("HOME"), "mypersonalgcpjsonkey.json") // path to your JSON file
func main() {
ctx := context.Background()
// Client for Cloud Resource Manager
cloudresourcemanagerService, err := cloudresourcemanager.NewService(ctx, option.WithCredentialsFile(jsonPath))
if err != nil {
log.Fatal(err)
}
log.Println(cloudresourcemanagerService.BasePath)
// Client for IAM
iamService, err := iam.NewService(ctx, option.WithCredentialsFile(jsonPath))
if err != nil {
log.Fatal(err)
}
log.Println(iamService.BasePath)
// Client for Service Infrastructure Manager
servicemanagementService, err := servicemanagement.NewService(ctx, option.WithCredentialsFile(jsonPath))
if err != nil {
log.Fatal(err)
}
log.Println(servicemanagementService.BasePath)
// Client for Cloud Billing
cloudbillingService, err := cloudbilling.NewService(ctx, option.WithCredentialsFile(jsonPath))
if err != nil {
log.Fatal(err)
}
log.Println(cloudbillingService.BasePath)
// Client for Google Cloud DNS API
dnsService, err := dns.NewService(ctx, option.WithCredentialsFile(jsonPath))
if err != nil {
log.Fatal(err)
}
log.Println(dnsService.BasePath)
}
The output will be:
2020/03/13 00:30:17 https://cloudresourcemanager.googleapis.com/
2020/03/13 00:30:17 https://iam.googleapis.com/
2020/03/13 00:30:17 https://servicemanagement.googleapis.com/
2020/03/13 00:30:17 https://cloudbilling.googleapis.com/
2020/03/13 00:30:17 https://dns.googleapis.com/dns/v1/projects/
Create a wrapper for all of those clients
Our intention is to make the code cleaner and more concise. For that we will group all of those different clients into an object. Later we will create an instance of this object, so we can use it.
Create the struct
We will create a new client object for interacting with Google Cloud:
// GoogleCloudClient is a generic wrapper for talking with individual services inside Google Cloud
// such as Cloud Resource Manager, IAM, Services, Billing and DNS
type GoogleCloudClient struct {
// Structs from Google library
Resource *cloudresourcemanager.Service
IAM *iam.Service
Service *servicemanagement.APIService
Billing *cloudbilling.APIService
DNS *dns.Service
// Required user input
ProjectID string
JSONPath string
}
Create an instance
The preferred method is to use a factory function in order to ensure that the new instance of GoogleCloudClient
struct will be constructed with the required arguments.
The only input from the user is going to be the ProjectID
and the JSONPath
.
We want to give those arguments and take back a ready-to-use instance of GoogleCloudClient
.
To be more precise, we will return a pointer to the GoogleCloudClient
instance.
// NewGoogleCloudClient returns a pointer to the `GoogleCloudClient` instance
func NewGoogleCloudClient(projectID string, json string) (*GoogleCloudClient, error) {
ctx := context.Background()
// Client for Cloud Resource Manager
cloudresourcemanagerService, err := cloudresourcemanager.NewService(ctx, option.WithCredentialsFile(jsonPath))
if err != nil {
return nil, fmt.Errorf("Error with Cloud Resource Manager Service: %v", err)
}
// Client for IAM
iamService, err := iam.NewService(ctx, option.WithCredentialsFile(jsonPath))
if err != nil {
return nil, fmt.Errorf("Error with the IAM Service: %v", err)
}
// Client for Service Infrastructure Manager
servicemanagementService, err := servicemanagement.NewService(ctx, option.WithCredentialsFile(jsonPath))
if err != nil {
return nil, fmt.Errorf("Error with the Service Management Service: %v", err)
}
// Client for Cloud Billing
cloudbillingService, err := cloudbilling.NewService(ctx, option.WithCredentialsFile(jsonPath))
if err != nil {
return nil, fmt.Errorf("Error with the Cloud Billing Account: %v", err)
}
// Client for Google Cloud DNS API
dnsService, err := dns.NewService(ctx, option.WithCredentialsFile(jsonPath))
if err != nil {
return nil, fmt.Errorf("Error with the Cloud DNS: %v", err)
}
return &GoogleCloudClient{
Resource: cloudresourcemanagerService,
IAM: iamService,
Service: servicemanagementService,
Billing: cloudbillingService,
DNS: dnsService,
ProjectID: projectID,
JSONPath: json,
}, nil
}
Use the instance
package main
import (
"context"
"fmt"
"log"
"os"
"path/filepath"
"google.golang.org/api/cloudbilling/v1"
"google.golang.org/api/cloudresourcemanager/v1"
"google.golang.org/api/dns/v1"
"google.golang.org/api/iam/v1"
"google.golang.org/api/option"
"google.golang.org/api/servicemanagement/v1"
)
// Credentials
var projectID = "hidden-howl-252922" // Your ProjectID
var jsonPath = filepath.Join(os.Getenv("HOME"), "mypersonalgcpjsonkey.json") // path to your JSON file
// GoogleCloudClient is a generic wrapper for talking with individual services inside Google Cloud
// such as Cloud Resource Manager, IAM, Services, Billing and DNS
type GoogleCloudClient struct {
// Structs from Google library
Resource *cloudresourcemanager.Service
IAM *iam.Service
Service *servicemanagement.APIService
Billing *cloudbilling.APIService
DNS *dns.Service
// Required user input
ProjectID string
JSONPath string
}
// NewGoogleCloudClient returns a pointer to the `GoogleCloudClient` instance
func NewGoogleCloudClient(projectID string, json string) (*GoogleCloudClient, error) {
ctx := context.Background()
// Client for Cloud Resource Manager
cloudresourcemanagerService, err := cloudresourcemanager.NewService(ctx, option.WithCredentialsFile(jsonPath))
if err != nil {
return nil, fmt.Errorf("Error with Cloud Resource Manager Service: %v", err)
}
// Client for IAM
iamService, err := iam.NewService(ctx, option.WithCredentialsFile(jsonPath))
if err != nil {
return nil, fmt.Errorf("Error with the IAM Service: %v", err)
}
// Client for Service Infrastructure Manager
servicemanagementService, err := servicemanagement.NewService(ctx, option.WithCredentialsFile(jsonPath))
if err != nil {
return nil, fmt.Errorf("Error with the Service Management Service: %v", err)
}
// Client for Cloud Billing
cloudbillingService, err := cloudbilling.NewService(ctx, option.WithCredentialsFile(jsonPath))
if err != nil {
return nil, fmt.Errorf("Error with the Cloud Billing Account: %v", err)
}
// Client for Google Cloud DNS API
dnsService, err := dns.NewService(ctx, option.WithCredentialsFile(jsonPath))
if err != nil {
return nil, fmt.Errorf("Error with the Cloud DNS: %v", err)
}
return &GoogleCloudClient{
Resource: cloudresourcemanagerService,
IAM: iamService,
Service: servicemanagementService,
Billing: cloudbillingService,
DNS: dnsService,
ProjectID: projectID,
JSONPath: json,
}, nil
}
func main() {
gcpClient, err := NewGoogleCloudClient(projectID, jsonPath)
if err != nil {
log.Fatal(err)
}
fmt.Println(gcpClient.Resource.BasePath)
fmt.Println(gcpClient.IAM.BasePath)
fmt.Println(gcpClient.Service.BasePath)
fmt.Println(gcpClient.Billing.BasePath)
fmt.Println(gcpClient.DNS.BasePath)
}
The output for verification should be:
https://cloudresourcemanager.googleapis.com/
https://iam.googleapis.com/
https://servicemanagement.googleapis.com/
https://cloudbilling.googleapis.com/
https://dns.googleapis.com/dns/v1/projects/
Do stuff with the Cloud Resource Manager
That it is. Now you have established a secure connection with Google GCP and you can start using its API. I will show you some basic examples, so you can get an idea.
List Projects
Read: Method: projects.list
You need to have Cloud Resource Manager API in your project. To do that:
- Go to the webpage that says Cloud Resource Manager API
- Click Enable.
- Wait a little bit to get it enabled.
We will use the function *cloudresourcemanager.Service.Projects.List().Do()
which returns two things:
*cloudresourcemanager.ListProjectsResponse
error
So what is this *cloudresourcemanager.ListProjectsResponse
?
This is a pointer to a struct ListProjectsResponse
that looks like this:
type ListProjectsResponse struct {
// Pagination tokens have a limited lifetime.
NextPageToken string `json:"nextPageToken,omitempty"`
// Projects: The list of Projects that matched the list filter. This list can be paginated.
Projects []*Project `json:"projects,omitempty"`
// ServerResponse contains the HTTP response code and headers from the server.
googleapi.ServerResponse `json:"-"`
/// and others
We are interested into the Projects
field which is a list of another struct called Project
which looks like this:
type Project struct {
CreateTime string `json:"createTime,omitempty"`
Labels map[string]string `json:"labels,omitempty"`
LifecycleState string `json:"lifecycleState,omitempty"`
Name string `json:"name,omitempty"`
Parent *ResourceId `json:"parent,omitempty"`
ProjectId string `json:"projectId,omitempty"`
ProjectNumber int64 `json:"projectNumber,omitempty,string"`
googleapi.ServerResponse `json:"-"`
ForceSendFields []string `json:"-"`
NullFields []string `json:"-"`
}
To keep it simple, we are interested particularly for the Name
and the ProjectID
.
// Fetch ListProjectsResponse
projectsList, err := gcpClient.Resource.Projects.List().Do()
if err != nil {
log.Fatal(err)
}
// From every Project of the ListProjectsResponse print the Name and the ProjectID
for _, value := range projectsList.Projects {
fmt.Printf("Project Name: %s\tProjectID: %s\r\n", value.Name, value.ProjectId)
}
The output is:
Project Name: My First Project ProjectID: hidden-howl-252922
Make a method
package main
import (
"context"
"fmt"
"log"
"os"
"path/filepath"
"google.golang.org/api/cloudbilling/v1"
"google.golang.org/api/cloudresourcemanager/v1"
"google.golang.org/api/dns/v1"
"google.golang.org/api/iam/v1"
"google.golang.org/api/option"
"google.golang.org/api/servicemanagement/v1"
)
// Credentials
var projectID = "hidden-howl-252922" // Your ProjectID
var jsonPath = filepath.Join(os.Getenv("HOME"), "mypersonalgcpjsonkey.json") // path to your JSON file
// GoogleCloudClient is a generic wrapper for talking with individual services inside Google Cloud
// such as Cloud Resource Manager, IAM, Services, Billing and DNS
type GoogleCloudClient struct {
// Structs from Google library
Resource *cloudresourcemanager.Service
IAM *iam.Service
Service *servicemanagement.APIService
Billing *cloudbilling.APIService
DNS *dns.Service
// Required user input
ProjectID string
JSONPath string
}
// NewGoogleCloudClient returns a pointer to the `GoogleCloudClient` instance
func NewGoogleCloudClient(projectID string, json string) (*GoogleCloudClient, error) {
ctx := context.Background()
// Client for Cloud Resource Manager
cloudresourcemanagerService, err := cloudresourcemanager.NewService(ctx, option.WithCredentialsFile(jsonPath))
if err != nil {
return nil, fmt.Errorf("Error with Cloud Resource Manager Service: %v", err)
}
// Client for IAM
iamService, err := iam.NewService(ctx, option.WithCredentialsFile(jsonPath))
if err != nil {
return nil, fmt.Errorf("Error with the IAM Service: %v", err)
}
// Client for Service Infrastructure Manager
servicemanagementService, err := servicemanagement.NewService(ctx, option.WithCredentialsFile(jsonPath))
if err != nil {
return nil, fmt.Errorf("Error with the Service Management Service: %v", err)
}
// Client for Cloud Billing
cloudbillingService, err := cloudbilling.NewService(ctx, option.WithCredentialsFile(jsonPath))
if err != nil {
return nil, fmt.Errorf("Error with the Cloud Billing Account: %v", err)
}
// Client for Google Cloud DNS API
dnsService, err := dns.NewService(ctx, option.WithCredentialsFile(jsonPath))
if err != nil {
return nil, fmt.Errorf("Error with the Cloud DNS: %v", err)
}
return &GoogleCloudClient{
Resource: cloudresourcemanagerService,
IAM: iamService,
Service: servicemanagementService,
Billing: cloudbillingService,
DNS: dnsService,
ProjectID: projectID,
JSONPath: json,
}, nil
}
// ListProjects lists the Projects of a GCP service account and returns an error
func (c *GoogleCloudClient) ListProjects() (*cloudresourcemanager.ListProjectsResponse, error) {
projectsList, err := c.Resource.Projects.List().Do()
if err != nil {
return nil, err
}
return projectsList, nil
}
func main() {
gcpClient, err := NewGoogleCloudClient(projectID, jsonPath)
if err != nil {
log.Fatal(err)
}
fmt.Println(gcpClient.Resource.BasePath)
fmt.Println(gcpClient.IAM.BasePath)
fmt.Println(gcpClient.Service.BasePath)
fmt.Println(gcpClient.Billing.BasePath)
fmt.Println(gcpClient.DNS.BasePath)
resp, err := gcpClient.ListProjects()
if err != nil {
log.Fatal(err)
}
for _, project := range resp.Projects {
fmt.Printf("Project Name: %s\tProjectID: %s\r\n", project.Name, project.ProjectId)
}
}
Output:
Project Name: My First Project ProjectID: hidden-howl-252922
Get a Project
Now that you can list the projects, you can also get
one.
Storing a project into a variable, you can later use the .
to access attributed of that project.
package main
import (
"context"
"fmt"
"log"
"os"
"path/filepath"
"google.golang.org/api/cloudbilling/v1"
"google.golang.org/api/cloudresourcemanager/v1"
"google.golang.org/api/dns/v1"
"google.golang.org/api/iam/v1"
"google.golang.org/api/option"
"google.golang.org/api/servicemanagement/v1"
)
// Credentials
var projectID = "hidden-howl-252922" // Your ProjectID
var jsonPath = filepath.Join(os.Getenv("HOME"), "mypersonalgcpjsonkey.json") // path to your JSON file
// GoogleCloudClient is a generic wrapper for talking with individual services inside Google Cloud
// such as Cloud Resource Manager, IAM, Services, Billing and DNS
type GoogleCloudClient struct {
// Structs from Google library
Resource *cloudresourcemanager.Service
IAM *iam.Service
Service *servicemanagement.APIService
Billing *cloudbilling.APIService
DNS *dns.Service
// Required user input
ProjectID string
JSONPath string
}
// NewGoogleCloudClient returns a pointer to the `GoogleCloudClient` instance
func NewGoogleCloudClient(projectID string, json string) (*GoogleCloudClient, error) {
ctx := context.Background()
// Client for Cloud Resource Manager
cloudresourcemanagerService, err := cloudresourcemanager.NewService(ctx, option.WithCredentialsFile(jsonPath))
if err != nil {
return nil, fmt.Errorf("Error with Cloud Resource Manager Service: %v", err)
}
// Client for IAM
iamService, err := iam.NewService(ctx, option.WithCredentialsFile(jsonPath))
if err != nil {
return nil, fmt.Errorf("Error with the IAM Service: %v", err)
}
// Client for Service Infrastructure Manager
servicemanagementService, err := servicemanagement.NewService(ctx, option.WithCredentialsFile(jsonPath))
if err != nil {
return nil, fmt.Errorf("Error with the Service Management Service: %v", err)
}
// Client for Cloud Billing
cloudbillingService, err := cloudbilling.NewService(ctx, option.WithCredentialsFile(jsonPath))
if err != nil {
return nil, fmt.Errorf("Error with the Cloud Billing Account: %v", err)
}
// Client for Google Cloud DNS API
dnsService, err := dns.NewService(ctx, option.WithCredentialsFile(jsonPath))
if err != nil {
return nil, fmt.Errorf("Error with the Cloud DNS: %v", err)
}
return &GoogleCloudClient{
Resource: cloudresourcemanagerService,
IAM: iamService,
Service: servicemanagementService,
Billing: cloudbillingService,
DNS: dnsService,
ProjectID: projectID,
JSONPath: json,
}, nil
}
// ListProjects lists the Projects of a GCP service account and returns an error
func (c *GoogleCloudClient) ListProjects() (*cloudresourcemanager.ListProjectsResponse, error) {
projectsList, err := c.Resource.Projects.List().Do()
if err != nil {
return nil, err
}
return projectsList, nil
}
// GetProject returns a project from GCP
func (c *GoogleCloudClient) GetProject(projectID string) (*cloudresourcemanager.Project, error) {
project, err := c.Resource.Projects.Get(projectID).Do()
if err != nil {
return nil, err
}
return project, nil
}
func main() {
gcpClient, err := NewGoogleCloudClient(projectID, jsonPath)
if err != nil {
log.Fatal(err)
}
fmt.Println(gcpClient.Resource.BasePath)
fmt.Println(gcpClient.IAM.BasePath)
fmt.Println(gcpClient.Service.BasePath)
fmt.Println(gcpClient.Billing.BasePath)
fmt.Println(gcpClient.DNS.BasePath)
resp, err := gcpClient.ListProjects()
if err != nil {
log.Fatal(err)
}
for _, project := range resp.Projects {
fmt.Printf("Project Name: %s\tProjectID: %s\r\n", project.Name, project.ProjectId)
}
// gcpClient.Resource.Projects.Delete("hidden-howl-252922")
resp1, err := gcpClient.GetProject("hidden-howl-252922")
if err != nil {
log.Fatal(err)
}
fmt.Println(resp1.Name)
}
Delete a Project
package main
import (
"context"
"fmt"
"log"
"os"
"path/filepath"
"google.golang.org/api/cloudbilling/v1"
"google.golang.org/api/cloudresourcemanager/v1"
"google.golang.org/api/dns/v1"
"google.golang.org/api/iam/v1"
"google.golang.org/api/option"
"google.golang.org/api/servicemanagement/v1"
)
// Credentials
var projectID = "hidden-howl-252922" // Your ProjectID
var jsonPath = filepath.Join(os.Getenv("HOME"), "mypersonalgcpjsonkey.json") // path to your JSON file
// GoogleCloudClient is a generic wrapper for talking with individual services inside Google Cloud
// such as Cloud Resource Manager, IAM, Services, Billing and DNS
type GoogleCloudClient struct {
// Structs from Google library
Resource *cloudresourcemanager.Service
IAM *iam.Service
Service *servicemanagement.APIService
Billing *cloudbilling.APIService
DNS *dns.Service
// Required user input
ProjectID string
JSONPath string
}
// NewGoogleCloudClient returns a pointer to the `GoogleCloudClient` instance
func NewGoogleCloudClient(projectID string, json string) (*GoogleCloudClient, error) {
ctx := context.Background()
// Client for Cloud Resource Manager
cloudresourcemanagerService, err := cloudresourcemanager.NewService(ctx, option.WithCredentialsFile(jsonPath))
if err != nil {
return nil, fmt.Errorf("Error with Cloud Resource Manager Service: %v", err)
}
// Client for IAM
iamService, err := iam.NewService(ctx, option.WithCredentialsFile(jsonPath))
if err != nil {
return nil, fmt.Errorf("Error with the IAM Service: %v", err)
}
// Client for Service Infrastructure Manager
servicemanagementService, err := servicemanagement.NewService(ctx, option.WithCredentialsFile(jsonPath))
if err != nil {
return nil, fmt.Errorf("Error with the Service Management Service: %v", err)
}
// Client for Cloud Billing
cloudbillingService, err := cloudbilling.NewService(ctx, option.WithCredentialsFile(jsonPath))
if err != nil {
return nil, fmt.Errorf("Error with the Cloud Billing Account: %v", err)
}
// Client for Google Cloud DNS API
dnsService, err := dns.NewService(ctx, option.WithCredentialsFile(jsonPath))
if err != nil {
return nil, fmt.Errorf("Error with the Cloud DNS: %v", err)
}
return &GoogleCloudClient{
Resource: cloudresourcemanagerService,
IAM: iamService,
Service: servicemanagementService,
Billing: cloudbillingService,
DNS: dnsService,
ProjectID: projectID,
JSONPath: json,
}, nil
}
// ListProjects lists the Projects of a GCP service account and returns an error
func (c *GoogleCloudClient) ListProjects() (*cloudresourcemanager.ListProjectsResponse, error) {
projectsList, err := c.Resource.Projects.List().Do()
if err != nil {
return nil, err
}
return projectsList, nil
}
// GetProject returns a project from GCP
func (c *GoogleCloudClient) GetProject(projectID string) (*cloudresourcemanager.Project, error) {
project, err := c.Resource.Projects.Get(projectID).Do()
if err != nil {
return nil, err
}
return project, nil
}
// DeleteProject deletes a project from GCP
func (c *GoogleCloudClient) DeleteProject(projectID string) (*cloudresourcemanager.Empty, error) {
project, err := c.Resource.Projects.Delete(projectID).Do()
if err != nil {
return nil, err
}
return project, nil
}
func main() {
gcpClient, err := NewGoogleCloudClient(projectID, jsonPath)
if err != nil {
log.Fatal(err)
}
fmt.Println(gcpClient.Resource.BasePath)
fmt.Println(gcpClient.IAM.BasePath)
fmt.Println(gcpClient.Service.BasePath)
fmt.Println(gcpClient.Billing.BasePath)
fmt.Println(gcpClient.DNS.BasePath)
// Get a List of Projects
resp, err := gcpClient.ListProjects()
if err != nil {
log.Fatal(err)
}
for _, project := range resp.Projects {
fmt.Printf("Project Name: %s\tProjectID: %s\r\n", project.Name, project.ProjectId)
}
// Get a Project
resp1, err := gcpClient.GetProject("hidden-howl-252922")
if err != nil {
log.Fatal(err)
}
// Use the . to access the attributes of this project
fmt.Println(resp1.Name)
fmt.Printf("The lifecycle state of %s project is %s:", resp1.Name, resp1.LifecycleState)
// Delete a Project
resp2, err := gcpClient.DeleteProject("hidden-howl-252922")
if err != nil {
log.Fatal(err)
}
fmt.Println(resp2.ServerResponse)
}