github.com/aldelo/common@v1.5.1/wrapper/cloudmap/cloudmap.go (about) 1 package cloudmap 2 3 /* 4 * Copyright 2020-2023 Aldelo, LP 5 * 6 * Licensed under the Apache License, Version 2.0 (the "License"); 7 * you may not use this file except in compliance with the License. 8 * You may obtain a copy of the License at 9 * 10 * http://www.apache.org/licenses/LICENSE-2.0 11 * 12 * Unless required by applicable law or agreed to in writing, software 13 * distributed under the License is distributed on an "AS IS" BASIS, 14 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 * See the License for the specific language governing permissions and 16 * limitations under the License. 17 */ 18 19 // ================================================================================================================= 20 // AWS CREDENTIAL: 21 // use $> aws configure (to set aws access key and secret to target machine) 22 // Store AWS Access ID and Secret Key into Default Profile Using '$ aws configure' cli 23 // 24 // To Install & Setup AWS CLI on Host: 25 // 1) https://docs.aws.amazon.com/cli/latest/userguide/install-cliv2-linux.html 26 // On Ubuntu, if host does not have zip and unzip: 27 // $> sudo apt install zip 28 // $> sudo apt install unzip 29 // On Ubuntu, to install AWS CLI v2: 30 // $> curl "https://awscli.amazonaws.com/awscli-exe-linux-x86_64.zip" -o "awscliv2.zip" 31 // $> unzip awscliv2.zip 32 // $> sudo ./aws/install 33 // 2) $> aws configure set region awsRegionName --profile default 34 // 3) $> aws configure 35 // follow prompts to enter Access ID and Secret Key 36 // 37 // AWS Region Name Reference: 38 // us-west-2, us-east-1, ap-northeast-1, etc 39 // See: https://docs.aws.amazon.com/general/latest/gr/rande.html 40 // ================================================================================================================= 41 42 import ( 43 "context" 44 "errors" 45 "fmt" 46 util "github.com/aldelo/common" 47 awshttp2 "github.com/aldelo/common/wrapper/aws" 48 "github.com/aldelo/common/wrapper/aws/awsregion" 49 "github.com/aldelo/common/wrapper/cloudmap/sdhealthchecktype" 50 "github.com/aldelo/common/wrapper/cloudmap/sdnamespacefilter" 51 "github.com/aldelo/common/wrapper/cloudmap/sdoperationfilter" 52 "github.com/aldelo/common/wrapper/xray" 53 "github.com/aws/aws-sdk-go/aws" 54 "github.com/aws/aws-sdk-go/aws/session" 55 "github.com/aws/aws-sdk-go/service/servicediscovery" 56 awsxray "github.com/aws/aws-xray-sdk-go/xray" 57 "net/http" 58 "time" 59 ) 60 61 // ================================================================================================================ 62 // STRUCTS 63 // ================================================================================================================ 64 65 // CloudMap struct encapsulates the AWS CloudMap access functionality 66 type CloudMap struct { 67 // define the AWS region that KMS is located at 68 AwsRegion awsregion.AWSRegion 69 70 // custom http2 client options 71 HttpOptions *awshttp2.HttpClientSettings 72 73 // store aws session object 74 sdClient *servicediscovery.ServiceDiscovery 75 76 _parentSegment *xray.XRayParentSegment 77 } 78 79 // DnsConf represents a dns config option to be used by CreateService 80 // for this project we will only use: 81 // 1. ipv4 - dns record type A 82 // 2. srv 83 // 84 // TTL = dns record time to live in seconds 85 // MultiValue = true: route 53 returns up to 8 healthy targets if health check is enabled (otherwise, all targets assumed healthy) 86 // 87 // false: route 53 uses WEIGHTED to return a random healthy target if health check is enabled (if no healthy target found, then any random target is used) 88 // 89 // SRV = true: dns use SRV; false: dns use A 90 type DnsConf struct { 91 TTL int64 92 MultiValue bool 93 SRV bool 94 } 95 96 // HealthCheckConf represents target health check configuration 97 // 98 // Custom = true: use HealthCheckCustomConfig (for Http, Public Dns, Private Dns namespaces) 99 // 100 // false: use HealthCheckConfig (for Public Dns namespace only) 101 // 102 // FailureThreshold = if Custom is true: 103 // 104 // *) number of 30-second intervals that cloud map waits after 105 // UpdateInstanceCustomHealthStatus is executed, 106 // before changing the target health status 107 // if Custom is false: 108 // *) number of consecutive times health checks of target 109 // must pass or fail for route 53 to consider healthy or unhealthy 110 // 111 // PubDns_HealthCheck_Type = for public dns namespace only: the endpoint protocol type used for health check 112 // PubDns_HealthCheck_Path = for public dns namespace only: (Http and Https type ONLY), 113 // 114 // path to service that responds to health check, that returns http status 2xx or 3xx as healthy 115 type HealthCheckConf struct { 116 Custom bool 117 FailureThreshold int64 118 PubDns_HealthCheck_Type sdhealthchecktype.SdHealthCheckType 119 PubDns_HealthCheck_Path string 120 } 121 122 // ================================================================================================================ 123 // STRUCTS FUNCTIONS 124 // ================================================================================================================ 125 126 // ---------------------------------------------------------------------------------------------------------------- 127 // utility functions 128 // ---------------------------------------------------------------------------------------------------------------- 129 130 // Connect will establish a connection to the CloudMap service 131 func (sd *CloudMap) Connect(parentSegment ...*xray.XRayParentSegment) (err error) { 132 if xray.XRayServiceOn() { 133 if len(parentSegment) > 0 { 134 sd._parentSegment = parentSegment[0] 135 } 136 137 seg := xray.NewSegment("Cloudmap-Connect", sd._parentSegment) 138 defer seg.Close() 139 defer func() { 140 _ = seg.Seg.AddMetadata("Cloudmap-AWS-Region", sd.AwsRegion) 141 142 if err != nil { 143 _ = seg.Seg.AddError(err) 144 } 145 }() 146 147 err = sd.connectInternal() 148 149 if err == nil { 150 awsxray.AWS(sd.sdClient.Client) 151 } 152 153 return err 154 } else { 155 return sd.connectInternal() 156 } 157 } 158 159 // Connect will establish a connection to the CloudMap service 160 func (sd *CloudMap) connectInternal() error { 161 // clean up prior sd client 162 sd.sdClient = nil 163 164 if !sd.AwsRegion.Valid() || sd.AwsRegion == awsregion.UNKNOWN { 165 return errors.New("Connect To CloudMap Failed: (AWS Session Error) " + "Region is Required") 166 } 167 168 // create custom http2 client if needed 169 var httpCli *http.Client 170 var httpErr error 171 172 if sd.HttpOptions == nil { 173 sd.HttpOptions = new(awshttp2.HttpClientSettings) 174 } 175 176 // use custom http2 client 177 h2 := &awshttp2.AwsHttp2Client{ 178 Options: sd.HttpOptions, 179 } 180 181 if httpCli, httpErr = h2.NewHttp2Client(); httpErr != nil { 182 return errors.New("Connect to CloudMap Failed: (AWS Session Error) " + "Create Custom Http2 Client Errored = " + httpErr.Error()) 183 } 184 185 // establish aws session connection 186 if sess, err := session.NewSession( 187 &aws.Config{ 188 Region: aws.String(sd.AwsRegion.Key()), 189 HTTPClient: httpCli, 190 }); err != nil { 191 // aws session error 192 return errors.New("Connect To CloudMap Failed: (AWS Session Error) " + err.Error()) 193 } else { 194 // create cached objects for shared use 195 sd.sdClient = servicediscovery.New(sess) 196 197 if sd.sdClient == nil { 198 return errors.New("Connect To CloudMap Client Failed: (New CloudMap Client Connection) " + "Connection Object Nil") 199 } 200 201 return nil 202 } 203 } 204 205 // Disconnect clear client 206 func (sd *CloudMap) Disconnect() { 207 sd.sdClient = nil 208 } 209 210 // toTags converts map of tags to slice of tags 211 func (sd *CloudMap) toTags(tagsMap map[string]string) (t []*servicediscovery.Tag) { 212 if tagsMap != nil { 213 for k, v := range tagsMap { 214 t = append(t, &servicediscovery.Tag{ 215 Key: aws.String(k), 216 Value: aws.String(v), 217 }) 218 } 219 } 220 return 221 } 222 223 // UpdateParentSegment updates this struct's xray parent segment, if no parent segment, set nil 224 func (sd *CloudMap) UpdateParentSegment(parentSegment *xray.XRayParentSegment) { 225 sd._parentSegment = parentSegment 226 } 227 228 // ---------------------------------------------------------------------------------------------------------------- 229 // namespace functions 230 // ---------------------------------------------------------------------------------------------------------------- 231 232 // CreateHttpNamespace creates an http namespace for AWS cloud map 233 // 234 // Service instances registered to http namespace can be discovered using DiscoverInstances(), 235 // 236 // however, service instances cannot be discovered via dns 237 // 238 // Parameters: 239 // 1. name = (required) name of the http namespace to create 240 // 2. creatorRequestId = (required) random and unique string to identify this create namespace action (such as uuid) 241 // 3. description = (optional) http namespace description 242 // 4. tags = (optional) one or more key value pairs to store as namespace tags 243 // 5. timeOutDuration = (optional) maximum time before timeout via context 244 // 245 // Return Values: 246 // 1. operationId = string representing the identifier to be used to check on operation status at a later time 247 // 2. err = contains error info if error was encountered 248 func (sd *CloudMap) CreateHttpNamespace(name string, 249 creatorRequestId string, 250 description string, 251 tags map[string]string, 252 timeOutDuration ...time.Duration) (operationId string, err error) { 253 segCtx := context.Background() 254 segCtxSet := false 255 256 seg := xray.NewSegmentNullable("Cloudmap-CreateHttpNamespace", sd._parentSegment) 257 258 if seg != nil { 259 segCtx = seg.Ctx 260 segCtxSet = true 261 262 defer seg.Close() 263 defer func() { 264 _ = seg.Seg.AddMetadata("Cloudmap-CreateHttpNamespace-Name", name) 265 _ = seg.Seg.AddMetadata("Cloudmap-CreateHttpNamespace-CreatorRequestID", creatorRequestId) 266 _ = seg.Seg.AddMetadata("Cloudmap-CreateHttpNamespace-Result-OperationID", operationId) 267 268 if err != nil { 269 _ = seg.Seg.AddError(err) 270 } 271 }() 272 } 273 274 // validate 275 if sd.sdClient == nil { 276 err = fmt.Errorf("CloudMap CreateHttpNamespace Failed: " + "SD Client is Required") 277 return "", err 278 } 279 280 if util.LenTrim(name) == 0 { 281 err = fmt.Errorf("CloudMap CreateHttpNamespace Failed: " + "Name is Required") 282 return "", err 283 } 284 285 if util.LenTrim(creatorRequestId) == 0 { 286 err = fmt.Errorf("CloudMap CreateHttpNamespace Failed: " + "CreatorRequestId is Required") 287 return "", err 288 } 289 290 // define input 291 input := &servicediscovery.CreateHttpNamespaceInput{ 292 Name: aws.String(name), 293 CreatorRequestId: aws.String(creatorRequestId), 294 } 295 296 if util.LenTrim(description) > 0 { 297 input.Description = aws.String(description) 298 } 299 300 if tags != nil { 301 t := sd.toTags(tags) 302 303 if len(t) > 0 { 304 if len(t) > 50 { 305 err = fmt.Errorf("CloudMap CreateHttpNamespace Failed: " + "Tags Maximum Entries is 50") 306 return "", err 307 } 308 309 input.Tags = t 310 } 311 } 312 313 // invoke action 314 var output *servicediscovery.CreateHttpNamespaceOutput 315 316 if len(timeOutDuration) > 0 { 317 ctx, cancel := context.WithTimeout(segCtx, timeOutDuration[0]) 318 defer cancel() 319 320 output, err = sd.sdClient.CreateHttpNamespaceWithContext(ctx, input) 321 } else { 322 if segCtxSet { 323 output, err = sd.sdClient.CreateHttpNamespaceWithContext(segCtx, input) 324 } else { 325 output, err = sd.sdClient.CreateHttpNamespace(input) 326 } 327 } 328 329 if err != nil { 330 err = fmt.Errorf("CloudMap CreateHttpNamespace Failed: (Create Action) " + err.Error()) 331 return "", err 332 } 333 334 // action completed 335 return *output.OperationId, nil 336 } 337 338 // CreatePrivateDnsNamespace creates a private dns based namespace, visible only inside a specified aws vpc, 339 // 340 // this namespace defines service naming scheme, 341 // for example: 342 // if namespace is named as 'example.com', and service is named as 'xyz-service', 343 // the resulting dns name for the service will be 'xyz-service.example.com' 344 // 345 // Parameters: 346 // 1. name = (required) name of the private dns namespace to create 347 // 2. creatorRequestId = (required) random and unique string to identify this create namespace action (such as uuid) 348 // 3. vpc = (required) aws vpc id that this private dns associated with 349 // 4. description = (optional) private dns namespace description 350 // 5. tags = (optional) one or more key value pairs to store as namespace tags 351 // 6. timeOutDuration = (optional) maximum time before timeout via context 352 // 353 // Return Values: 354 // 1. operationId = string representing the identifier to be used to check on operation status at a later time 355 // 2. err = contains error info if error was encountered 356 func (sd *CloudMap) CreatePrivateDnsNamespace(name string, 357 creatorRequestId string, 358 vpc string, 359 description string, 360 tags map[string]string, 361 timeOutDuration ...time.Duration) (operationId string, err error) { 362 segCtx := context.Background() 363 segCtxSet := false 364 365 seg := xray.NewSegmentNullable("Cloudmap-CreatePrivateDnsNamespace", sd._parentSegment) 366 367 if seg != nil { 368 segCtx = seg.Ctx 369 segCtxSet = true 370 371 defer seg.Close() 372 defer func() { 373 _ = seg.Seg.AddMetadata("Cloudmap-CreatePrivateDnsNamespace-Name", name) 374 _ = seg.Seg.AddMetadata("Cloudmap-CreatePrivateDnsNamespace-CreatorRequestID", creatorRequestId) 375 _ = seg.Seg.AddMetadata("Cloudmap-CreatePrivateDnsNamespace-VPC", vpc) 376 _ = seg.Seg.AddMetadata("Cloudmap-CreatePrivateDnsNamespace-Result-OperationID", operationId) 377 378 if err != nil { 379 _ = seg.Seg.AddError(err) 380 } 381 }() 382 } 383 384 // validate 385 if sd.sdClient == nil { 386 err = errors.New("CloudMap CreatePrivateDnsNamespace Failed: " + "SD Client is Required") 387 return "", err 388 } 389 390 if util.LenTrim(name) == 0 { 391 err = errors.New("CloudMap CreatePrivateDnsNamespace Failed: " + "Name is Required") 392 return "", err 393 } 394 395 if util.LenTrim(creatorRequestId) == 0 { 396 err = errors.New("CloudMap CreatePrivateDnsNamespace Failed: " + "CreatorRequestId is Required") 397 return "", err 398 } 399 400 if util.LenTrim(vpc) == 0 { 401 err = errors.New("CloudMap CreatePrivateDnsNamespace Failed: " + "VPC is Required") 402 return "", err 403 } 404 405 // define input 406 input := &servicediscovery.CreatePrivateDnsNamespaceInput{ 407 Name: aws.String(name), 408 CreatorRequestId: aws.String(creatorRequestId), 409 Vpc: aws.String(vpc), 410 } 411 412 if util.LenTrim(description) > 0 { 413 input.Description = aws.String(description) 414 } 415 416 if tags != nil { 417 t := sd.toTags(tags) 418 419 if len(t) > 0 { 420 if len(t) > 50 { 421 err = errors.New("CloudMap CreatePrivateDnsNamespace Failed: " + "Tags Maximum Entries is 50") 422 return "", err 423 } 424 425 input.Tags = t 426 } 427 } 428 429 // invoke action 430 var output *servicediscovery.CreatePrivateDnsNamespaceOutput 431 432 if len(timeOutDuration) > 0 { 433 ctx, cancel := context.WithTimeout(segCtx, timeOutDuration[0]) 434 defer cancel() 435 436 output, err = sd.sdClient.CreatePrivateDnsNamespaceWithContext(ctx, input) 437 } else { 438 if segCtxSet { 439 output, err = sd.sdClient.CreatePrivateDnsNamespaceWithContext(segCtx, input) 440 } else { 441 output, err = sd.sdClient.CreatePrivateDnsNamespace(input) 442 } 443 } 444 445 if err != nil { 446 err = errors.New("CloudMap CreatePrivateDnsNamespace Failed: (Create Action) " + err.Error()) 447 return "", err 448 } 449 450 // action completed 451 return *output.OperationId, nil 452 } 453 454 // CreatePublicDnsNamespace creates a public dns based namespace, accessible via the public internet, 455 // 456 // this namespace defines service naming scheme, 457 // for example: 458 // if namespace is named as 'example.com', and service is named as 'xyz-service', 459 // the resulting dns name for the service will be 'xyz-service.example.com' 460 // 461 // Parameters: 462 // 1. name = (required) name of the public dns namespace to create 463 // 2. creatorRequestId = (required) random and unique string to identify this create namespace action (such as uuid) 464 // 3. description = (optional) public dns namespace description 465 // 4. tags = (optional) one or more key value pairs to store as namespace tags 466 // 5. timeOutDuration = (optional) maximum time before timeout via context 467 // 468 // Return Values: 469 // 1. operationId = string representing the identifier to be used to check on operation status at a later time 470 // 2. err = contains error info if error was encountered 471 func (sd *CloudMap) CreatePublicDnsNamespace(name string, 472 creatorRequestId string, 473 description string, 474 tags map[string]string, 475 timeOutDuration ...time.Duration) (operationId string, err error) { 476 segCtx := context.Background() 477 segCtxSet := false 478 479 seg := xray.NewSegmentNullable("Cloudmap-CreatePublicDnsNamespace", sd._parentSegment) 480 481 if seg != nil { 482 segCtx = seg.Ctx 483 segCtxSet = true 484 485 defer seg.Close() 486 defer func() { 487 _ = seg.Seg.AddMetadata("Cloudmap-CreatePublicDnsNamespace-Name", name) 488 _ = seg.Seg.AddMetadata("Cloudmap-CreatePublicDnsNamespace-CreatorRequestID", creatorRequestId) 489 _ = seg.Seg.AddMetadata("Cloudmap-CreatePublicDnsNamespace-Result-OperationID", operationId) 490 491 if err != nil { 492 _ = seg.Seg.AddError(err) 493 } 494 }() 495 } 496 497 // validate 498 if sd.sdClient == nil { 499 err = errors.New("CloudMap CreatePublicDnsNamespace Failed: " + "SD Client is Required") 500 return "", err 501 } 502 503 if util.LenTrim(name) == 0 { 504 err = errors.New("CloudMap CreatePublicDnsNamespace Failed: " + "Name is Required") 505 return "", err 506 } 507 508 if util.LenTrim(creatorRequestId) == 0 { 509 err = errors.New("CloudMap CreatePublicDnsNamespace Failed: " + "CreatorRequestId is Required") 510 return "", err 511 } 512 513 // define input 514 input := &servicediscovery.CreatePublicDnsNamespaceInput{ 515 Name: aws.String(name), 516 CreatorRequestId: aws.String(creatorRequestId), 517 } 518 519 if util.LenTrim(description) > 0 { 520 input.Description = aws.String(description) 521 } 522 523 if tags != nil { 524 t := sd.toTags(tags) 525 526 if len(t) > 0 { 527 if len(t) > 50 { 528 err = errors.New("CloudMap CreatePublicDnsNamespace Failed: " + "Tags Maximum Entries is 50") 529 return "", err 530 } 531 532 input.Tags = t 533 } 534 } 535 536 // invoke action 537 var output *servicediscovery.CreatePublicDnsNamespaceOutput 538 539 if len(timeOutDuration) > 0 { 540 ctx, cancel := context.WithTimeout(segCtx, timeOutDuration[0]) 541 defer cancel() 542 543 output, err = sd.sdClient.CreatePublicDnsNamespaceWithContext(ctx, input) 544 } else { 545 if segCtxSet { 546 output, err = sd.sdClient.CreatePublicDnsNamespaceWithContext(segCtx, input) 547 } else { 548 output, err = sd.sdClient.CreatePublicDnsNamespace(input) 549 } 550 } 551 552 if err != nil { 553 err = errors.New("CloudMap CreatePublicDnsNamespace Failed: (Create Action) " + err.Error()) 554 return "", err 555 } 556 557 // action completed 558 return *output.OperationId, nil 559 } 560 561 // GetNamespace gets the information about a specific namespace 562 // 563 // Parameters: 564 // 1. namespaceId = (required) namespace id used for search 565 // 2. timeOutDuration = (optional) maximum time before timeout via context 566 // 567 // Return Values: 568 // 1. namespace = sd namespace object found 569 // 2. err = error info if any 570 func (sd *CloudMap) GetNamespace(namespaceId string, timeOutDuration ...time.Duration) (namespace *servicediscovery.Namespace, err error) { 571 segCtx := context.Background() 572 segCtxSet := false 573 574 seg := xray.NewSegmentNullable("Cloudmap-GetNamespace", sd._parentSegment) 575 576 if seg != nil { 577 segCtx = seg.Ctx 578 segCtxSet = true 579 580 defer seg.Close() 581 defer func() { 582 _ = seg.Seg.AddMetadata("Cloudmap-GetNamespace-NamespaceID", namespaceId) 583 _ = seg.Seg.AddMetadata("Cloudmap-GetNamespace-Result-NamespaceObject", namespace) 584 585 if err != nil { 586 _ = seg.Seg.AddError(err) 587 } 588 }() 589 } 590 591 // validate 592 if sd.sdClient == nil { 593 err = errors.New("CloudMap GetNamespace Failed: " + "SD Client is Required") 594 return nil, err 595 } 596 597 if util.LenTrim(namespaceId) == 0 { 598 err = errors.New("CloudMap GetNamespace Failed: " + "NamespaceId is Required") 599 return nil, err 600 } 601 602 // define input 603 input := &servicediscovery.GetNamespaceInput{ 604 Id: aws.String(namespaceId), 605 } 606 607 // invoke action 608 var output *servicediscovery.GetNamespaceOutput 609 610 if len(timeOutDuration) > 0 { 611 ctx, cancel := context.WithTimeout(segCtx, timeOutDuration[0]) 612 defer cancel() 613 614 output, err = sd.sdClient.GetNamespaceWithContext(ctx, input) 615 } else { 616 if segCtxSet { 617 output, err = sd.sdClient.GetNamespaceWithContext(segCtx, input) 618 } else { 619 output, err = sd.sdClient.GetNamespace(input) 620 } 621 } 622 623 if err != nil { 624 // handle error 625 err = errors.New("CloudMap GetNamespace Failed: (Get Action) " + err.Error()) 626 return nil, err 627 } 628 629 return output.Namespace, nil 630 } 631 632 // ListNamespaces gets summary information about namespaces created already 633 // 634 // Parameters: 635 // 1. filter = (optional) specifies namespace filter options 636 // 2. maxResults = (optional) specifies maximum count to return 637 // 3. nextToken = (optional) if initial action, leave blank; if this is a subsequent action to get more, input the moreNextToken returned from a prior action 638 // 4. timeOutDuration = (optional) maximum time before timeout via context 639 // 640 // Return Values: 641 // 1. namespaces = slice of sd namespace summary objects 642 // 2. moreNextToken = if more data exists, this token can be used in a subsequent action via nextToken parameter 643 // 3. err = error info if any 644 func (sd *CloudMap) ListNamespaces(filter *sdnamespacefilter.SdNamespaceFilter, 645 maxResults *int64, 646 nextToken *string, 647 timeOutDuration ...time.Duration) (namespaces []*servicediscovery.NamespaceSummary, moreNextToken string, err error) { 648 segCtx := context.Background() 649 segCtxSet := false 650 651 seg := xray.NewSegmentNullable("Cloudmap-ListNamespaces", sd._parentSegment) 652 653 if seg != nil { 654 segCtx = seg.Ctx 655 segCtxSet = true 656 657 defer seg.Close() 658 defer func() { 659 _ = seg.Seg.AddMetadata("Cloudmap-ListNamespaces-Filter", filter) 660 _ = seg.Seg.AddMetadata("Cloudmap-ListNamespaces-Max-Results", maxResults) 661 _ = seg.Seg.AddMetadata("Cloudmap-ListNamespaces-Next-Token", nextToken) 662 _ = seg.Seg.AddMetadata("Cloudmap-ListNamespaces-Result-Namespaces", namespaces) 663 _ = seg.Seg.AddMetadata("Cloudmap-ListNamespaces-Result-Next-Token", moreNextToken) 664 665 if err != nil { 666 _ = seg.Seg.AddError(err) 667 } 668 }() 669 } 670 671 // validate 672 if sd.sdClient == nil { 673 err = errors.New("CloudMap ListNamespaces Failed: " + "SD Client is Required") 674 return nil, "", err 675 } 676 677 if maxResults != nil { 678 if *maxResults <= 0 { 679 err = errors.New("CloudMap ListNamespaces Failed: " + "MaxResults Must Be Greater Than Zero") 680 return nil, "", err 681 } 682 } 683 684 // define input 685 input := &servicediscovery.ListNamespacesInput{} 686 687 if filter != nil && filter.Valid() && *filter != sdnamespacefilter.UNKNOWN { 688 input.Filters = []*servicediscovery.NamespaceFilter{ 689 { 690 Name: aws.String("TYPE"), 691 }, 692 } 693 694 switch *filter { 695 case sdnamespacefilter.PrivateDnsNamespace: 696 input.Filters[0].Condition = aws.String("EQ") 697 input.Filters[0].Values = []*string{ 698 aws.String("DNS_PRIVATE"), 699 } 700 case sdnamespacefilter.PublicDnsNamespace: 701 input.Filters[0].Condition = aws.String("EQ") 702 input.Filters[0].Values = []*string{ 703 aws.String("DNS_PUBLIC"), 704 } 705 case sdnamespacefilter.Both: 706 input.Filters[0].Condition = aws.String("IN") 707 input.Filters[0].Values = []*string{ 708 aws.String("DNS_PRIVATE"), 709 aws.String("DNS_PUBLIC"), 710 } 711 } 712 } 713 714 if maxResults != nil { 715 input.MaxResults = maxResults 716 } 717 718 if nextToken != nil { 719 if util.LenTrim(*nextToken) > 0 { 720 input.NextToken = nextToken 721 } 722 } 723 724 // invoke action 725 var output *servicediscovery.ListNamespacesOutput 726 727 if len(timeOutDuration) > 0 { 728 ctx, cancel := context.WithTimeout(segCtx, timeOutDuration[0]) 729 defer cancel() 730 731 output, err = sd.sdClient.ListNamespacesWithContext(ctx, input) 732 } else { 733 if segCtxSet { 734 output, err = sd.sdClient.ListNamespacesWithContext(segCtx, input) 735 } else { 736 output, err = sd.sdClient.ListNamespaces(input) 737 } 738 } 739 740 if err != nil { 741 // handle error 742 err = errors.New("CloudMap ListNamespaces Failed: (List Action) " + err.Error()) 743 return nil, "", err 744 } 745 746 return output.Namespaces, *output.NextToken, nil 747 } 748 749 // ListNamespacesPages gets summary information about namespaces created already 750 // (issues multiple page requests until max results is met or all data is retrieved) 751 // 752 // Parameters: 753 // 1. filter = (optional) specifies namespace filter options 754 // 2. maxResults = (optional) specifies maximum count to return 755 // 3. nextToken = (optional) if initial action, leave blank; if this is a subsequent action to get more, input the moreNextToken returned from a prior action 756 // 4. timeOutDuration = (optional) maximum time before timeout via context 757 // 758 // Return Values: 759 // 1. namespaces = slice of sd namespace summary objects 760 // 2. moreNextToken = if more data exists, this token can be used in a subsequent action via nextToken parameter 761 // 3. err = error info if any 762 func (sd *CloudMap) ListNamespacesPages(filter *sdnamespacefilter.SdNamespaceFilter, 763 maxResults *int64, 764 nextToken *string, 765 timeOutDuration ...time.Duration) (namespaces []*servicediscovery.NamespaceSummary, moreNextToken string, err error) { 766 segCtx := context.Background() 767 segCtxSet := false 768 769 seg := xray.NewSegmentNullable("Cloudmap-ListNamespacesPages", sd._parentSegment) 770 771 if seg != nil { 772 segCtx = seg.Ctx 773 segCtxSet = true 774 775 defer seg.Close() 776 defer func() { 777 _ = seg.Seg.AddMetadata("Cloudmap-ListNamespacesPages-Filter", filter) 778 _ = seg.Seg.AddMetadata("Cloudmap-ListNamespacesPages-Max-Results", maxResults) 779 _ = seg.Seg.AddMetadata("Cloudmap-ListNamespacesPages-Next-Token", nextToken) 780 _ = seg.Seg.AddMetadata("Cloudmap-ListNamespacesPages-Result-Namespaces", namespaces) 781 _ = seg.Seg.AddMetadata("Cloudmap-ListNamespacesPages-Result-Next-Token", moreNextToken) 782 783 if err != nil { 784 _ = seg.Seg.AddError(err) 785 } 786 }() 787 } 788 789 // validate 790 if sd.sdClient == nil { 791 err = errors.New("CloudMap ListNamespacesPages Failed: " + "SD Client is Required") 792 return nil, "", err 793 } 794 795 if maxResults != nil { 796 if *maxResults <= 0 { 797 err = errors.New("CloudMap ListNamespacesPages Failed: " + "MaxResults Must Be Greater Than Zero") 798 return nil, "", err 799 } 800 } 801 802 // define input 803 input := &servicediscovery.ListNamespacesInput{} 804 805 if filter != nil && filter.Valid() && *filter != sdnamespacefilter.UNKNOWN { 806 input.Filters = []*servicediscovery.NamespaceFilter{ 807 { 808 Name: aws.String("TYPE"), 809 }, 810 } 811 812 switch *filter { 813 case sdnamespacefilter.PrivateDnsNamespace: 814 input.Filters[0].Condition = aws.String("EQ") 815 input.Filters[0].Values = []*string{ 816 aws.String("DNS_PRIVATE"), 817 } 818 case sdnamespacefilter.PublicDnsNamespace: 819 input.Filters[0].Condition = aws.String("EQ") 820 input.Filters[0].Values = []*string{ 821 aws.String("DNS_PUBLIC"), 822 } 823 case sdnamespacefilter.Both: 824 input.Filters[0].Condition = aws.String("IN") 825 input.Filters[0].Values = []*string{ 826 aws.String("DNS_PRIVATE"), 827 aws.String("DNS_PUBLIC"), 828 } 829 } 830 } 831 832 if maxResults != nil { 833 input.MaxResults = maxResults 834 } 835 836 if nextToken != nil { 837 if util.LenTrim(*nextToken) > 0 { 838 input.NextToken = nextToken 839 } 840 } 841 842 // invoke action 843 fn := func(pageOutput *servicediscovery.ListNamespacesOutput, lastPage bool) bool { 844 if pageOutput != nil { 845 moreNextToken = *pageOutput.NextToken 846 namespaces = append(namespaces, pageOutput.Namespaces...) 847 } 848 849 return !lastPage 850 } 851 852 if len(timeOutDuration) > 0 { 853 ctx, cancel := context.WithTimeout(segCtx, timeOutDuration[0]) 854 defer cancel() 855 856 err = sd.sdClient.ListNamespacesPagesWithContext(ctx, input, fn) 857 } else { 858 if segCtxSet { 859 err = sd.sdClient.ListNamespacesPagesWithContext(segCtx, input, fn) 860 } else { 861 err = sd.sdClient.ListNamespacesPages(input, fn) 862 } 863 } 864 865 if err != nil { 866 // handle error 867 err = errors.New("CloudMap ListNamespacesPages Failed: (ListPages Action) " + err.Error()) 868 return nil, "", err 869 } 870 871 return namespaces, moreNextToken, nil 872 } 873 874 // DeleteNamespace deletes an existing namespace, however if namespace still has attached services, then action will fail 875 // 876 // Parameters: 877 // 1. namespaceId = (required) namespace id to delete 878 // 879 // Return Values: 880 // 1. operationId = represents the operation to be used for status check on this action via GetOperation() 881 // 2. err = error info if any 882 func (sd *CloudMap) DeleteNamespace(namespaceId string, timeOutDuration ...time.Duration) (operationId string, err error) { 883 segCtx := context.Background() 884 segCtxSet := false 885 886 seg := xray.NewSegmentNullable("Cloudmap-DeleteNamespace", sd._parentSegment) 887 888 if seg != nil { 889 segCtx = seg.Ctx 890 segCtxSet = true 891 892 defer seg.Close() 893 defer func() { 894 _ = seg.Seg.AddMetadata("Cloudmap-DeleteNamespace-NamespaceID", namespaceId) 895 _ = seg.Seg.AddMetadata("Cloudmap-DeleteNamespace-Result-OperationID", operationId) 896 897 if err != nil { 898 _ = seg.Seg.AddError(err) 899 } 900 }() 901 } 902 903 // validate 904 if sd.sdClient == nil { 905 err = errors.New("CloudMap DeleteNamespace Failed: " + "SD Client is Required") 906 return "", err 907 } 908 909 if util.LenTrim(namespaceId) == 0 { 910 err = errors.New("CloudMap DeleteNamespace Failed: " + "NamespaceId is Required") 911 return "", err 912 } 913 914 // define input 915 input := &servicediscovery.DeleteNamespaceInput{ 916 Id: aws.String(namespaceId), 917 } 918 919 // invoke action 920 var output *servicediscovery.DeleteNamespaceOutput 921 922 if len(timeOutDuration) > 0 { 923 ctx, cancel := context.WithTimeout(segCtx, timeOutDuration[0]) 924 defer cancel() 925 926 output, err = sd.sdClient.DeleteNamespaceWithContext(ctx, input) 927 } else { 928 if segCtxSet { 929 output, err = sd.sdClient.DeleteNamespaceWithContext(segCtx, input) 930 } else { 931 output, err = sd.sdClient.DeleteNamespace(input) 932 } 933 } 934 935 if err != nil { 936 // handle error 937 err = errors.New("CloudMap DeleteNamespace Failed: (Delete Action) " + err.Error()) 938 return "", err 939 } 940 941 return *output.OperationId, nil 942 } 943 944 // ---------------------------------------------------------------------------------------------------------------- 945 // service functions 946 // ---------------------------------------------------------------------------------------------------------------- 947 948 // CreateService creates a service under a specific namespace 949 // 950 // # After service is created, use RegisterInstance() to register an instance for the given service 951 // 952 // Parameters: 953 // 1. name = (required) name of the service to create, under the given namespaceId 954 // 2. creatorRequestId = (required) random and unique string to identify this create service action (such as uuid) 955 // 3. namespaceId = (required) namespace that this service be created under 956 // 4. dnsConf = (conditional) required for public and private dns namespaces, configures the dns parameters for this service 957 // 5. healthCheckConf = (optional) nil will not set health check, otherwise sets a health check condition for this services' instances 958 // 6. description = (optional) public dns namespace description 959 // 7. tags = (optional) one or more key value pairs to store as namespace tags 960 // 8. timeOutDuration = (optional) maximum time before timeout via context 961 // 962 // Return Values: 963 // 1. service = service object that was created 964 // 2. err = contains error info if error was encountered 965 func (sd *CloudMap) CreateService(name string, 966 creatorRequestId string, 967 namespaceId string, 968 dnsConf *DnsConf, 969 healthCheckConf *HealthCheckConf, 970 description string, 971 tags map[string]string, 972 timeOutDuration ...time.Duration) (service *servicediscovery.Service, err error) { 973 segCtx := context.Background() 974 segCtxSet := false 975 976 seg := xray.NewSegmentNullable("Cloudmap-CreateService", sd._parentSegment) 977 978 if seg != nil { 979 segCtx = seg.Ctx 980 segCtxSet = true 981 982 defer seg.Close() 983 defer func() { 984 _ = seg.Seg.AddMetadata("Cloudmap-CreateService-ServiceName", name) 985 _ = seg.Seg.AddMetadata("Cloudmap-CreateService-CreatorRequestID", creatorRequestId) 986 _ = seg.Seg.AddMetadata("Cloudmap-CreateService-NamespaceID", namespaceId) 987 _ = seg.Seg.AddMetadata("Cloudmap-CreateService-DNSConf", dnsConf) 988 _ = seg.Seg.AddMetadata("Cloudmap-CreateService-HealthCheckConf", healthCheckConf) 989 _ = seg.Seg.AddMetadata("Cloudmap-CreateService-Result-ServiceObject", service) 990 991 if err != nil { 992 _ = seg.Seg.AddError(err) 993 } 994 }() 995 } 996 997 // validate 998 if sd.sdClient == nil { 999 err = errors.New("CloudMap CreateService Failed: " + "SD Client is Required") 1000 return nil, err 1001 } 1002 1003 if util.LenTrim(name) == 0 { 1004 err = errors.New("CloudMap CreateService Failed: " + "Name is Required") 1005 return nil, err 1006 } 1007 1008 if util.LenTrim(creatorRequestId) == 0 { 1009 err = errors.New("CloudMap CreateService Failed: " + "CreatorRequestId is Required") 1010 return nil, err 1011 } 1012 1013 if util.LenTrim(namespaceId) == 0 { 1014 err = errors.New("CloudMap CreateService Failed: " + "NamespaceId is Required") 1015 return nil, err 1016 } 1017 1018 if dnsConf != nil { 1019 // dns conf set, public or private dns namespace only 1020 if dnsConf.TTL <= 0 { 1021 dnsConf.TTL = 300 // default to 5 minutes ttl if not specified 1022 } 1023 1024 if healthCheckConf != nil { 1025 if healthCheckConf.FailureThreshold <= 0 { 1026 healthCheckConf.FailureThreshold = 1 1027 } 1028 1029 if healthCheckConf.Custom { 1030 healthCheckConf.PubDns_HealthCheck_Type = sdhealthchecktype.UNKNOWN 1031 healthCheckConf.PubDns_HealthCheck_Path = "" 1032 } else { 1033 if !healthCheckConf.PubDns_HealthCheck_Type.Valid() || healthCheckConf.PubDns_HealthCheck_Type == sdhealthchecktype.UNKNOWN { 1034 err = errors.New("CloudMap CreateService Failed: " + "Public Dns Namespace Health Check Requires Endpoint Type") 1035 return nil, err 1036 } 1037 1038 if healthCheckConf.PubDns_HealthCheck_Type == sdhealthchecktype.TCP { 1039 healthCheckConf.PubDns_HealthCheck_Path = "" 1040 } else { 1041 if util.LenTrim(healthCheckConf.PubDns_HealthCheck_Path) == 0 { 1042 err = errors.New("CloudMap CreateService Failed: " + "Health Check Resource Path is Required for HTTP & HTTPS Types") 1043 return nil, err 1044 } 1045 } 1046 } 1047 } 1048 } else { 1049 // if dns is not defined, this is api only, health check must be custom 1050 if !healthCheckConf.Custom { 1051 err = errors.New("CloudMap CreateService Failed: " + "Route 53 Health Check is for Private or Public Dns Namespaces Only") 1052 return nil, err 1053 } 1054 } 1055 1056 // define input 1057 input := &servicediscovery.CreateServiceInput{ 1058 Name: aws.String(name), 1059 CreatorRequestId: aws.String(creatorRequestId), 1060 NamespaceId: aws.String(namespaceId), 1061 } 1062 1063 if util.LenTrim(description) > 0 { 1064 input.Description = aws.String(description) 1065 } 1066 1067 if tags != nil { 1068 t := sd.toTags(tags) 1069 1070 if len(t) > 0 { 1071 if len(t) > 50 { 1072 err = errors.New("CloudMap CreateService Failed: " + "Tags Maximum Entries is 50") 1073 return nil, err 1074 } 1075 1076 input.Tags = t 1077 } 1078 } 1079 1080 if dnsConf != nil { 1081 routingPolicy := "MULTIVALUE" 1082 1083 if !dnsConf.MultiValue { 1084 routingPolicy = "WEIGHTED" 1085 } 1086 1087 dnsType := "A" 1088 1089 if dnsConf.SRV { 1090 dnsType = "SRV" 1091 } 1092 1093 input.DnsConfig = &servicediscovery.DnsConfig{ 1094 RoutingPolicy: aws.String(routingPolicy), 1095 DnsRecords: []*servicediscovery.DnsRecord{ 1096 { 1097 TTL: aws.Int64(dnsConf.TTL), 1098 Type: aws.String(dnsType), 1099 }, 1100 }, 1101 } 1102 } 1103 1104 if healthCheckConf != nil { 1105 if healthCheckConf.Custom { 1106 // custom health config 1107 input.HealthCheckCustomConfig = &servicediscovery.HealthCheckCustomConfig{ 1108 FailureThreshold: aws.Int64(healthCheckConf.FailureThreshold), 1109 } 1110 } else { 1111 // public dns health config 1112 input.HealthCheckConfig = &servicediscovery.HealthCheckConfig{ 1113 FailureThreshold: aws.Int64(healthCheckConf.FailureThreshold), 1114 Type: aws.String(healthCheckConf.PubDns_HealthCheck_Type.Key()), 1115 } 1116 1117 if util.LenTrim(healthCheckConf.PubDns_HealthCheck_Path) > 0 { 1118 input.HealthCheckConfig.SetResourcePath(healthCheckConf.PubDns_HealthCheck_Path) 1119 } 1120 } 1121 } 1122 1123 // invoke action 1124 var output *servicediscovery.CreateServiceOutput 1125 1126 if len(timeOutDuration) > 0 { 1127 ctx, cancel := context.WithTimeout(segCtx, timeOutDuration[0]) 1128 defer cancel() 1129 1130 output, err = sd.sdClient.CreateServiceWithContext(ctx, input) 1131 } else { 1132 if segCtxSet { 1133 output, err = sd.sdClient.CreateServiceWithContext(segCtx, input) 1134 } else { 1135 output, err = sd.sdClient.CreateService(input) 1136 } 1137 } 1138 1139 if err != nil { 1140 // handle error 1141 err = errors.New("CloudMap CreateService Failed: (Create Action) " + err.Error()) 1142 return nil, err 1143 } 1144 1145 return output.Service, nil 1146 } 1147 1148 // UpdateService submits request for the following operations: 1149 // 1. update the TTL for existing dnsRecords configurations 1150 // 2. add, update, or delete HealthCheckConfig for a specified service, 1151 // HealthCheckCustomConfig cannot be added, updated or deleted via UpdateService action 1152 // 1153 // Notes: 1154 // 1. public and private dns namespaces, 1155 // a) if any existing dnsRecords or healthCheckConfig configurations are omitted from the UpdateService request, 1156 // those omitted configurations ARE deleted from the service 1157 // b) if any existing HealthCheckCustomConfig configurations are omitted from the UpdateService request, 1158 // the omitted configurations ARE NOT deleted from the service 1159 // 2. when settings are updated for a service, 1160 // aws cloud map also updates the corresponding settings in all the records and health checks, 1161 // that were created by the given service 1162 // 1163 // Parameters: 1164 // 1. serviceId = (required) service to update 1165 // 2. dnsConfUpdate = (required) update dns config to this value, if nil, existing dns configuration will be removed from service 1166 // 3. healthCheckConf = (optional) update health check config to this value, if nil, existing health check config will be removed from service 1167 // 4. descriptionUpdate = (optional) service description to update, if nil, existing description will be removed from service 1168 // 5. timeOutDuration = (optional) maximum time before timeout via context 1169 // 1170 // Return Values: 1171 // 1. operationId = this action's operation id to be used in GetOperation for status check 1172 // 2. err = contains error info if error was encountered 1173 func (sd *CloudMap) UpdateService(serviceId string, 1174 dnsConfUpdate *DnsConf, 1175 healthCheckConfUpdate *HealthCheckConf, 1176 descriptionUpdate *string, 1177 timeOutDuration ...time.Duration) (operationId string, err error) { 1178 segCtx := context.Background() 1179 segCtxSet := false 1180 1181 seg := xray.NewSegmentNullable("Cloudmap-UpdateService", sd._parentSegment) 1182 1183 if seg != nil { 1184 segCtx = seg.Ctx 1185 segCtxSet = true 1186 1187 defer seg.Close() 1188 defer func() { 1189 _ = seg.Seg.AddMetadata("Cloudmap-UpdateService-ServiceID", serviceId) 1190 _ = seg.Seg.AddMetadata("Cloudmap-UpdateService-DNSConfUpdate", dnsConfUpdate) 1191 _ = seg.Seg.AddMetadata("Cloudmap-UpdateService-HealthCheckConfUpdate", healthCheckConfUpdate) 1192 _ = seg.Seg.AddMetadata("Cloudmap-UpdateService-DescriptionUpdate", descriptionUpdate) 1193 _ = seg.Seg.AddMetadata("Cloudmap-UpdateService-Result-OperationID", operationId) 1194 1195 if err != nil { 1196 _ = seg.Seg.AddError(err) 1197 } 1198 }() 1199 } 1200 1201 // validate 1202 if sd.sdClient == nil { 1203 err = errors.New("CloudMap UpdateService Failed: " + "SD Client is Required") 1204 return "", err 1205 } 1206 1207 if util.LenTrim(serviceId) == 0 { 1208 err = errors.New("CloudMap UpdateService Failed: " + "ServiceId is Required") 1209 return "", err 1210 } 1211 1212 if dnsConfUpdate == nil { 1213 err = errors.New("CloudMap UpdateService Failed: " + "Dns Config Update is Required") 1214 return "", err 1215 } 1216 1217 if healthCheckConfUpdate != nil && healthCheckConfUpdate.Custom { 1218 err = errors.New("CloudMap UpdateService Failed: " + "Health Check Custom Config Cannot Be Updated") 1219 return "", err 1220 } 1221 1222 // dns conf set, public or private dns namespace only 1223 if dnsConfUpdate.TTL <= 0 { 1224 dnsConfUpdate.TTL = 300 // default to 5 minutes ttl if not specified 1225 } 1226 1227 if healthCheckConfUpdate != nil { 1228 if healthCheckConfUpdate.FailureThreshold <= 0 { 1229 healthCheckConfUpdate.FailureThreshold = 1 1230 } 1231 1232 if !healthCheckConfUpdate.PubDns_HealthCheck_Type.Valid() || healthCheckConfUpdate.PubDns_HealthCheck_Type == sdhealthchecktype.UNKNOWN { 1233 err = errors.New("CloudMap UpdateService Failed: " + "Public Dns Namespace Health Check Requires Endpoint Type") 1234 return "", err 1235 } 1236 1237 if healthCheckConfUpdate.PubDns_HealthCheck_Type == sdhealthchecktype.TCP { 1238 healthCheckConfUpdate.PubDns_HealthCheck_Path = "" 1239 } else { 1240 if util.LenTrim(healthCheckConfUpdate.PubDns_HealthCheck_Path) == 0 { 1241 err = errors.New("CloudMap UpdateService Failed: " + "Health Check Resource Path is Required for HTTP & HTTPS Types") 1242 return "", err 1243 } 1244 } 1245 } 1246 1247 // define input 1248 input := &servicediscovery.UpdateServiceInput{ 1249 Id: aws.String(serviceId), 1250 } 1251 1252 input.Service = &servicediscovery.ServiceChange{} 1253 1254 if descriptionUpdate != nil { 1255 if util.LenTrim(*descriptionUpdate) > 0 { 1256 input.Service.Description = descriptionUpdate 1257 } 1258 } 1259 1260 // dns update is TTL only but must provide existing dns type 1261 dnsType := "A" 1262 1263 if dnsConfUpdate.SRV { 1264 dnsType = "SRV" 1265 } 1266 1267 input.Service.DnsConfig = &servicediscovery.DnsConfigChange{ 1268 DnsRecords: []*servicediscovery.DnsRecord{ 1269 { 1270 TTL: aws.Int64(dnsConfUpdate.TTL), 1271 Type: aws.String(dnsType), 1272 }, 1273 }, 1274 } 1275 1276 if healthCheckConfUpdate != nil { 1277 // update public dns health config 1278 input.Service.HealthCheckConfig = &servicediscovery.HealthCheckConfig{ 1279 FailureThreshold: aws.Int64(healthCheckConfUpdate.FailureThreshold), 1280 Type: aws.String(healthCheckConfUpdate.PubDns_HealthCheck_Type.Key()), 1281 } 1282 1283 if util.LenTrim(healthCheckConfUpdate.PubDns_HealthCheck_Path) > 0 { 1284 input.Service.HealthCheckConfig.ResourcePath = aws.String(healthCheckConfUpdate.PubDns_HealthCheck_Path) 1285 } 1286 } 1287 1288 // invoke action 1289 var output *servicediscovery.UpdateServiceOutput 1290 1291 if len(timeOutDuration) > 0 { 1292 ctx, cancel := context.WithTimeout(segCtx, timeOutDuration[0]) 1293 defer cancel() 1294 1295 output, err = sd.sdClient.UpdateServiceWithContext(ctx, input) 1296 } else { 1297 if segCtxSet { 1298 output, err = sd.sdClient.UpdateServiceWithContext(segCtx, input) 1299 } else { 1300 output, err = sd.sdClient.UpdateService(input) 1301 } 1302 } 1303 1304 if err != nil { 1305 // handle error 1306 err = errors.New("CloudMap UpdateService Failed: (Update Action) " + err.Error()) 1307 return "", err 1308 } 1309 1310 return *output.OperationId, nil 1311 } 1312 1313 // GetService gets a specified service's settings 1314 // 1315 // Parameters: 1316 // 1. serviceId = (required) get service based on this service id 1317 // 2. timeOutDuration = (optional) maximum time before timeout via context 1318 // 1319 // Return Values: 1320 // 1. service = service object found based on the provided serviceId 1321 // 2. err = contains error info if error was encountered 1322 func (sd *CloudMap) GetService(serviceId string, timeOutDuration ...time.Duration) (service *servicediscovery.Service, err error) { 1323 segCtx := context.Background() 1324 segCtxSet := false 1325 1326 seg := xray.NewSegmentNullable("Cloudmap-GetService", sd._parentSegment) 1327 1328 if seg != nil { 1329 segCtx = seg.Ctx 1330 segCtxSet = true 1331 1332 defer seg.Close() 1333 defer func() { 1334 _ = seg.Seg.AddMetadata("Cloudmap-GetService-ServiceID", serviceId) 1335 _ = seg.Seg.AddMetadata("Cloudmap-GetService-Result-Service", service) 1336 1337 if err != nil { 1338 _ = seg.Seg.AddError(err) 1339 } 1340 }() 1341 } 1342 1343 // validate 1344 if sd.sdClient == nil { 1345 err = errors.New("CloudMap GetService Failed: " + "SD Client is Required") 1346 return nil, err 1347 } 1348 1349 if util.LenTrim(serviceId) == 0 { 1350 err = errors.New("CloudMap GetService Failed: " + "ServiceId is Required") 1351 return nil, err 1352 } 1353 1354 // define input 1355 input := &servicediscovery.GetServiceInput{ 1356 Id: aws.String(serviceId), 1357 } 1358 1359 // invoke action 1360 var output *servicediscovery.GetServiceOutput 1361 1362 if len(timeOutDuration) > 0 { 1363 ctx, cancel := context.WithTimeout(segCtx, timeOutDuration[0]) 1364 defer cancel() 1365 1366 output, err = sd.sdClient.GetServiceWithContext(ctx, input) 1367 } else { 1368 if segCtxSet { 1369 output, err = sd.sdClient.GetServiceWithContext(segCtx, input) 1370 } else { 1371 output, err = sd.sdClient.GetService(input) 1372 } 1373 } 1374 1375 if err != nil { 1376 // handle error 1377 err = errors.New("CloudMap GetService Failed: (Get Action) " + err.Error()) 1378 return nil, err 1379 } 1380 1381 return output.Service, nil 1382 } 1383 1384 // ListServices lists summary information about all the services associated with one or more namespaces 1385 // 1386 // Parameters: 1387 // 1. filter = (optional) filter by namespace(s) as specified, slice of namespaceId to filter 1388 // 2. maxResults = (optional) specifies maximum count to return 1389 // 3. nextToken = (optional) if initial action, leave blank; if this is a subsequent action to get more, input the moreNextToken returned from a prior action 1390 // 4. timeOutDuration = (optional) maximum time before timeout via context 1391 // 1392 // Return Values: 1393 // 1. services = slice of sd service summary objects 1394 // 2. moreNextToken = if more data exists, this token can be used in a subsequent action via nextToken parameter 1395 // 3. err = error info if any 1396 func (sd *CloudMap) ListServices(filter []string, 1397 maxResults *int64, 1398 nextToken *string, 1399 timeOutDuration ...time.Duration) (services []*servicediscovery.ServiceSummary, moreNextToken string, err error) { 1400 segCtx := context.Background() 1401 segCtxSet := false 1402 1403 seg := xray.NewSegmentNullable("Cloudmap-ListServices", sd._parentSegment) 1404 1405 if seg != nil { 1406 segCtx = seg.Ctx 1407 segCtxSet = true 1408 1409 defer seg.Close() 1410 defer func() { 1411 _ = seg.Seg.AddMetadata("Cloudmap-ListServices-Filter", filter) 1412 _ = seg.Seg.AddMetadata("Cloudmap-ListServices-MaxResults", maxResults) 1413 _ = seg.Seg.AddMetadata("Cloudmap-ListServices-NextToken", nextToken) 1414 _ = seg.Seg.AddMetadata("Cloudmap-ListServices-Result-Services", services) 1415 _ = seg.Seg.AddMetadata("Cloudmap-ListServices-Result-NextToken", moreNextToken) 1416 1417 if err != nil { 1418 _ = seg.Seg.AddError(err) 1419 } 1420 }() 1421 } 1422 1423 // validate 1424 if sd.sdClient == nil { 1425 err = errors.New("CloudMap ListService Failed: " + "SD Client is Required") 1426 return nil, "", err 1427 } 1428 1429 if maxResults != nil { 1430 if *maxResults <= 0 { 1431 err = errors.New("CloudMap ListServices Failed: " + "MaxResults Must Be Greater Than Zero") 1432 return nil, "", err 1433 } 1434 } 1435 1436 // define input 1437 input := &servicediscovery.ListServicesInput{} 1438 1439 if len(filter) == 1 { 1440 input.Filters = []*servicediscovery.ServiceFilter{ 1441 { 1442 Name: aws.String("NAMESPACE_ID"), 1443 Condition: aws.String("EQ"), 1444 Values: []*string{ 1445 aws.String(filter[0]), 1446 }, 1447 }, 1448 } 1449 } else if len(filter) > 1 { 1450 input.Filters = []*servicediscovery.ServiceFilter{ 1451 { 1452 Name: aws.String("NAMESPACE_ID"), 1453 Condition: aws.String("IN"), 1454 }, 1455 } 1456 1457 var fv []string 1458 1459 for _, v := range filter { 1460 fv = append(fv, v) 1461 } 1462 1463 input.Filters[0].Values = aws.StringSlice(fv) 1464 } 1465 1466 if maxResults != nil { 1467 input.MaxResults = maxResults 1468 } 1469 1470 if nextToken != nil { 1471 if util.LenTrim(*nextToken) > 0 { 1472 input.NextToken = nextToken 1473 } 1474 } 1475 1476 // invoke action 1477 var output *servicediscovery.ListServicesOutput 1478 1479 if len(timeOutDuration) > 0 { 1480 ctx, cancel := context.WithTimeout(segCtx, timeOutDuration[0]) 1481 defer cancel() 1482 1483 output, err = sd.sdClient.ListServicesWithContext(ctx, input) 1484 } else { 1485 if segCtxSet { 1486 output, err = sd.sdClient.ListServicesWithContext(segCtx, input) 1487 } else { 1488 output, err = sd.sdClient.ListServices(input) 1489 } 1490 } 1491 1492 if err != nil { 1493 // handle error 1494 err = errors.New("CloudMap ListServices Failed: (List Action) " + err.Error()) 1495 return nil, "", err 1496 } 1497 1498 return output.Services, *output.NextToken, nil 1499 } 1500 1501 // ListServicesPages lists summary information about all the services associated with one or more namespaces 1502 // (issues multiple page requests until max results is met or all data is retrieved) 1503 // 1504 // Parameters: 1505 // 1. filter = (optional) filter by namespace(s) as specified, slice of namespaceId to filter 1506 // 2. maxResults = (optional) specifies maximum count to return 1507 // 3. nextToken = (optional) if initial action, leave blank; if this is a subsequent action to get more, input the moreNextToken returned from a prior action 1508 // 4. timeOutDuration = (optional) maximum time before timeout via context 1509 // 1510 // Return Values: 1511 // 1. namespaces = slice of sd service summary objects 1512 // 2. moreNextToken = if more data exists, this token can be used in a subsequent action via nextToken parameter 1513 // 3. err = error info if any 1514 func (sd *CloudMap) ListServicesPages(filter []string, 1515 maxResults *int64, 1516 nextToken *string, 1517 timeOutDuration ...time.Duration) (services []*servicediscovery.ServiceSummary, moreNextToken string, err error) { 1518 segCtx := context.Background() 1519 segCtxSet := false 1520 1521 seg := xray.NewSegmentNullable("Cloudmap-ListServicesPages", sd._parentSegment) 1522 1523 if seg != nil { 1524 segCtx = seg.Ctx 1525 segCtxSet = true 1526 1527 defer seg.Close() 1528 defer func() { 1529 _ = seg.Seg.AddMetadata("Cloudmap-ListServicesPages-Filter", filter) 1530 _ = seg.Seg.AddMetadata("Cloudmap-ListServicesPages-MaxResults", maxResults) 1531 _ = seg.Seg.AddMetadata("Cloudmap-ListServicesPages-NextToken", nextToken) 1532 _ = seg.Seg.AddMetadata("Cloudmap-ListServicesPages-Result-Services", services) 1533 _ = seg.Seg.AddMetadata("Cloudmap-ListServicesPages-Result-NextToken", moreNextToken) 1534 1535 if err != nil { 1536 _ = seg.Seg.AddError(err) 1537 } 1538 }() 1539 } 1540 1541 // validate 1542 if sd.sdClient == nil { 1543 err = errors.New("CloudMap ListServicesPages Failed: " + "SD Client is Required") 1544 return nil, "", err 1545 } 1546 1547 if maxResults != nil { 1548 if *maxResults <= 0 { 1549 err = errors.New("CloudMap ListServicesPages Failed: " + "MaxResults Must Be Greater Than Zero") 1550 return nil, "", err 1551 } 1552 } 1553 1554 // define input 1555 input := &servicediscovery.ListServicesInput{} 1556 1557 if len(filter) == 1 { 1558 input.Filters = []*servicediscovery.ServiceFilter{ 1559 { 1560 Name: aws.String("NAMESPACE_ID"), 1561 Condition: aws.String("EQ"), 1562 Values: []*string{ 1563 aws.String(filter[0]), 1564 }, 1565 }, 1566 } 1567 } else if len(filter) > 1 { 1568 input.Filters = []*servicediscovery.ServiceFilter{ 1569 { 1570 Name: aws.String("NAMESPACE_ID"), 1571 Condition: aws.String("IN"), 1572 }, 1573 } 1574 1575 var fv []string 1576 1577 for _, v := range filter { 1578 fv = append(fv, v) 1579 } 1580 1581 input.Filters[0].Values = aws.StringSlice(fv) 1582 } 1583 1584 if maxResults != nil { 1585 input.MaxResults = maxResults 1586 } 1587 1588 if nextToken != nil { 1589 if util.LenTrim(*nextToken) > 0 { 1590 input.NextToken = nextToken 1591 } 1592 } 1593 1594 // invoke action 1595 fn := func(pageOutput *servicediscovery.ListServicesOutput, lastPage bool) bool { 1596 if pageOutput != nil { 1597 moreNextToken = *pageOutput.NextToken 1598 services = append(services, pageOutput.Services...) 1599 } 1600 1601 return !lastPage 1602 } 1603 1604 if len(timeOutDuration) > 0 { 1605 ctx, cancel := context.WithTimeout(segCtx, timeOutDuration[0]) 1606 defer cancel() 1607 1608 err = sd.sdClient.ListServicesPagesWithContext(ctx, input, fn) 1609 } else { 1610 if segCtxSet { 1611 err = sd.sdClient.ListServicesPagesWithContext(segCtx, input, fn) 1612 } else { 1613 err = sd.sdClient.ListServicesPages(input, fn) 1614 } 1615 } 1616 1617 if err != nil { 1618 // handle error 1619 err = errors.New("CloudMap ListServicesPages Failed: (ListPages Action) " + err.Error()) 1620 return nil, "", err 1621 } 1622 1623 return services, moreNextToken, nil 1624 } 1625 1626 // DeleteService deletes the specified service, 1627 // 1628 // if the service still contains one or more registered instances, the delete action will fail 1629 // 1630 // Parameters: 1631 // 1. serviceId = (required) service to be deleted via the specified service id 1632 // 2. timeOutDuration = (optional) maximum time before timeout via context 1633 // 1634 // Return Values: 1635 // 1. err = nil indicates success; contains error info if error was encountered 1636 func (sd *CloudMap) DeleteService(serviceId string, timeOutDuration ...time.Duration) (err error) { 1637 segCtx := context.Background() 1638 segCtxSet := false 1639 1640 seg := xray.NewSegmentNullable("Cloudmap-DeleteService", sd._parentSegment) 1641 1642 if seg != nil { 1643 segCtx = seg.Ctx 1644 segCtxSet = true 1645 1646 defer seg.Close() 1647 defer func() { 1648 _ = seg.Seg.AddMetadata("Cloudmap-DeleteService-ServiceID", serviceId) 1649 1650 if err != nil { 1651 _ = seg.Seg.AddError(err) 1652 } 1653 }() 1654 } 1655 1656 // validate 1657 if sd.sdClient == nil { 1658 err = errors.New("CloudMap DeleteService Failed: " + "SD Client is Required") 1659 return err 1660 } 1661 1662 if util.LenTrim(serviceId) == 0 { 1663 err = errors.New("CloudMap DeleteService Failed: " + "ServiceId is Required") 1664 return err 1665 } 1666 1667 // define input 1668 input := &servicediscovery.DeleteServiceInput{ 1669 Id: aws.String(serviceId), 1670 } 1671 1672 // invoke action 1673 if len(timeOutDuration) > 0 { 1674 ctx, cancel := context.WithTimeout(segCtx, timeOutDuration[0]) 1675 defer cancel() 1676 1677 _, err = sd.sdClient.DeleteServiceWithContext(ctx, input) 1678 } else { 1679 if segCtxSet { 1680 _, err = sd.sdClient.DeleteServiceWithContext(segCtx, input) 1681 } else { 1682 _, err = sd.sdClient.DeleteService(input) 1683 } 1684 } 1685 1686 if err != nil { 1687 // handle error 1688 err = errors.New("CloudMap DeleteService Failed: (Delete Action) " + err.Error()) 1689 return err 1690 } 1691 1692 return nil 1693 } 1694 1695 // ---------------------------------------------------------------------------------------------------------------- 1696 // instance functions 1697 // ---------------------------------------------------------------------------------------------------------------- 1698 1699 // RegisterInstance creates or updates one or more records, 1700 // 1701 // and optionally creates a health check based on settings from the specified service 1702 // 1703 // When RegisterInstance() request is submitted: 1704 // 1. for each dns record defined in the service as specified by ServiceId, 1705 // a record is created or updated in the hosted zone that is associated with the corresponding namespace 1706 // 2. if the service includes HealthCheckConfig, 1707 // a health check is created based on the settings in the health check configuration 1708 // 3. the health check is associated with each of the new or updated records (if applicable) 1709 // 1710 // # One RegisterInstance() request must complete before another is submitted 1711 // 1712 // When AWS cloud map receives a dns query for the specified dns name, 1713 // 1. if the health check is healthy, all records returned 1714 // 2. if the health check is unhealthy, applicable value for the last healthy instance is returned 1715 // 3. if health check configuration wasn't specified, then all records are returned regardless healthy or otherwise 1716 // 1717 // Parameters: 1718 // 1. serviceId = (required) register instance to this serviceId 1719 // 2. instanceId = (required) unique value for this instance, if instanceId already exists, this action will update instead of new 1720 // 3. creatorRequestId = (required) unique request id to use in case of a failure (during fail-retry, use the same creatorRequestId 1721 // 4. attributes = (required) map of attributes to register for this instance with the given serviceId, keys are as follows: 1722 // a) AWS_ALIAS_DNS_NAME = instruct cloud map to create route 53 alias record to route traffic to an ELB, 1723 // set the dns name associated with the load balancer to this key, 1724 // the associated service RoutingPolicy must be WEIGHTED, 1725 // when this key is set, DO NOT set values to any other AWS_INSTANCE attributes 1726 // b) AWS_EC2_INSTANCE_ID = for http namespace only, sets this instance's EC2 instance ID, 1727 // when this key is set, ONLY OTHER key allowed is AWS_INIT_HEALTH_STATUS, 1728 // when this key is set, the AWS_INSTANCE_IPV4 attribute will be filled with the primary private IPv4 address 1729 // c) AWS_INIT_HEALTH_STATUS = if associated service includes HealthCheckCustomConfig, 1730 // then this key may be optionally set to specify the initial status of custom health check: HEALTHY or UNHEALTHY, 1731 // if this key is not set, then initial status is HEALTHY 1732 // d) AWS_INSTANCE_IPV4 = if associated service dns record type is A, then set the IPv4 address to this key, 1733 // this key is required for service dns record type A 1734 // e) AWS_INSTANCE_PORT = if associated service includes HealthCheckConfig, 1735 // set the port for this endpoint that route 53 will send health check request to, 1736 // this key is required for service having HealthCheckConfig set 1737 // f) Custom Attributes = up to 30 custom attribute key value pairs, 1738 // key must not exceed 255 chars, value must not exceed 1024 chars, 1739 // total of all custom attribute key value pairs combined cannot exceed 5000 chars 1740 // 1741 // Return Values: 1742 // 1. operationId = identifier to be used with GetOperation for status check (to verify completion of action) 1743 // 2. err = contains error info if any 1744 func (sd *CloudMap) RegisterInstance(serviceId string, 1745 instanceId string, 1746 creatorRequestId string, 1747 attributes map[string]string, 1748 timeOutDuration ...time.Duration) (operationId string, err error) { 1749 segCtx := context.Background() 1750 segCtxSet := false 1751 1752 seg := xray.NewSegmentNullable("Cloudmap-RegisterInstance", sd._parentSegment) 1753 1754 if seg != nil { 1755 segCtx = seg.Ctx 1756 segCtxSet = true 1757 1758 defer seg.Close() 1759 defer func() { 1760 _ = seg.Seg.AddMetadata("Cloudmap-RegisterInstance-ServiceID", serviceId) 1761 _ = seg.Seg.AddMetadata("Cloudmap-RegisterInstance-InstanceID", instanceId) 1762 _ = seg.Seg.AddMetadata("Cloudmap-RegisterInstance-CreatorRequestID", creatorRequestId) 1763 _ = seg.Seg.AddMetadata("Cloudmap-RegisterInstance-Attributes", attributes) 1764 _ = seg.Seg.AddMetadata("Cloudmap-RegisterInstance-Result-OperationID", operationId) 1765 1766 if err != nil { 1767 _ = seg.Seg.AddError(err) 1768 } 1769 }() 1770 } 1771 1772 // validate 1773 if sd.sdClient == nil { 1774 err = errors.New("CloudMap RegisterInstance Failed: " + "SD Client is Required") 1775 return "", err 1776 } 1777 1778 if util.LenTrim(serviceId) == 0 { 1779 err = errors.New("CloudMap RegisterInstance Failed: " + "ServiceId is Required") 1780 return "", err 1781 } 1782 1783 if util.LenTrim(instanceId) == 0 { 1784 err = errors.New("CloudMap RegisterInstance Failed: " + "InstanceId is Required") 1785 return "", err 1786 } 1787 1788 if util.LenTrim(creatorRequestId) == 0 { 1789 err = errors.New("CloudMap RegisterInstance Failed: " + "CreatorRequestId is Required") 1790 return "", err 1791 } 1792 1793 if attributes == nil { 1794 err = errors.New("CloudMap RegisterInstance Failed: " + "Attributes are Required (nil)") 1795 return "", err 1796 } 1797 1798 if len(attributes) == 0 { 1799 err = errors.New("CloudMap RegisterInstance Failed: " + "Attributes Are Required (len = 0)") 1800 return "", err 1801 } 1802 1803 // define input 1804 input := &servicediscovery.RegisterInstanceInput{ 1805 InstanceId: aws.String(instanceId), 1806 CreatorRequestId: aws.String(creatorRequestId), 1807 ServiceId: aws.String(serviceId), 1808 Attributes: aws.StringMap(attributes), 1809 } 1810 1811 // invoke action 1812 var output *servicediscovery.RegisterInstanceOutput 1813 1814 if len(timeOutDuration) > 0 { 1815 ctx, cancel := context.WithTimeout(segCtx, timeOutDuration[0]) 1816 defer cancel() 1817 1818 output, err = sd.sdClient.RegisterInstanceWithContext(ctx, input) 1819 } else { 1820 if segCtxSet { 1821 output, err = sd.sdClient.RegisterInstanceWithContext(segCtx, input) 1822 } else { 1823 output, err = sd.sdClient.RegisterInstance(input) 1824 } 1825 } 1826 1827 if err != nil { 1828 // handle error 1829 err = errors.New("CloudMap RegisterInstance Failed: (Register Action) " + err.Error()) 1830 return "", err 1831 } 1832 1833 return *output.OperationId, nil 1834 } 1835 1836 // UpdateInstanceCustomHealthStatus submits a request to change the health status of a custom health check, 1837 // 1838 // to healthy or unhealthy 1839 // 1840 // This action works only with configuration of Custom Health Checks, 1841 // 1842 // which was defined using HealthCheckCustomConfig when creating a service 1843 // 1844 // This action cannot be used to change the status of a route 53 health check, 1845 // 1846 // which was defined using HealthCheckConfig when creating a service 1847 // 1848 // Parameters: 1849 // 1. instanceId = (required) update healthy status to this instanceId 1850 // 2. serviceId = (required) the associated service 1851 // 3. isHealthy = specify the health status during this update action 1852 // 4. timeOutDuration = (optional) maximum time before timeout via context 1853 // 1854 // Return Values: 1855 // 1. err = nil indicates success; otherwise error info is included 1856 func (sd *CloudMap) UpdateInstanceCustomHealthStatus(instanceId string, 1857 serviceId string, 1858 isHealthy bool, 1859 timeOutDuration ...time.Duration) (err error) { 1860 segCtx := context.Background() 1861 segCtxSet := false 1862 1863 seg := xray.NewSegmentNullable("Cloudmap-UpdateInstanceCustomHealthStatus", sd._parentSegment) 1864 1865 if seg != nil { 1866 segCtx = seg.Ctx 1867 segCtxSet = true 1868 1869 defer seg.Close() 1870 defer func() { 1871 _ = seg.Seg.AddMetadata("Cloudmap-UpdateInstanceCustomHealthStatus-InstanceID", instanceId) 1872 _ = seg.Seg.AddMetadata("Cloudmap-UpdateInstanceCustomHealthStatus-ServiceID", serviceId) 1873 _ = seg.Seg.AddMetadata("Cloudmap-UpdateInstanceCustomHealthStatus-IsHealthy", isHealthy) 1874 1875 if err != nil { 1876 _ = seg.Seg.AddError(err) 1877 } 1878 }() 1879 } 1880 1881 // validate 1882 if sd.sdClient == nil { 1883 err = errors.New("CloudMap UpdateInstanceCustomHealthStatus Failed: " + "SD Client is Required") 1884 return err 1885 } 1886 1887 if util.LenTrim(instanceId) == 0 { 1888 err = errors.New("CloudMap UpdateInstanceCustomHealthStatus Failed: " + "InstanceId is Required") 1889 return err 1890 } 1891 1892 if util.LenTrim(serviceId) == 0 { 1893 err = errors.New("CloudMap UpdateInstanceCustomHealthStatus Failed: " + "ServiceId is Required") 1894 return err 1895 } 1896 1897 // define input 1898 healthStatus := "" 1899 1900 if isHealthy { 1901 healthStatus = "HEALTHY" 1902 } else { 1903 healthStatus = "UNHEALTHY" 1904 } 1905 1906 input := &servicediscovery.UpdateInstanceCustomHealthStatusInput{ 1907 InstanceId: aws.String(instanceId), 1908 ServiceId: aws.String(serviceId), 1909 Status: aws.String(healthStatus), 1910 } 1911 1912 // invoke action 1913 if len(timeOutDuration) > 0 { 1914 ctx, cancel := context.WithTimeout(segCtx, timeOutDuration[0]) 1915 defer cancel() 1916 1917 _, err = sd.sdClient.UpdateInstanceCustomHealthStatusWithContext(ctx, input) 1918 } else { 1919 if segCtxSet { 1920 _, err = sd.sdClient.UpdateInstanceCustomHealthStatusWithContext(segCtx, input) 1921 } else { 1922 _, err = sd.sdClient.UpdateInstanceCustomHealthStatus(input) 1923 } 1924 } 1925 1926 if err != nil { 1927 // handle error 1928 err = errors.New("CloudMap UpdateInstanceCustomHealthStatus Failed: (Update Action) " + err.Error()) 1929 return err 1930 } 1931 1932 return nil 1933 } 1934 1935 // DeregisterInstance deletes the route 53 dns record and health check (if any), 1936 // 1937 // that was created by cloud map for the specified instance 1938 // 1939 // Parameters: 1940 // 1. instanceId = (required) instance to deregister 1941 // 2. serviceId = (required) the associated service 1942 // 1943 // Return Values: 1944 // 1. operationId = operation identifier to be used with GetOperation for action completion status check 1945 // 2. err = error info if any 1946 func (sd *CloudMap) DeregisterInstance(instanceId string, 1947 serviceId string, 1948 timeOutDuration ...time.Duration) (operationId string, err error) { 1949 segCtx := context.Background() 1950 segCtxSet := false 1951 1952 seg := xray.NewSegmentNullable("Cloudmap-DeregisterInstance", sd._parentSegment) 1953 1954 if seg != nil { 1955 segCtx = seg.Ctx 1956 segCtxSet = true 1957 1958 defer seg.Close() 1959 defer func() { 1960 _ = seg.Seg.AddMetadata("Cloudmap-DeregisterInstance-InstanceID", instanceId) 1961 _ = seg.Seg.AddMetadata("Cloudmap-DeregisterInstance-ServiceID", serviceId) 1962 _ = seg.Seg.AddMetadata("Cloudmap-DeregisterInstance-Result-OperationID", operationId) 1963 1964 if err != nil { 1965 _ = seg.Seg.AddError(err) 1966 } 1967 }() 1968 } 1969 1970 // validate 1971 if sd.sdClient == nil { 1972 err = errors.New("CloudMap DeregisterInstance Failed: " + "SD Client is Required") 1973 return "", err 1974 } 1975 1976 if util.LenTrim(instanceId) == 0 { 1977 err = errors.New("CloudMap DeregisterInstance Failed: " + "InstanceId is Required") 1978 return "", err 1979 } 1980 1981 if util.LenTrim(serviceId) == 0 { 1982 err = errors.New("CloudMap DeregisterInstance Failed: " + "ServiceId is Required") 1983 return "", err 1984 } 1985 1986 // define input 1987 input := &servicediscovery.DeregisterInstanceInput{ 1988 InstanceId: aws.String(instanceId), 1989 ServiceId: aws.String(serviceId), 1990 } 1991 1992 // invoke action 1993 var output *servicediscovery.DeregisterInstanceOutput 1994 1995 if len(timeOutDuration) > 0 { 1996 ctx, cancel := context.WithTimeout(segCtx, timeOutDuration[0]) 1997 defer cancel() 1998 1999 output, err = sd.sdClient.DeregisterInstanceWithContext(ctx, input) 2000 } else { 2001 if segCtxSet { 2002 output, err = sd.sdClient.DeregisterInstanceWithContext(segCtx, input) 2003 } else { 2004 output, err = sd.sdClient.DeregisterInstance(input) 2005 } 2006 } 2007 2008 if err != nil { 2009 // handle error 2010 err = errors.New("CloudMap DeregisterInstance Failed: (Deregister Action) " + err.Error()) 2011 return "", err 2012 } 2013 2014 return *output.OperationId, nil 2015 } 2016 2017 // GetInstance gets information about a specified instance 2018 // 2019 // Parameters: 2020 // 1. instanceId = (required) instance to get 2021 // 2. serviceId = (required) the associated service 2022 // 2023 // Return Values: 2024 // 1. instance = instance object retrieved 2025 // 2. err = error info if any 2026 func (sd *CloudMap) GetInstance(instanceId string, 2027 serviceId string, 2028 timeOutDuration ...time.Duration) (instance *servicediscovery.Instance, err error) { 2029 segCtx := context.Background() 2030 segCtxSet := false 2031 2032 seg := xray.NewSegmentNullable("Cloudmap-GetInstance", sd._parentSegment) 2033 2034 if seg != nil { 2035 segCtx = seg.Ctx 2036 segCtxSet = true 2037 2038 defer seg.Close() 2039 defer func() { 2040 _ = seg.Seg.AddMetadata("Cloudmap-GetInstance-InstanceID", instanceId) 2041 _ = seg.Seg.AddMetadata("Cloudmap-GetInstance-ServiceID", serviceId) 2042 _ = seg.Seg.AddMetadata("Cloudmap-GetInstance-Result-Instance", instance) 2043 2044 if err != nil { 2045 _ = seg.Seg.AddError(err) 2046 } 2047 }() 2048 } 2049 2050 // validate 2051 if sd.sdClient == nil { 2052 err = errors.New("CloudMap GetInstance Failed: " + "SD Client is Required") 2053 return nil, err 2054 } 2055 2056 if util.LenTrim(instanceId) == 0 { 2057 err = errors.New("CloudMap GetInstance Failed: " + "InstanceId is Required") 2058 return nil, err 2059 } 2060 2061 if util.LenTrim(serviceId) == 0 { 2062 err = errors.New("CloudMap GetInstance Failed: " + "ServiceId is Required") 2063 return nil, err 2064 } 2065 2066 // define input 2067 input := &servicediscovery.GetInstanceInput{ 2068 InstanceId: aws.String(instanceId), 2069 ServiceId: aws.String(serviceId), 2070 } 2071 2072 // invoke action 2073 var output *servicediscovery.GetInstanceOutput 2074 2075 if len(timeOutDuration) > 0 { 2076 ctx, cancel := context.WithTimeout(segCtx, timeOutDuration[0]) 2077 defer cancel() 2078 2079 output, err = sd.sdClient.GetInstanceWithContext(ctx, input) 2080 } else { 2081 if segCtxSet { 2082 output, err = sd.sdClient.GetInstanceWithContext(segCtx, input) 2083 } else { 2084 output, err = sd.sdClient.GetInstance(input) 2085 } 2086 } 2087 2088 if err != nil { 2089 // handle error 2090 err = errors.New("CloudMap GetInstance Failed: (Get Action) " + err.Error()) 2091 return nil, err 2092 } 2093 2094 return output.Instance, nil 2095 } 2096 2097 // GetInstancesHealthStatus gets the current health status (healthy, unhealthy, unknown) of one or more instances, 2098 // 2099 // that are associated with a specified service 2100 // 2101 // # There is a brief delay between register an instance and when the health status for the instance is available 2102 // 2103 // Parameters: 2104 // 1. serviceId = (required) service id assciated with the instances being checked 2105 // 2. instanceIds = (optional) list of instance ids to check health status on, if omitted, then all instances of given service is checked 2106 // 3. maxResults = (optional) specifies maximum count to return 2107 // 4. nextToken = (optional) if initial action, leave blank; if this is a subsequent action to get more, input the moreNextToken returned from a prior action 2108 // 5. timeOutDuration = (optional) maximum time before timeout via context 2109 // 2110 // Return Values: 2111 // 1. status = map of instance status (key = instance id, value = health status 'healthy', 'unhealthy', 'unknown') 2112 // 2. moreNextToken = if more data exists, this token can be used in a subsequent action via nextToken parameter 2113 // 3. err = error info if any 2114 func (sd *CloudMap) GetInstancesHealthStatus(serviceId string, 2115 instanceIds []string, 2116 maxResults *int64, 2117 nextToken *string, 2118 timeOutDuration ...time.Duration) (status map[string]string, moreNextToken string, err error) { 2119 segCtx := context.Background() 2120 segCtxSet := false 2121 2122 seg := xray.NewSegmentNullable("Cloudmap-GetInstancesHealthStatus", sd._parentSegment) 2123 2124 if seg != nil { 2125 segCtx = seg.Ctx 2126 segCtxSet = true 2127 2128 defer seg.Close() 2129 defer func() { 2130 _ = seg.Seg.AddMetadata("Cloudmap-GetInstancesHealthStatus-ServiceID", serviceId) 2131 _ = seg.Seg.AddMetadata("Cloudmap-GetInstancesHealthStatus-InstanceIDs", instanceIds) 2132 _ = seg.Seg.AddMetadata("Cloudmap-GetInstancesHealthStatus-MaxResults", maxResults) 2133 _ = seg.Seg.AddMetadata("Cloudmap-GetInstancesHealthStatus-NextToken", nextToken) 2134 _ = seg.Seg.AddMetadata("Cloudmap-GetInstancesHealthStatus-Result-Status", status) 2135 _ = seg.Seg.AddMetadata("Cloudmap-GetInstancesHealthStatus-Result-NextToken", moreNextToken) 2136 2137 if err != nil { 2138 _ = seg.Seg.AddError(err) 2139 } 2140 }() 2141 } 2142 2143 // validate 2144 if sd.sdClient == nil { 2145 err = errors.New("CloudMap GetInstancesHealthStatus Failed: " + "SD Client is Required") 2146 return nil, "", err 2147 } 2148 2149 if maxResults != nil { 2150 if *maxResults <= 0 { 2151 err = errors.New("CloudMap GetInstancesHealthStatus Failed: " + "MaxResults Must Be Greater Than Zero") 2152 return nil, "", err 2153 } 2154 } 2155 2156 // define input 2157 input := &servicediscovery.GetInstancesHealthStatusInput{ 2158 ServiceId: aws.String(serviceId), 2159 } 2160 2161 if len(instanceIds) > 0 { 2162 input.Instances = aws.StringSlice(instanceIds) 2163 } 2164 2165 if maxResults != nil { 2166 input.MaxResults = maxResults 2167 } 2168 2169 if nextToken != nil { 2170 if util.LenTrim(*nextToken) > 0 { 2171 input.NextToken = nextToken 2172 } 2173 } 2174 2175 // invoke action 2176 var output *servicediscovery.GetInstancesHealthStatusOutput 2177 2178 if len(timeOutDuration) > 0 { 2179 ctx, cancel := context.WithTimeout(segCtx, timeOutDuration[0]) 2180 defer cancel() 2181 2182 output, err = sd.sdClient.GetInstancesHealthStatusWithContext(ctx, input) 2183 } else { 2184 if segCtxSet { 2185 output, err = sd.sdClient.GetInstancesHealthStatusWithContext(segCtx, input) 2186 } else { 2187 output, err = sd.sdClient.GetInstancesHealthStatus(input) 2188 } 2189 } 2190 2191 if err != nil { 2192 // handle error 2193 err = errors.New("CloudMap GetInstancesHealthStatus Failed: (Get Action) " + err.Error()) 2194 return nil, "", err 2195 } 2196 2197 return aws.StringValueMap(output.Status), *output.NextToken, nil 2198 } 2199 2200 // GetInstancesHealthStatusPages gets the current health status (healthy, unhealthy, unknown) of one or more instances, 2201 // 2202 // that are associated with a specified service 2203 // (issues multiple page requests until max results is met or all data is retrieved) 2204 // 2205 // # There is a brief delay between register an instance and when the health status for the instance is available 2206 // 2207 // Parameters: 2208 // 1. serviceId = (required) service id assciated with the instances being checked 2209 // 2. instanceIds = (optional) list of instance ids to check health status on, if omitted, then all instances of given service is checked 2210 // 3. maxResults = (optional) specifies maximum count to return 2211 // 4. nextToken = (optional) if initial action, leave blank; if this is a subsequent action to get more, input the moreNextToken returned from a prior action 2212 // 5. timeOutDuration = (optional) maximum time before timeout via context 2213 // 2214 // Return Values: 2215 // 1. status = map of instance status (key = instance id, value = health status 'healthy', 'unhealthy', 'unknown') 2216 // 2. moreNextToken = if more data exists, this token can be used in a subsequent action via nextToken parameter 2217 // 3. err = error info if any 2218 func (sd *CloudMap) GetInstancesHealthStatusPages(serviceId string, 2219 instanceIds []string, 2220 maxResults *int64, 2221 nextToken *string, 2222 timeOutDuration ...time.Duration) (status map[string]string, moreNextToken string, err error) { 2223 segCtx := context.Background() 2224 segCtxSet := false 2225 2226 seg := xray.NewSegmentNullable("Cloudmap-GetInstancesHealthStatusPages", sd._parentSegment) 2227 2228 if seg != nil { 2229 segCtx = seg.Ctx 2230 segCtxSet = true 2231 2232 defer seg.Close() 2233 defer func() { 2234 _ = seg.Seg.AddMetadata("Cloudmap-GetInstancesHealthStatusPages-ServiceID", serviceId) 2235 _ = seg.Seg.AddMetadata("Cloudmap-GetInstancesHealthStatusPages-InstanceIDs", instanceIds) 2236 _ = seg.Seg.AddMetadata("Cloudmap-GetInstancesHealthStatusPages-MaxResults", maxResults) 2237 _ = seg.Seg.AddMetadata("Cloudmap-GetInstancesHealthStatusPages-NextToken", nextToken) 2238 _ = seg.Seg.AddMetadata("Cloudmap-GetInstancesHealthStatusPages-Result-Status", status) 2239 _ = seg.Seg.AddMetadata("Cloudmap-GetInstancesHealthStatusPages-Result-NextToken", moreNextToken) 2240 2241 if err != nil { 2242 _ = seg.Seg.AddError(err) 2243 } 2244 }() 2245 } 2246 2247 // validate 2248 if sd.sdClient == nil { 2249 err = errors.New("CloudMap GetInstancesHealthStatusPages Failed: " + "SD Client is Required") 2250 return nil, "", err 2251 } 2252 2253 if maxResults != nil { 2254 if *maxResults <= 0 { 2255 err = errors.New("CloudMap GetInstancesHealthStatusPages Failed: " + "MaxResults Must Be Greater Than Zero") 2256 return nil, "", err 2257 } 2258 } 2259 2260 // define input 2261 input := &servicediscovery.GetInstancesHealthStatusInput{ 2262 ServiceId: aws.String(serviceId), 2263 } 2264 2265 if len(instanceIds) > 0 { 2266 input.Instances = aws.StringSlice(instanceIds) 2267 } 2268 2269 if maxResults != nil { 2270 input.MaxResults = maxResults 2271 } 2272 2273 if nextToken != nil { 2274 if util.LenTrim(*nextToken) > 0 { 2275 input.NextToken = nextToken 2276 } 2277 } 2278 2279 // invoke action 2280 fn := func(pageOutput *servicediscovery.GetInstancesHealthStatusOutput, lastPage bool) bool { 2281 if pageOutput != nil { 2282 moreNextToken = *pageOutput.NextToken 2283 m := aws.StringValueMap(pageOutput.Status) 2284 2285 if status == nil { 2286 status = make(map[string]string) 2287 } 2288 2289 for k, v := range m { 2290 status[k] = v 2291 } 2292 } 2293 2294 return !lastPage 2295 } 2296 2297 if len(timeOutDuration) > 0 { 2298 ctx, cancel := context.WithTimeout(segCtx, timeOutDuration[0]) 2299 defer cancel() 2300 2301 err = sd.sdClient.GetInstancesHealthStatusPagesWithContext(ctx, input, fn) 2302 } else { 2303 if segCtxSet { 2304 err = sd.sdClient.GetInstancesHealthStatusPagesWithContext(segCtx, input, fn) 2305 } else { 2306 err = sd.sdClient.GetInstancesHealthStatusPages(input, fn) 2307 } 2308 } 2309 2310 if err != nil { 2311 // handle error 2312 err = errors.New("CloudMap GetInstancesHealthStatusPages Failed: (ListPages Action) " + err.Error()) 2313 return nil, "", err 2314 } 2315 2316 return status, moreNextToken, nil 2317 } 2318 2319 // DiscoverInstances discovers registered instances for a specified namespace and service 2320 // 2321 // Notes: 2322 // 1. Used to discover instances for any type of namespace (http, private dns, public dns) 2323 // 2. For public and private dns namespaces, 2324 // may also use dns queries to discover distances instead 2325 // 2326 // Parameters: 2327 // 1. namespaceName = (required) name of the namespace to be discovered 2328 // 2. serviceName = (required) name of the service to be discovered 2329 // 3. isHealthy = (required) discover healthy or unhealthy instances 2330 // 4. queryParameters = (optional) map of key value pairs, containing custom attributes registered during RegisterInstance, 2331 // if custom attributes is specified, all attributes in the queryParameters must match for the instance to discover 2332 // 5. maxResults = (optional) max count of discovered instances to return, if not specified, up to 100 is returned 2333 // 6. timeOutDuration = (optional) maximum time before timeout via context 2334 // 2335 // Return Values: 2336 // 1. instances = slice of discovered instance objects 2337 // 2. err = error info if any 2338 func (sd *CloudMap) DiscoverInstances(namespaceName string, 2339 serviceName string, 2340 isHealthy bool, 2341 queryParameters map[string]string, 2342 maxResults *int64, 2343 timeOutDuration ...time.Duration) (instances []*servicediscovery.HttpInstanceSummary, err error) { 2344 segCtx := context.Background() 2345 segCtxSet := false 2346 2347 seg := xray.NewSegmentNullable("Cloudmap-DiscoverInstances", sd._parentSegment) 2348 2349 if seg != nil { 2350 segCtx = seg.Ctx 2351 segCtxSet = true 2352 2353 defer seg.Close() 2354 defer func() { 2355 _ = seg.Seg.AddMetadata("Cloudmap-DiscoverInstances-NamespaceName", namespaceName) 2356 _ = seg.Seg.AddMetadata("Cloudmap-DiscoverInstances-ServiceName", serviceName) 2357 _ = seg.Seg.AddMetadata("Cloudmap-DiscoverInstances-IsHealthy", isHealthy) 2358 _ = seg.Seg.AddMetadata("Cloudmap-DiscoverInstances-QueryParameters", queryParameters) 2359 _ = seg.Seg.AddMetadata("Cloudmap-DiscoverInstances-MaxResults", maxResults) 2360 _ = seg.Seg.AddMetadata("Cloudmap-DiscoverInstances-Result-Instances", instances) 2361 2362 if err != nil { 2363 _ = seg.Seg.AddError(err) 2364 } 2365 }() 2366 } 2367 2368 // validate 2369 if sd.sdClient == nil { 2370 err = errors.New("CloudMap DiscoverInstances Failed: " + "SD Client is Required") 2371 return nil, err 2372 } 2373 2374 if util.LenTrim(namespaceName) == 0 { 2375 err = errors.New("CloudMap DiscoverInstances Failed: " + "Namespace Name is Required") 2376 return nil, err 2377 } 2378 2379 if util.LenTrim(serviceName) == 0 { 2380 err = errors.New("CloudMap DiscoverInstances Failed: " + "Service Name is Required") 2381 return nil, err 2382 } 2383 2384 // define input 2385 healthStatus := "" 2386 2387 if isHealthy { 2388 healthStatus = "HEALTHY" 2389 } else { 2390 healthStatus = "UNHEALTHY" 2391 } 2392 2393 input := &servicediscovery.DiscoverInstancesInput{ 2394 NamespaceName: aws.String(namespaceName), 2395 ServiceName: aws.String(serviceName), 2396 HealthStatus: aws.String(healthStatus), 2397 } 2398 2399 if queryParameters != nil && len(queryParameters) > 0 { 2400 input.QueryParameters = aws.StringMap(queryParameters) 2401 } 2402 2403 if maxResults != nil && *maxResults > 0 { 2404 input.MaxResults = maxResults 2405 } 2406 2407 // invoke action 2408 var output *servicediscovery.DiscoverInstancesOutput 2409 2410 if len(timeOutDuration) > 0 { 2411 ctx, cancel := context.WithTimeout(segCtx, timeOutDuration[0]) 2412 defer cancel() 2413 2414 output, err = sd.sdClient.DiscoverInstancesWithContext(ctx, input) 2415 } else { 2416 if segCtxSet { 2417 output, err = sd.sdClient.DiscoverInstancesWithContext(segCtx, input) 2418 } else { 2419 output, err = sd.sdClient.DiscoverInstances(input) 2420 } 2421 } 2422 2423 if err != nil { 2424 // handle error 2425 err = errors.New("CloudMap DiscoverInstances Failed: (Discover Action) " + err.Error()) 2426 return nil, err 2427 } 2428 2429 return output.Instances, nil 2430 } 2431 2432 // ListInstances lists summary information about the instances registered using a specified service 2433 // 2434 // Parameters: 2435 // 1. serviceId = (required) service id assciated with the instances being checked 2436 // 2. maxResults = (optional) specifies maximum count to return 2437 // 3. nextToken = (optional) if initial action, leave blank; if this is a subsequent action to get more, input the moreNextToken returned from a prior action 2438 // 4. timeOutDuration = (optional) maximum time before timeout via context 2439 // 2440 // Return Values: 2441 // 1. instances = slice of sd instance summary objects 2442 // 2. moreNextToken = if more data exists, this token can be used in a subsequent action via nextToken parameter 2443 // 3. err = error info if any 2444 func (sd *CloudMap) ListInstances(serviceId string, 2445 maxResults *int64, 2446 nextToken *string, 2447 timeOutDuration ...time.Duration) (instances []*servicediscovery.InstanceSummary, moreNextToken string, err error) { 2448 segCtx := context.Background() 2449 segCtxSet := false 2450 2451 seg := xray.NewSegmentNullable("Cloudmap-ListInstances", sd._parentSegment) 2452 2453 if seg != nil { 2454 segCtx = seg.Ctx 2455 segCtxSet = true 2456 2457 defer seg.Close() 2458 defer func() { 2459 _ = seg.Seg.AddMetadata("Cloudmap-ListInstances-ServiceID", serviceId) 2460 _ = seg.Seg.AddMetadata("Cloudmap-ListInstances-MaxResults", maxResults) 2461 _ = seg.Seg.AddMetadata("Cloudmap-ListInstances-NextToken", nextToken) 2462 _ = seg.Seg.AddMetadata("Cloudmap-ListInstances-Result-Instances", instances) 2463 _ = seg.Seg.AddMetadata("Cloudmap-ListInstances-Result-NextToken", moreNextToken) 2464 2465 if err != nil { 2466 _ = seg.Seg.AddError(err) 2467 } 2468 }() 2469 } 2470 2471 // validate 2472 if sd.sdClient == nil { 2473 err = errors.New("CloudMap ListInstances Failed: " + "SD Client is Required") 2474 return nil, "", err 2475 } 2476 2477 if util.LenTrim(serviceId) == 0 { 2478 err = errors.New("CloudMap ListInstances Failed: " + "Service ID is Required") 2479 return nil, "", err 2480 } 2481 2482 if maxResults != nil { 2483 if *maxResults <= 0 { 2484 err = errors.New("CloudMap ListInstances Failed: " + "MaxResults Must Be Greater Than Zero") 2485 return nil, "", err 2486 } 2487 } 2488 2489 // define input 2490 input := &servicediscovery.ListInstancesInput{ 2491 ServiceId: aws.String(serviceId), 2492 } 2493 2494 if maxResults != nil { 2495 input.MaxResults = maxResults 2496 } 2497 2498 if nextToken != nil { 2499 if util.LenTrim(*nextToken) > 0 { 2500 input.NextToken = nextToken 2501 } 2502 } 2503 2504 // invoke action 2505 var output *servicediscovery.ListInstancesOutput 2506 2507 if len(timeOutDuration) > 0 { 2508 ctx, cancel := context.WithTimeout(segCtx, timeOutDuration[0]) 2509 defer cancel() 2510 2511 output, err = sd.sdClient.ListInstancesWithContext(ctx, input) 2512 } else { 2513 if segCtxSet { 2514 output, err = sd.sdClient.ListInstancesWithContext(segCtx, input) 2515 } else { 2516 output, err = sd.sdClient.ListInstances(input) 2517 } 2518 } 2519 2520 if err != nil { 2521 // handle error 2522 err = errors.New("CloudMap ListInstances Failed: (List Action) " + err.Error()) 2523 return nil, "", err 2524 } 2525 2526 return output.Instances, *output.NextToken, nil 2527 } 2528 2529 // ListInstancesPages lists summary information about the instances registered using a specified service 2530 // (issues multiple page requests until max results is met or all data is retrieved) 2531 // 2532 // Parameters: 2533 // 1. serviceId = (required) service id assciated with the instances being checked 2534 // 2. maxResults = (optional) specifies maximum count to return 2535 // 3. nextToken = (optional) if initial action, leave blank; if this is a subsequent action to get more, input the moreNextToken returned from a prior action 2536 // 4. timeOutDuration = (optional) maximum time before timeout via context 2537 // 2538 // Return Values: 2539 // 1. instances = slice of sd instance summary objects 2540 // 2. moreNextToken = if more data exists, this token can be used in a subsequent action via nextToken parameter 2541 // 3. err = error info if any 2542 func (sd *CloudMap) ListInstancesPages(serviceId string, 2543 maxResults *int64, 2544 nextToken *string, 2545 timeOutDuration ...time.Duration) (instances []*servicediscovery.InstanceSummary, moreNextToken string, err error) { 2546 segCtx := context.Background() 2547 segCtxSet := false 2548 2549 seg := xray.NewSegmentNullable("Cloudmap-ListInstancesPages", sd._parentSegment) 2550 2551 if seg != nil { 2552 segCtx = seg.Ctx 2553 segCtxSet = true 2554 2555 defer seg.Close() 2556 defer func() { 2557 _ = seg.Seg.AddMetadata("Cloudmap-ListInstancesPages-ServiceID", serviceId) 2558 _ = seg.Seg.AddMetadata("Cloudmap-ListInstancesPages-MaxResults", maxResults) 2559 _ = seg.Seg.AddMetadata("Cloudmap-ListInstancesPages-NextToken", nextToken) 2560 _ = seg.Seg.AddMetadata("Cloudmap-ListInstancesPages-Result-Instances", instances) 2561 _ = seg.Seg.AddMetadata("Cloudmap-ListInstancesPages-Result-NextToken", moreNextToken) 2562 2563 if err != nil { 2564 _ = seg.Seg.AddError(err) 2565 } 2566 }() 2567 } 2568 2569 // validate 2570 if sd.sdClient == nil { 2571 err = errors.New("CloudMap ListInstancesPages Failed: " + "SD Client is Required") 2572 return nil, "", err 2573 } 2574 2575 if util.LenTrim(serviceId) == 0 { 2576 err = errors.New("CloudMap ListInstancesPages Failed: " + "Service ID is Required") 2577 return nil, "", err 2578 } 2579 2580 if maxResults != nil { 2581 if *maxResults <= 0 { 2582 err = errors.New("CloudMap ListInstancesPages Failed: " + "MaxResults Must Be Greater Than Zero") 2583 return nil, "", err 2584 } 2585 } 2586 2587 // define input 2588 input := &servicediscovery.ListInstancesInput{ 2589 ServiceId: aws.String(serviceId), 2590 } 2591 2592 if maxResults != nil { 2593 input.MaxResults = maxResults 2594 } 2595 2596 if nextToken != nil { 2597 if util.LenTrim(*nextToken) > 0 { 2598 input.NextToken = nextToken 2599 } 2600 } 2601 2602 // invoke action 2603 fn := func(pageOutput *servicediscovery.ListInstancesOutput, lastPage bool) bool { 2604 if pageOutput != nil { 2605 moreNextToken = *pageOutput.NextToken 2606 instances = append(instances, pageOutput.Instances...) 2607 } 2608 2609 return !lastPage 2610 } 2611 2612 if len(timeOutDuration) > 0 { 2613 ctx, cancel := context.WithTimeout(segCtx, timeOutDuration[0]) 2614 defer cancel() 2615 2616 err = sd.sdClient.ListInstancesPagesWithContext(ctx, input, fn) 2617 } else { 2618 if segCtxSet { 2619 err = sd.sdClient.ListInstancesPagesWithContext(segCtx, input, fn) 2620 } else { 2621 err = sd.sdClient.ListInstancesPages(input, fn) 2622 } 2623 } 2624 2625 if err != nil { 2626 // handle error 2627 err = errors.New("CloudMap ListInstancesPages Failed: (ListPages Action) " + err.Error()) 2628 return nil, "", err 2629 } 2630 2631 return instances, moreNextToken, nil 2632 } 2633 2634 // ---------------------------------------------------------------------------------------------------------------- 2635 // operation functions 2636 // ---------------------------------------------------------------------------------------------------------------- 2637 2638 // GetOperation gets information about any operation that returned an operationId in the response, 2639 // 2640 // such as CreateHttpNamespace(), CreateService(), etc 2641 // 2642 // Parameters: 2643 // 1. operationId = (required) the operation to retrieve, operationId is obtained during Create, and other related actions 2644 // 2. timeOutDuration = (optional) maximum time before timeout via context 2645 // 2646 // Return Values: 2647 // 1. operation = operation object retrieved 2648 // a) Targets = evaluate Targets to retrieve namespaceId, serviceId, InstanceId etc, using NAMESPACE, SERVICE, INSTANCE key names 2649 // 2. err = error info any 2650 func (sd *CloudMap) GetOperation(operationId string, timeOutDuration ...time.Duration) (operation *servicediscovery.Operation, err error) { 2651 segCtx := context.Background() 2652 segCtxSet := false 2653 2654 seg := xray.NewSegmentNullable("Cloudmap-GetOperation", sd._parentSegment) 2655 2656 if seg != nil { 2657 segCtx = seg.Ctx 2658 segCtxSet = true 2659 2660 defer seg.Close() 2661 defer func() { 2662 _ = seg.Seg.AddMetadata("Cloudmap-GetOperation-OperationID", operationId) 2663 _ = seg.Seg.AddMetadata("Cloudmap-GetOperation-Result-Operation", operation) 2664 2665 if err != nil { 2666 _ = seg.Seg.AddError(err) 2667 } 2668 }() 2669 } 2670 2671 // validate 2672 if sd.sdClient == nil { 2673 err = errors.New("CloudMap GetOperation Failed: " + "SD Client is Required") 2674 return nil, err 2675 } 2676 2677 if util.LenTrim(operationId) == 0 { 2678 err = errors.New("CloudMap GetOperation Failed: " + "OperationId is Required") 2679 return nil, err 2680 } 2681 2682 // define input 2683 input := &servicediscovery.GetOperationInput{ 2684 OperationId: aws.String(operationId), 2685 } 2686 2687 // invoke action 2688 var output *servicediscovery.GetOperationOutput 2689 2690 if len(timeOutDuration) > 0 { 2691 ctx, cancel := context.WithTimeout(segCtx, timeOutDuration[0]) 2692 defer cancel() 2693 2694 output, err = sd.sdClient.GetOperationWithContext(ctx, input) 2695 } else { 2696 if segCtxSet { 2697 output, err = sd.sdClient.GetOperationWithContext(segCtx, input) 2698 } else { 2699 output, err = sd.sdClient.GetOperation(input) 2700 } 2701 } 2702 2703 if err != nil { 2704 // handle error 2705 err = errors.New("CloudMap GetOperation Failed: (Get Action) " + err.Error()) 2706 return nil, err 2707 } 2708 2709 return output.Operation, nil 2710 } 2711 2712 // ListOperations lists operations that match the criteria specified in parameters 2713 // 2714 // Parameters: 2715 // 1. filter = (optional) map of filter operations (EQ_ filters allow single value per key) 2716 // a) EQ_Status / IN_Status = Valid Values: SUBMITTED, PENDING, SUCCEED, FAIL 2717 // b) EQ_Type / IN_Type = Valid Values: CREATE_NAMESPACE, DELETE_NAMESPACE, UPDATE_SERVICE, REGISTER_INSTANCE, DEREGISTER_INSTANCE 2718 // c) BETWEEN_UpdateDate = begin and end in Unix DateTime in UTC 2719 // 2. maxResults = (optional) specifies maximum count to return 2720 // 3. nextToken = (optional) if initial action, leave blank; if this is a subsequent action to get more, input the moreNextToken returned from a prior action 2721 // 4. timeOutDuration = (optional) maximum time before timeout via context 2722 // 2723 // Return Values: 2724 // 1. operations = slice of sd operation summary objects 2725 // a) Targets = evaluate Targets to retrieve namespaceId, serviceId, InstanceId etc, using NAMESPACE, SERVICE, INSTANCE key names 2726 // 2. moreNextToken = if more data exists, this token can be used in a subsequent action via nextToken parameter 2727 // 3. err = error info if any 2728 func (sd *CloudMap) ListOperations(filter map[sdoperationfilter.SdOperationFilter][]string, 2729 maxResults *int64, 2730 nextToken *string, 2731 timeOutDuration ...time.Duration) (operations []*servicediscovery.OperationSummary, moreNextToken string, err error) { 2732 segCtx := context.Background() 2733 segCtxSet := false 2734 2735 seg := xray.NewSegmentNullable("Cloudmap-ListOperations", sd._parentSegment) 2736 2737 if seg != nil { 2738 segCtx = seg.Ctx 2739 segCtxSet = true 2740 2741 defer seg.Close() 2742 defer func() { 2743 _ = seg.Seg.AddMetadata("Cloudmap-ListOperations-Filter", filter) 2744 _ = seg.Seg.AddMetadata("Cloudmap-ListOperations-MaxResults", maxResults) 2745 _ = seg.Seg.AddMetadata("Cloudmap-ListOperations-NextToken", nextToken) 2746 _ = seg.Seg.AddMetadata("Cloudmap-ListOperations-Result-Operations", operations) 2747 _ = seg.Seg.AddMetadata("Cloudmap-ListOperations-Result-NextToken", moreNextToken) 2748 2749 if err != nil { 2750 _ = seg.Seg.AddError(err) 2751 } 2752 }() 2753 } 2754 2755 // validate 2756 if sd.sdClient == nil { 2757 err = errors.New("CloudMap ListOperations Failed: " + "SD Client is Required") 2758 return nil, "", err 2759 } 2760 2761 if maxResults != nil { 2762 if *maxResults <= 0 { 2763 err = errors.New("CloudMap ListOperations Failed: " + "MaxResults Must Be Greater Than Zero") 2764 return nil, "", err 2765 } 2766 } 2767 2768 // define input 2769 input := &servicediscovery.ListOperationsInput{} 2770 2771 if filter != nil { 2772 var opFilters []*servicediscovery.OperationFilter 2773 2774 for fk, fv := range filter { 2775 var sdof *servicediscovery.OperationFilter 2776 2777 switch fk { 2778 case sdoperationfilter.EQ_NameSpaceID: 2779 if len(fv) == 1 { 2780 sdof = &servicediscovery.OperationFilter{ 2781 Name: aws.String("NAMESPACE_ID"), 2782 Condition: aws.String("EQ"), 2783 Values: aws.StringSlice(fv), 2784 } 2785 } 2786 case sdoperationfilter.EQ_ServiceID: 2787 if len(fv) == 1 { 2788 sdof = &servicediscovery.OperationFilter{ 2789 Name: aws.String("SERVICE_ID"), 2790 Condition: aws.String("EQ"), 2791 Values: aws.StringSlice(fv), 2792 } 2793 } 2794 case sdoperationfilter.EQ_Status: 2795 if len(fv) == 1 { 2796 sdof = &servicediscovery.OperationFilter{ 2797 Name: aws.String("STATUS"), 2798 Condition: aws.String("EQ"), 2799 Values: aws.StringSlice(fv), 2800 } 2801 } 2802 case sdoperationfilter.EQ_Type: 2803 if len(fv) == 1 { 2804 sdof = &servicediscovery.OperationFilter{ 2805 Name: aws.String("TYPE"), 2806 Condition: aws.String("EQ"), 2807 Values: aws.StringSlice(fv), 2808 } 2809 } 2810 case sdoperationfilter.IN_Status: 2811 if len(fv) > 0 { 2812 sdof = &servicediscovery.OperationFilter{ 2813 Name: aws.String("STATUS"), 2814 Condition: aws.String("IN"), 2815 Values: aws.StringSlice(fv), 2816 } 2817 } 2818 case sdoperationfilter.IN_Type: 2819 if len(fv) > 0 { 2820 sdof = &servicediscovery.OperationFilter{ 2821 Name: aws.String("TYPE"), 2822 Condition: aws.String("IN"), 2823 Values: aws.StringSlice(fv), 2824 } 2825 } 2826 case sdoperationfilter.BETWEEN_UpdateDate: 2827 if len(fv) == 2 { 2828 sdof = &servicediscovery.OperationFilter{ 2829 Name: aws.String("UPDATE_DATE"), 2830 Condition: aws.String("BETWEEN"), 2831 Values: aws.StringSlice(fv), 2832 } 2833 } 2834 } 2835 2836 if sdof != nil { 2837 opFilters = append(opFilters, sdof) 2838 } 2839 } 2840 2841 if len(opFilters) > 0 { 2842 input.Filters = opFilters 2843 } 2844 } 2845 2846 if maxResults != nil { 2847 input.MaxResults = maxResults 2848 } 2849 2850 if nextToken != nil { 2851 if util.LenTrim(*nextToken) > 0 { 2852 input.NextToken = nextToken 2853 } 2854 } 2855 2856 // invoke action 2857 var output *servicediscovery.ListOperationsOutput 2858 2859 if len(timeOutDuration) > 0 { 2860 ctx, cancel := context.WithTimeout(segCtx, timeOutDuration[0]) 2861 defer cancel() 2862 2863 output, err = sd.sdClient.ListOperationsWithContext(ctx, input) 2864 } else { 2865 if segCtxSet { 2866 output, err = sd.sdClient.ListOperationsWithContext(segCtx, input) 2867 } else { 2868 output, err = sd.sdClient.ListOperations(input) 2869 } 2870 } 2871 2872 if err != nil { 2873 // handle error 2874 err = errors.New("CloudMap ListOperations Failed: (List Action) " + err.Error()) 2875 return nil, "", err 2876 } 2877 2878 return output.Operations, *output.NextToken, nil 2879 } 2880 2881 // ListOperationsPages lists operations that match the criteria specified in parameters 2882 // (issues multiple page requests until max results is met or all data is retrieved) 2883 // 2884 // Parameters: 2885 // 1. filter = (optional) map of filter operations (EQ_ filters allow single value per key) 2886 // a) EQ_Status / IN_Status = Valid Values: SUBMITTED, PENDING, SUCCEED, FAIL 2887 // b) EQ_Type / IN_Type = Valid Values: CREATE_NAMESPACE, DELETE_NAMESPACE, UPDATE_SERVICE, REGISTER_INSTANCE, DEREGISTER_INSTANCE 2888 // c) BETWEEN_UpdateDate = begin and end in Unix DateTime in UTC 2889 // 2. maxResults = (optional) specifies maximum count to return 2890 // 3. nextToken = (optional) if initial action, leave blank; if this is a subsequent action to get more, input the moreNextToken returned from a prior action 2891 // 4. timeOutDuration = (optional) maximum time before timeout via context 2892 // 2893 // Return Values: 2894 // 1. operations = slice of sd operation summary objects 2895 // a) Targets = evaluate Targets to retrieve namespaceId, serviceId, InstanceId etc, using NAMESPACE, SERVICE, INSTANCE key names 2896 // 2. moreNextToken = if more data exists, this token can be used in a subsequent action via nextToken parameter 2897 // 3. err = error info if any 2898 func (sd *CloudMap) ListOperationsPages(filter map[sdoperationfilter.SdOperationFilter][]string, 2899 maxResults *int64, 2900 nextToken *string, 2901 timeOutDuration ...time.Duration) (operations []*servicediscovery.OperationSummary, moreNextToken string, err error) { 2902 segCtx := context.Background() 2903 segCtxSet := false 2904 2905 seg := xray.NewSegmentNullable("Cloudmap-ListOperationsPages", sd._parentSegment) 2906 2907 if seg != nil { 2908 segCtx = seg.Ctx 2909 segCtxSet = true 2910 2911 defer seg.Close() 2912 defer func() { 2913 _ = seg.Seg.AddMetadata("Cloudmap-ListOperationsPages-Filter", filter) 2914 _ = seg.Seg.AddMetadata("Cloudmap-ListOperationsPages-MaxResults", maxResults) 2915 _ = seg.Seg.AddMetadata("Cloudmap-ListOperationsPages-NextToken", nextToken) 2916 _ = seg.Seg.AddMetadata("Cloudmap-ListOperationsPages-Result-Operations", operations) 2917 _ = seg.Seg.AddMetadata("Cloudmap-ListOperationsPages-Result-NextToken", moreNextToken) 2918 2919 if err != nil { 2920 _ = seg.Seg.AddError(err) 2921 } 2922 }() 2923 } 2924 2925 // validate 2926 if sd.sdClient == nil { 2927 err = errors.New("CloudMap ListOperationsPages Failed: " + "SD Client is Required") 2928 return nil, "", err 2929 } 2930 2931 if maxResults != nil { 2932 if *maxResults <= 0 { 2933 err = errors.New("CloudMap ListOperationsPages Failed: " + "MaxResults Must Be Greater Than Zero") 2934 return nil, "", err 2935 } 2936 } 2937 2938 // define input 2939 input := &servicediscovery.ListOperationsInput{} 2940 2941 if filter != nil { 2942 var opFilters []*servicediscovery.OperationFilter 2943 2944 for fk, fv := range filter { 2945 var sdof *servicediscovery.OperationFilter 2946 2947 switch fk { 2948 case sdoperationfilter.EQ_NameSpaceID: 2949 if len(fv) == 1 { 2950 sdof = &servicediscovery.OperationFilter{ 2951 Name: aws.String("NAMESPACE_ID"), 2952 Condition: aws.String("EQ"), 2953 Values: aws.StringSlice(fv), 2954 } 2955 } 2956 case sdoperationfilter.EQ_ServiceID: 2957 if len(fv) == 1 { 2958 sdof = &servicediscovery.OperationFilter{ 2959 Name: aws.String("SERVICE_ID"), 2960 Condition: aws.String("EQ"), 2961 Values: aws.StringSlice(fv), 2962 } 2963 } 2964 case sdoperationfilter.EQ_Status: 2965 if len(fv) == 1 { 2966 sdof = &servicediscovery.OperationFilter{ 2967 Name: aws.String("STATUS"), 2968 Condition: aws.String("EQ"), 2969 Values: aws.StringSlice(fv), 2970 } 2971 } 2972 case sdoperationfilter.EQ_Type: 2973 if len(fv) == 1 { 2974 sdof = &servicediscovery.OperationFilter{ 2975 Name: aws.String("TYPE"), 2976 Condition: aws.String("EQ"), 2977 Values: aws.StringSlice(fv), 2978 } 2979 } 2980 case sdoperationfilter.IN_Status: 2981 if len(fv) > 0 { 2982 sdof = &servicediscovery.OperationFilter{ 2983 Name: aws.String("STATUS"), 2984 Condition: aws.String("IN"), 2985 Values: aws.StringSlice(fv), 2986 } 2987 } 2988 case sdoperationfilter.IN_Type: 2989 if len(fv) > 0 { 2990 sdof = &servicediscovery.OperationFilter{ 2991 Name: aws.String("TYPE"), 2992 Condition: aws.String("IN"), 2993 Values: aws.StringSlice(fv), 2994 } 2995 } 2996 case sdoperationfilter.BETWEEN_UpdateDate: 2997 if len(fv) == 2 { 2998 sdof = &servicediscovery.OperationFilter{ 2999 Name: aws.String("UPDATE_DATE"), 3000 Condition: aws.String("BETWEEN"), 3001 Values: aws.StringSlice(fv), 3002 } 3003 } 3004 } 3005 3006 if sdof != nil { 3007 opFilters = append(opFilters, sdof) 3008 } 3009 } 3010 3011 if len(opFilters) > 0 { 3012 input.Filters = opFilters 3013 } 3014 } 3015 3016 if maxResults != nil { 3017 input.MaxResults = maxResults 3018 } 3019 3020 if nextToken != nil { 3021 if util.LenTrim(*nextToken) > 0 { 3022 input.NextToken = nextToken 3023 } 3024 } 3025 3026 // invoke action 3027 fn := func(pageOutput *servicediscovery.ListOperationsOutput, lastPage bool) bool { 3028 if pageOutput != nil { 3029 moreNextToken = *pageOutput.NextToken 3030 operations = append(operations, pageOutput.Operations...) 3031 } 3032 3033 return !lastPage 3034 } 3035 3036 if len(timeOutDuration) > 0 { 3037 ctx, cancel := context.WithTimeout(segCtx, timeOutDuration[0]) 3038 defer cancel() 3039 3040 err = sd.sdClient.ListOperationsPagesWithContext(ctx, input, fn) 3041 } else { 3042 if segCtxSet { 3043 err = sd.sdClient.ListOperationsPagesWithContext(segCtx, input, fn) 3044 } else { 3045 err = sd.sdClient.ListOperationsPages(input, fn) 3046 } 3047 } 3048 3049 if err != nil { 3050 // handle error 3051 err = errors.New("CloudMap ListOperationsPages Failed: (ListPages Action) " + err.Error()) 3052 return nil, "", err 3053 } 3054 3055 return operations, moreNextToken, nil 3056 }