@@ -31,6 +31,7 @@ import (
3131 "sync/atomic"
3232 "time"
3333
34+ "go.temporal.io/api/cloud/cloudservice/v1"
3435 commonpb "go.temporal.io/api/common/v1"
3536 enumspb "go.temporal.io/api/enums/v1"
3637 "go.temporal.io/api/operatorservice/v1"
@@ -489,6 +490,48 @@ type (
489490 DisableErrorCodeMetricTags bool
490491 }
491492
493+ CloudOperationsClient interface {
494+ CloudService () cloudservice.CloudServiceClient
495+ Close ()
496+ }
497+
498+ // CloudOperationsClientOptions are parameters for CloudOperationsClient creation.
499+ //
500+ // WARNING: Cloud operations client is currently experimental.
501+ CloudOperationsClientOptions struct {
502+ // Optional: The credentials for this client. This is essentially required.
503+ // See [go.temporal.io/sdk/client.NewAPIKeyStaticCredentials],
504+ // [go.temporal.io/sdk/client.NewAPIKeyDynamicCredentials], and
505+ // [go.temporal.io/sdk/client.NewMTLSCredentials].
506+ // Default: No credentials.
507+ Credentials Credentials
508+
509+ // Optional: Version header for safer mutations. May or may not be required
510+ // depending on cloud settings.
511+ // Default: No header.
512+ Version string
513+
514+ // Optional: Advanced server connection options such as TLS settings. Not
515+ // usually needed.
516+ ConnectionOptions ConnectionOptions
517+
518+ // Optional: Logger framework can use to log.
519+ // Default: Default logger provided.
520+ Logger log.Logger
521+
522+ // Optional: Metrics handler for reporting metrics.
523+ // Default: No metrics
524+ MetricsHandler metrics.Handler
525+
526+ // Optional: Overrides the specific host to connect to. Not usually needed.
527+ // Default: saas-api.tmprl.cloud:443
528+ HostPort string
529+
530+ // Optional: Disable TLS.
531+ // Default: false (i.e. TLS enabled)
532+ DisableTLS bool
533+ }
534+
492535 // HeadersProvider returns a map of gRPC headers that should be used on every request.
493536 HeadersProvider interface {
494537 GetHeaders (ctx context.Context ) (map [string ]string , error )
@@ -728,7 +771,7 @@ type (
728771
729772// Credentials are optional credentials that can be specified in ClientOptions.
730773type Credentials interface {
731- applyToOptions (* ClientOptions ) error
774+ applyToOptions (* ConnectionOptions ) error
732775 // Can return nil to have no interceptor
733776 gRPCInterceptor () grpc.UnaryClientInterceptor
734777}
@@ -783,7 +826,7 @@ func newClient(ctx context.Context, options ClientOptions, existing *WorkflowCli
783826 }
784827
785828 if options .Credentials != nil {
786- if err := options .Credentials .applyToOptions (& options ); err != nil {
829+ if err := options .Credentials .applyToOptions (& options . ConnectionOptions ); err != nil {
787830 return nil , err
788831 }
789832 }
@@ -897,6 +940,59 @@ func NewServiceClient(workflowServiceClient workflowservice.WorkflowServiceClien
897940 return client
898941}
899942
943+ // DialCloudOperationsClient creates a cloud client to perform cloud-management
944+ // operations.
945+ func DialCloudOperationsClient (ctx context.Context , options CloudOperationsClientOptions ) (CloudOperationsClient , error ) {
946+ // Set defaults
947+ if options .MetricsHandler == nil {
948+ options .MetricsHandler = metrics .NopHandler
949+ }
950+ if options .Logger == nil {
951+ options .Logger = ilog .NewDefaultLogger ()
952+ }
953+ if options .HostPort == "" {
954+ options .HostPort = "saas-api.tmprl.cloud:443"
955+ }
956+ if options .Version != "" {
957+ options .ConnectionOptions .DialOptions = append (
958+ options .ConnectionOptions .DialOptions ,
959+ grpc .WithChainUnaryInterceptor (func (
960+ ctx context.Context , method string , req , reply any ,
961+ cc * grpc.ClientConn , invoker grpc.UnaryInvoker , opts ... grpc.CallOption ,
962+ ) error {
963+ ctx = metadata .AppendToOutgoingContext (ctx , "temporal-cloud-api-version" , options .Version )
964+ return invoker (ctx , method , req , reply , cc , opts ... )
965+ }),
966+ )
967+ }
968+ if options .Credentials != nil {
969+ if err := options .Credentials .applyToOptions (& options .ConnectionOptions ); err != nil {
970+ return nil , err
971+ }
972+ }
973+ if options .ConnectionOptions .TLS == nil && ! options .DisableTLS {
974+ options .ConnectionOptions .TLS = & tls.Config {}
975+ }
976+ // Exclude internal from retry by default
977+ options .ConnectionOptions .excludeInternalFromRetry = & atomic.Bool {}
978+ options .ConnectionOptions .excludeInternalFromRetry .Store (true )
979+ // TODO(cretz): Pass through context on dial
980+ conn , err := dial (newDialParameters (& ClientOptions {
981+ HostPort : options .HostPort ,
982+ ConnectionOptions : options .ConnectionOptions ,
983+ MetricsHandler : options .MetricsHandler ,
984+ Credentials : options .Credentials ,
985+ }, options .ConnectionOptions .excludeInternalFromRetry ))
986+ if err != nil {
987+ return nil , err
988+ }
989+ return & cloudOperationsClient {
990+ conn : conn ,
991+ logger : options .Logger ,
992+ cloudServiceClient : cloudservice .NewCloudServiceClient (conn ),
993+ }, nil
994+ }
995+
900996// NewNamespaceClient creates an instance of a namespace client, to manager lifecycle of namespaces.
901997func NewNamespaceClient (options ClientOptions ) (NamespaceClient , error ) {
902998 // Initialize root tags
@@ -964,7 +1060,7 @@ func NewAPIKeyDynamicCredentials(apiKeyCallback func(context.Context) (string, e
9641060 return apiKeyCredentials (apiKeyCallback )
9651061}
9661062
967- func (apiKeyCredentials ) applyToOptions (* ClientOptions ) error { return nil }
1063+ func (apiKeyCredentials ) applyToOptions (* ConnectionOptions ) error { return nil }
9681064
9691065func (a apiKeyCredentials ) gRPCInterceptor () grpc.UnaryClientInterceptor { return a .gRPCIntercept }
9701066
@@ -992,13 +1088,13 @@ type mTLSCredentials tls.Certificate
9921088
9931089func NewMTLSCredentials (certificate tls.Certificate ) Credentials { return mTLSCredentials (certificate ) }
9941090
995- func (m mTLSCredentials ) applyToOptions (opts * ClientOptions ) error {
996- if opts .ConnectionOptions . TLS == nil {
997- opts .ConnectionOptions . TLS = & tls.Config {}
998- } else if len (opts .ConnectionOptions . TLS .Certificates ) != 0 {
1091+ func (m mTLSCredentials ) applyToOptions (opts * ConnectionOptions ) error {
1092+ if opts .TLS == nil {
1093+ opts .TLS = & tls.Config {}
1094+ } else if len (opts .TLS .Certificates ) != 0 {
9991095 return fmt .Errorf ("cannot apply mTLS credentials, certificates already exist on TLS options" )
10001096 }
1001- opts .ConnectionOptions . TLS .Certificates = append (opts . ConnectionOptions .TLS .Certificates , tls .Certificate (m ))
1097+ opts .TLS .Certificates = append (opts .TLS .Certificates , tls .Certificate (m ))
10021098 return nil
10031099}
10041100
0 commit comments