reference-architectures/cloud_deploy_flow/CloudFunctions/cloudDeployInteractions/main.go (99 lines of code) (raw):
package example
import (
"context"
"encoding/json"
"fmt"
"log"
deploy "cloud.google.com/go/deploy/apiv1"
"cloud.google.com/go/deploy/apiv1/deploypb"
"github.com/GoogleCloudPlatform/functions-framework-go/functions"
"github.com/cloudevents/sdk-go/v2/event"
"google.golang.org/api/option"
)
// init registers the cloudDeployInteractions function as an event listener
// for cloud events with the name "cloudDeployInteractions".
func init() {
functions.CloudEvent("cloudDeployInteractions", cloudDeployInteractions)
}
// PubSubMessage defines the structure for the Pub/Sub message data payload.
type PubSubMessage struct {
Data []byte `json:"data"`
}
// MessagePublishedData represents the message structure when received from Pub/Sub.
type MessagePublishedData struct {
Message PubSubMessage
}
// DeployCommand represents the deployment command types with their corresponding
// Cloud Deploy request data structures.
type DeployCommand struct {
Commmand string `json:"command"` // Command type: CreateRelease, CreateRollout, or ApproveRollout
CreateRelease deploypb.CreateReleaseRequest `json:"createReleaseRequest"` // Data required to create a release
CreateRollout deploypb.CreateRolloutRequest `json:"createRolloutRequest"` // Data required to create a rollout
ApproveRollout deploypb.ApproveRolloutRequest `json:"approveRolloutRequest"` // Data required to approve a rollout
}
// cloudDeployInteractions is the main function that handles cloud events and
// processes deployment commands based on incoming Pub/Sub messages.
func cloudDeployInteractions(ctx context.Context, e event.Event) error {
log.Printf("Deploy trigger function invoked")
// Parse the Pub/Sub message into MessagePublishedData structure
var msg MessagePublishedData
if err := e.DataAs(&msg); err != nil {
return fmt.Errorf("event.DataAs: %w", err)
}
// Unmarshal the Pub/Sub message data into the DeployCommand structure
log.Printf("Converting Byte to Struct Object")
var c DeployCommand
if err := json.Unmarshal(msg.Message.Data, &c); err != nil {
log.Printf("Failed to unmarshal to command, assuming bad command")
return nil // Returning nil acknowledges the message, preventing reprocessing
}
// Create a new Cloud Deploy client to interact with Cloud Deploy services
deployClient, err := deploy.NewCloudDeployClient(ctx,
option.WithUserAgent("cloud-solutions/platform-engineering-cloud-deploy-pipeline-code-v1"),
)
if err != nil {
return fmt.Errorf("error creating Cloud Deploy client: %v", err)
}
defer deployClient.Close() // Ensure client is closed after function completes
// Process the command based on its type (CreateRelease, CreateRollout, or ApproveRollout)
switch c.Commmand {
case "CreateRelease":
if err := cdCreateRelease(ctx, *deployClient, &c.CreateRelease); err != nil {
_ = fmt.Errorf("create release failed: %v", err)
return nil
}
case "CreateRollout":
if err := cdCreateRollout(ctx, *deployClient, &c.CreateRollout); err != nil {
_ = fmt.Errorf("create rollout failed: %v", err)
return nil
}
case "ApproveRollout":
if err := cdApproveRollout(ctx, *deployClient, &c.ApproveRollout); err != nil {
_ = fmt.Errorf("approve rollout failed: %v", err)
return nil
}
}
return nil
}
// cdCreateRelease sends a request to Google Cloud Deploy to create a new release
func cdCreateRelease(ctx context.Context, d deploy.CloudDeployClient, c *deploypb.CreateReleaseRequest) error {
// Initiate the release creation operation
releaseOp, err := d.CreateRelease(ctx, c)
if err != nil {
return fmt.Errorf("error creating release request: %v", err)
}
log.Printf("Created release operation: %s", releaseOp.Name())
// Wait for the release operation to complete and check for errors
_, err = releaseOp.Wait(ctx)
if err != nil {
return fmt.Errorf("error on release operation: %v", err)
}
log.Printf("Create Release Operation Completed")
return nil
}
// cdCreateRollout sends a request to Google Cloud Deploy to create a rollout for a release
func cdCreateRollout(ctx context.Context, d deploy.CloudDeployClient, c *deploypb.CreateRolloutRequest) error {
// Initiate the rollout creation operation
rollout, err := d.CreateRollout(ctx, c)
if err != nil {
return fmt.Errorf("error creating rollout request: %v", err)
}
log.Printf("Created Rollout Request: %v", rollout.Name())
// Wait for the rollout operation to complete and check for errors
_, err = rollout.Wait(ctx)
if err != nil {
return fmt.Errorf("error on rollout operation: %v", err)
}
log.Printf("Create Rollout Operation Completed")
return nil
}
// cdApproveRollout sends a request to Google Cloud Deploy to approve an existing rollout
func cdApproveRollout(ctx context.Context, d deploy.CloudDeployClient, c *deploypb.ApproveRolloutRequest) error {
// Approve the rollout using the Cloud Deploy client
_, err := d.ApproveRollout(ctx, c)
if err != nil {
return fmt.Errorf("error approving rollout request operation: %v", err)
}
log.Printf("Approved Rollout")
return nil
}