1// Code generated by smithy-go-codegen DO NOT EDIT. 2 3package emr 4 5import ( 6 "context" 7 "fmt" 8 awsmiddleware "github.com/aws/aws-sdk-go-v2/aws/middleware" 9 "github.com/aws/aws-sdk-go-v2/aws/signer/v4" 10 "github.com/aws/aws-sdk-go-v2/service/emr/types" 11 "github.com/aws/smithy-go/middleware" 12 smithytime "github.com/aws/smithy-go/time" 13 smithyhttp "github.com/aws/smithy-go/transport/http" 14 smithywaiter "github.com/aws/smithy-go/waiter" 15 "github.com/jmespath/go-jmespath" 16 "time" 17) 18 19// Provides cluster-level details including status, hardware and software 20// configuration, VPC settings, and so on. 21func (c *Client) DescribeCluster(ctx context.Context, params *DescribeClusterInput, optFns ...func(*Options)) (*DescribeClusterOutput, error) { 22 if params == nil { 23 params = &DescribeClusterInput{} 24 } 25 26 result, metadata, err := c.invokeOperation(ctx, "DescribeCluster", params, optFns, addOperationDescribeClusterMiddlewares) 27 if err != nil { 28 return nil, err 29 } 30 31 out := result.(*DescribeClusterOutput) 32 out.ResultMetadata = metadata 33 return out, nil 34} 35 36// This input determines which cluster to describe. 37type DescribeClusterInput struct { 38 39 // The identifier of the cluster to describe. 40 // 41 // This member is required. 42 ClusterId *string 43} 44 45// This output contains the description of the cluster. 46type DescribeClusterOutput struct { 47 48 // This output contains the details for the requested cluster. 49 Cluster *types.Cluster 50 51 // Metadata pertaining to the operation's result. 52 ResultMetadata middleware.Metadata 53} 54 55func addOperationDescribeClusterMiddlewares(stack *middleware.Stack, options Options) (err error) { 56 err = stack.Serialize.Add(&awsAwsjson11_serializeOpDescribeCluster{}, middleware.After) 57 if err != nil { 58 return err 59 } 60 err = stack.Deserialize.Add(&awsAwsjson11_deserializeOpDescribeCluster{}, middleware.After) 61 if err != nil { 62 return err 63 } 64 if err = addSetLoggerMiddleware(stack, options); err != nil { 65 return err 66 } 67 if err = awsmiddleware.AddClientRequestIDMiddleware(stack); err != nil { 68 return err 69 } 70 if err = smithyhttp.AddComputeContentLengthMiddleware(stack); err != nil { 71 return err 72 } 73 if err = addResolveEndpointMiddleware(stack, options); err != nil { 74 return err 75 } 76 if err = v4.AddComputePayloadSHA256Middleware(stack); err != nil { 77 return err 78 } 79 if err = addRetryMiddlewares(stack, options); err != nil { 80 return err 81 } 82 if err = addHTTPSignerV4Middleware(stack, options); err != nil { 83 return err 84 } 85 if err = awsmiddleware.AddRawResponseToMetadata(stack); err != nil { 86 return err 87 } 88 if err = awsmiddleware.AddRecordResponseTiming(stack); err != nil { 89 return err 90 } 91 if err = addClientUserAgent(stack); err != nil { 92 return err 93 } 94 if err = smithyhttp.AddErrorCloseResponseBodyMiddleware(stack); err != nil { 95 return err 96 } 97 if err = smithyhttp.AddCloseResponseBodyMiddleware(stack); err != nil { 98 return err 99 } 100 if err = addOpDescribeClusterValidationMiddleware(stack); err != nil { 101 return err 102 } 103 if err = stack.Initialize.Add(newServiceMetadataMiddleware_opDescribeCluster(options.Region), middleware.Before); err != nil { 104 return err 105 } 106 if err = addRequestIDRetrieverMiddleware(stack); err != nil { 107 return err 108 } 109 if err = addResponseErrorMiddleware(stack); err != nil { 110 return err 111 } 112 if err = addRequestResponseLogging(stack, options); err != nil { 113 return err 114 } 115 return nil 116} 117 118// DescribeClusterAPIClient is a client that implements the DescribeCluster 119// operation. 120type DescribeClusterAPIClient interface { 121 DescribeCluster(context.Context, *DescribeClusterInput, ...func(*Options)) (*DescribeClusterOutput, error) 122} 123 124var _ DescribeClusterAPIClient = (*Client)(nil) 125 126// ClusterRunningWaiterOptions are waiter options for ClusterRunningWaiter 127type ClusterRunningWaiterOptions struct { 128 129 // Set of options to modify how an operation is invoked. These apply to all 130 // operations invoked for this client. Use functional options on operation call to 131 // modify this list for per operation behavior. 132 APIOptions []func(*middleware.Stack) error 133 134 // MinDelay is the minimum amount of time to delay between retries. If unset, 135 // ClusterRunningWaiter will use default minimum delay of 30 seconds. Note that 136 // MinDelay must resolve to a value lesser than or equal to the MaxDelay. 137 MinDelay time.Duration 138 139 // MaxDelay is the maximum amount of time to delay between retries. If unset or set 140 // to zero, ClusterRunningWaiter will use default max delay of 120 seconds. Note 141 // that MaxDelay must resolve to value greater than or equal to the MinDelay. 142 MaxDelay time.Duration 143 144 // LogWaitAttempts is used to enable logging for waiter retry attempts 145 LogWaitAttempts bool 146 147 // Retryable is function that can be used to override the service defined 148 // waiter-behavior based on operation output, or returned error. This function is 149 // used by the waiter to decide if a state is retryable or a terminal state. By 150 // default service-modeled logic will populate this option. This option can thus be 151 // used to define a custom waiter state with fall-back to service-modeled waiter 152 // state mutators.The function returns an error in case of a failure state. In case 153 // of retry state, this function returns a bool value of true and nil error, while 154 // in case of success it returns a bool value of false and nil error. 155 Retryable func(context.Context, *DescribeClusterInput, *DescribeClusterOutput, error) (bool, error) 156} 157 158// ClusterRunningWaiter defines the waiters for ClusterRunning 159type ClusterRunningWaiter struct { 160 client DescribeClusterAPIClient 161 162 options ClusterRunningWaiterOptions 163} 164 165// NewClusterRunningWaiter constructs a ClusterRunningWaiter. 166func NewClusterRunningWaiter(client DescribeClusterAPIClient, optFns ...func(*ClusterRunningWaiterOptions)) *ClusterRunningWaiter { 167 options := ClusterRunningWaiterOptions{} 168 options.MinDelay = 30 * time.Second 169 options.MaxDelay = 120 * time.Second 170 options.Retryable = clusterRunningStateRetryable 171 172 for _, fn := range optFns { 173 fn(&options) 174 } 175 return &ClusterRunningWaiter{ 176 client: client, 177 options: options, 178 } 179} 180 181// Wait calls the waiter function for ClusterRunning waiter. The maxWaitDur is the 182// maximum wait duration the waiter will wait. The maxWaitDur is required and must 183// be greater than zero. 184func (w *ClusterRunningWaiter) Wait(ctx context.Context, params *DescribeClusterInput, maxWaitDur time.Duration, optFns ...func(*ClusterRunningWaiterOptions)) error { 185 if maxWaitDur <= 0 { 186 return fmt.Errorf("maximum wait time for waiter must be greater than zero") 187 } 188 189 options := w.options 190 for _, fn := range optFns { 191 fn(&options) 192 } 193 194 if options.MaxDelay <= 0 { 195 options.MaxDelay = 120 * time.Second 196 } 197 198 if options.MinDelay > options.MaxDelay { 199 return fmt.Errorf("minimum waiter delay %v must be lesser than or equal to maximum waiter delay of %v.", options.MinDelay, options.MaxDelay) 200 } 201 202 ctx, cancelFn := context.WithTimeout(ctx, maxWaitDur) 203 defer cancelFn() 204 205 logger := smithywaiter.Logger{} 206 remainingTime := maxWaitDur 207 208 var attempt int64 209 for { 210 211 attempt++ 212 apiOptions := options.APIOptions 213 start := time.Now() 214 215 if options.LogWaitAttempts { 216 logger.Attempt = attempt 217 apiOptions = append([]func(*middleware.Stack) error{}, options.APIOptions...) 218 apiOptions = append(apiOptions, logger.AddLogger) 219 } 220 221 out, err := w.client.DescribeCluster(ctx, params, func(o *Options) { 222 o.APIOptions = append(o.APIOptions, apiOptions...) 223 }) 224 225 retryable, err := options.Retryable(ctx, params, out, err) 226 if err != nil { 227 return err 228 } 229 if !retryable { 230 return nil 231 } 232 233 remainingTime -= time.Since(start) 234 if remainingTime < options.MinDelay || remainingTime <= 0 { 235 break 236 } 237 238 // compute exponential backoff between waiter retries 239 delay, err := smithywaiter.ComputeDelay( 240 attempt, options.MinDelay, options.MaxDelay, remainingTime, 241 ) 242 if err != nil { 243 return fmt.Errorf("error computing waiter delay, %w", err) 244 } 245 246 remainingTime -= delay 247 // sleep for the delay amount before invoking a request 248 if err := smithytime.SleepWithContext(ctx, delay); err != nil { 249 return fmt.Errorf("request cancelled while waiting, %w", err) 250 } 251 } 252 return fmt.Errorf("exceeded max wait time for ClusterRunning waiter") 253} 254 255func clusterRunningStateRetryable(ctx context.Context, input *DescribeClusterInput, output *DescribeClusterOutput, err error) (bool, error) { 256 257 if err == nil { 258 pathValue, err := jmespath.Search("Cluster.Status.State", output) 259 if err != nil { 260 return false, fmt.Errorf("error evaluating waiter state: %w", err) 261 } 262 263 expectedValue := "RUNNING" 264 value, ok := pathValue.(types.ClusterState) 265 if !ok { 266 return false, fmt.Errorf("waiter comparator expected types.ClusterState value, got %T", pathValue) 267 } 268 269 if string(value) == expectedValue { 270 return false, nil 271 } 272 } 273 274 if err == nil { 275 pathValue, err := jmespath.Search("Cluster.Status.State", output) 276 if err != nil { 277 return false, fmt.Errorf("error evaluating waiter state: %w", err) 278 } 279 280 expectedValue := "WAITING" 281 value, ok := pathValue.(types.ClusterState) 282 if !ok { 283 return false, fmt.Errorf("waiter comparator expected types.ClusterState value, got %T", pathValue) 284 } 285 286 if string(value) == expectedValue { 287 return false, nil 288 } 289 } 290 291 if err == nil { 292 pathValue, err := jmespath.Search("Cluster.Status.State", output) 293 if err != nil { 294 return false, fmt.Errorf("error evaluating waiter state: %w", err) 295 } 296 297 expectedValue := "TERMINATING" 298 value, ok := pathValue.(types.ClusterState) 299 if !ok { 300 return false, fmt.Errorf("waiter comparator expected types.ClusterState value, got %T", pathValue) 301 } 302 303 if string(value) == expectedValue { 304 return false, fmt.Errorf("waiter state transitioned to Failure") 305 } 306 } 307 308 if err == nil { 309 pathValue, err := jmespath.Search("Cluster.Status.State", output) 310 if err != nil { 311 return false, fmt.Errorf("error evaluating waiter state: %w", err) 312 } 313 314 expectedValue := "TERMINATED" 315 value, ok := pathValue.(types.ClusterState) 316 if !ok { 317 return false, fmt.Errorf("waiter comparator expected types.ClusterState value, got %T", pathValue) 318 } 319 320 if string(value) == expectedValue { 321 return false, fmt.Errorf("waiter state transitioned to Failure") 322 } 323 } 324 325 if err == nil { 326 pathValue, err := jmespath.Search("Cluster.Status.State", output) 327 if err != nil { 328 return false, fmt.Errorf("error evaluating waiter state: %w", err) 329 } 330 331 expectedValue := "TERMINATED_WITH_ERRORS" 332 value, ok := pathValue.(types.ClusterState) 333 if !ok { 334 return false, fmt.Errorf("waiter comparator expected types.ClusterState value, got %T", pathValue) 335 } 336 337 if string(value) == expectedValue { 338 return false, fmt.Errorf("waiter state transitioned to Failure") 339 } 340 } 341 342 return true, nil 343} 344 345// ClusterTerminatedWaiterOptions are waiter options for ClusterTerminatedWaiter 346type ClusterTerminatedWaiterOptions struct { 347 348 // Set of options to modify how an operation is invoked. These apply to all 349 // operations invoked for this client. Use functional options on operation call to 350 // modify this list for per operation behavior. 351 APIOptions []func(*middleware.Stack) error 352 353 // MinDelay is the minimum amount of time to delay between retries. If unset, 354 // ClusterTerminatedWaiter will use default minimum delay of 30 seconds. Note that 355 // MinDelay must resolve to a value lesser than or equal to the MaxDelay. 356 MinDelay time.Duration 357 358 // MaxDelay is the maximum amount of time to delay between retries. If unset or set 359 // to zero, ClusterTerminatedWaiter will use default max delay of 120 seconds. Note 360 // that MaxDelay must resolve to value greater than or equal to the MinDelay. 361 MaxDelay time.Duration 362 363 // LogWaitAttempts is used to enable logging for waiter retry attempts 364 LogWaitAttempts bool 365 366 // Retryable is function that can be used to override the service defined 367 // waiter-behavior based on operation output, or returned error. This function is 368 // used by the waiter to decide if a state is retryable or a terminal state. By 369 // default service-modeled logic will populate this option. This option can thus be 370 // used to define a custom waiter state with fall-back to service-modeled waiter 371 // state mutators.The function returns an error in case of a failure state. In case 372 // of retry state, this function returns a bool value of true and nil error, while 373 // in case of success it returns a bool value of false and nil error. 374 Retryable func(context.Context, *DescribeClusterInput, *DescribeClusterOutput, error) (bool, error) 375} 376 377// ClusterTerminatedWaiter defines the waiters for ClusterTerminated 378type ClusterTerminatedWaiter struct { 379 client DescribeClusterAPIClient 380 381 options ClusterTerminatedWaiterOptions 382} 383 384// NewClusterTerminatedWaiter constructs a ClusterTerminatedWaiter. 385func NewClusterTerminatedWaiter(client DescribeClusterAPIClient, optFns ...func(*ClusterTerminatedWaiterOptions)) *ClusterTerminatedWaiter { 386 options := ClusterTerminatedWaiterOptions{} 387 options.MinDelay = 30 * time.Second 388 options.MaxDelay = 120 * time.Second 389 options.Retryable = clusterTerminatedStateRetryable 390 391 for _, fn := range optFns { 392 fn(&options) 393 } 394 return &ClusterTerminatedWaiter{ 395 client: client, 396 options: options, 397 } 398} 399 400// Wait calls the waiter function for ClusterTerminated waiter. The maxWaitDur is 401// the maximum wait duration the waiter will wait. The maxWaitDur is required and 402// must be greater than zero. 403func (w *ClusterTerminatedWaiter) Wait(ctx context.Context, params *DescribeClusterInput, maxWaitDur time.Duration, optFns ...func(*ClusterTerminatedWaiterOptions)) error { 404 if maxWaitDur <= 0 { 405 return fmt.Errorf("maximum wait time for waiter must be greater than zero") 406 } 407 408 options := w.options 409 for _, fn := range optFns { 410 fn(&options) 411 } 412 413 if options.MaxDelay <= 0 { 414 options.MaxDelay = 120 * time.Second 415 } 416 417 if options.MinDelay > options.MaxDelay { 418 return fmt.Errorf("minimum waiter delay %v must be lesser than or equal to maximum waiter delay of %v.", options.MinDelay, options.MaxDelay) 419 } 420 421 ctx, cancelFn := context.WithTimeout(ctx, maxWaitDur) 422 defer cancelFn() 423 424 logger := smithywaiter.Logger{} 425 remainingTime := maxWaitDur 426 427 var attempt int64 428 for { 429 430 attempt++ 431 apiOptions := options.APIOptions 432 start := time.Now() 433 434 if options.LogWaitAttempts { 435 logger.Attempt = attempt 436 apiOptions = append([]func(*middleware.Stack) error{}, options.APIOptions...) 437 apiOptions = append(apiOptions, logger.AddLogger) 438 } 439 440 out, err := w.client.DescribeCluster(ctx, params, func(o *Options) { 441 o.APIOptions = append(o.APIOptions, apiOptions...) 442 }) 443 444 retryable, err := options.Retryable(ctx, params, out, err) 445 if err != nil { 446 return err 447 } 448 if !retryable { 449 return nil 450 } 451 452 remainingTime -= time.Since(start) 453 if remainingTime < options.MinDelay || remainingTime <= 0 { 454 break 455 } 456 457 // compute exponential backoff between waiter retries 458 delay, err := smithywaiter.ComputeDelay( 459 attempt, options.MinDelay, options.MaxDelay, remainingTime, 460 ) 461 if err != nil { 462 return fmt.Errorf("error computing waiter delay, %w", err) 463 } 464 465 remainingTime -= delay 466 // sleep for the delay amount before invoking a request 467 if err := smithytime.SleepWithContext(ctx, delay); err != nil { 468 return fmt.Errorf("request cancelled while waiting, %w", err) 469 } 470 } 471 return fmt.Errorf("exceeded max wait time for ClusterTerminated waiter") 472} 473 474func clusterTerminatedStateRetryable(ctx context.Context, input *DescribeClusterInput, output *DescribeClusterOutput, err error) (bool, error) { 475 476 if err == nil { 477 pathValue, err := jmespath.Search("Cluster.Status.State", output) 478 if err != nil { 479 return false, fmt.Errorf("error evaluating waiter state: %w", err) 480 } 481 482 expectedValue := "TERMINATED" 483 value, ok := pathValue.(types.ClusterState) 484 if !ok { 485 return false, fmt.Errorf("waiter comparator expected types.ClusterState value, got %T", pathValue) 486 } 487 488 if string(value) == expectedValue { 489 return false, nil 490 } 491 } 492 493 if err == nil { 494 pathValue, err := jmespath.Search("Cluster.Status.State", output) 495 if err != nil { 496 return false, fmt.Errorf("error evaluating waiter state: %w", err) 497 } 498 499 expectedValue := "TERMINATED_WITH_ERRORS" 500 value, ok := pathValue.(types.ClusterState) 501 if !ok { 502 return false, fmt.Errorf("waiter comparator expected types.ClusterState value, got %T", pathValue) 503 } 504 505 if string(value) == expectedValue { 506 return false, fmt.Errorf("waiter state transitioned to Failure") 507 } 508 } 509 510 return true, nil 511} 512 513func newServiceMetadataMiddleware_opDescribeCluster(region string) *awsmiddleware.RegisterServiceMetadata { 514 return &awsmiddleware.RegisterServiceMetadata{ 515 Region: region, 516 ServiceID: ServiceID, 517 SigningName: "elasticmapreduce", 518 OperationName: "DescribeCluster", 519 } 520} 521