github.com/vtorhonen/terraform@v0.9.0-beta2.0.20170307220345-5d894e4ffda7/builtin/providers/spotinst/resource_spotinst_aws_group.go (about) 1 package spotinst 2 3 import ( 4 "bytes" 5 "crypto/sha1" 6 "encoding/base64" 7 "encoding/hex" 8 "fmt" 9 "log" 10 "regexp" 11 "strings" 12 13 "github.com/hashicorp/terraform/helper/hashcode" 14 "github.com/hashicorp/terraform/helper/schema" 15 "github.com/spotinst/spotinst-sdk-go/spotinst" 16 "github.com/spotinst/spotinst-sdk-go/spotinst/util/stringutil" 17 ) 18 19 func resourceSpotinstAwsGroup() *schema.Resource { 20 return &schema.Resource{ 21 Create: resourceSpotinstAwsGroupCreate, 22 Read: resourceSpotinstAwsGroupRead, 23 Update: resourceSpotinstAwsGroupUpdate, 24 Delete: resourceSpotinstAwsGroupDelete, 25 26 Schema: map[string]*schema.Schema{ 27 "name": &schema.Schema{ 28 Type: schema.TypeString, 29 Required: true, 30 }, 31 32 "description": &schema.Schema{ 33 Type: schema.TypeString, 34 Required: true, 35 }, 36 37 "capacity": &schema.Schema{ 38 Type: schema.TypeSet, 39 Required: true, 40 MaxItems: 1, 41 Elem: &schema.Resource{ 42 Schema: map[string]*schema.Schema{ 43 "target": &schema.Schema{ 44 Type: schema.TypeInt, 45 Required: true, 46 }, 47 48 "minimum": &schema.Schema{ 49 Type: schema.TypeInt, 50 Optional: true, 51 Computed: true, 52 }, 53 54 "maximum": &schema.Schema{ 55 Type: schema.TypeInt, 56 Optional: true, 57 Computed: true, 58 }, 59 60 "unit": &schema.Schema{ 61 Type: schema.TypeString, 62 Optional: true, 63 Computed: true, 64 }, 65 }, 66 }, 67 Set: hashAwsGroupCapacity, 68 }, 69 70 "strategy": &schema.Schema{ 71 Type: schema.TypeSet, 72 Required: true, 73 MaxItems: 1, 74 Elem: &schema.Resource{ 75 Schema: map[string]*schema.Schema{ 76 "risk": &schema.Schema{ 77 Type: schema.TypeFloat, 78 Optional: true, 79 }, 80 81 "ondemand_count": &schema.Schema{ 82 Type: schema.TypeInt, 83 Optional: true, 84 }, 85 86 "availability_vs_cost": &schema.Schema{ 87 Type: schema.TypeString, 88 Optional: true, 89 Computed: true, 90 }, 91 92 "draining_timeout": &schema.Schema{ 93 Type: schema.TypeInt, 94 Optional: true, 95 Computed: true, 96 }, 97 98 "utilize_reserved_instances": &schema.Schema{ 99 Type: schema.TypeBool, 100 Optional: true, 101 Computed: true, 102 }, 103 104 "fallback_to_ondemand": &schema.Schema{ 105 Type: schema.TypeBool, 106 Optional: true, 107 Computed: true, 108 }, 109 }, 110 }, 111 Set: hashAwsGroupStrategy, 112 }, 113 114 "scheduled_task": &schema.Schema{ 115 Type: schema.TypeSet, 116 Optional: true, 117 Elem: &schema.Resource{ 118 Schema: map[string]*schema.Schema{ 119 "task_type": &schema.Schema{ 120 Type: schema.TypeString, 121 Optional: true, 122 }, 123 124 "frequency": &schema.Schema{ 125 Type: schema.TypeString, 126 Optional: true, 127 }, 128 129 "cron_expression": &schema.Schema{ 130 Type: schema.TypeString, 131 Optional: true, 132 }, 133 134 "scale_target_capacity": &schema.Schema{ 135 Type: schema.TypeInt, 136 Optional: true, 137 }, 138 139 "scale_min_capacity": &schema.Schema{ 140 Type: schema.TypeInt, 141 Optional: true, 142 }, 143 144 "scale_max_capacity": &schema.Schema{ 145 Type: schema.TypeInt, 146 Optional: true, 147 }, 148 }, 149 }, 150 }, 151 152 "product": &schema.Schema{ 153 Type: schema.TypeString, 154 Required: true, 155 ForceNew: true, 156 }, 157 158 "instance_types": &schema.Schema{ 159 Type: schema.TypeSet, 160 Required: true, 161 MaxItems: 1, 162 Elem: &schema.Resource{ 163 Schema: map[string]*schema.Schema{ 164 "ondemand": &schema.Schema{ 165 Type: schema.TypeString, 166 Required: true, 167 }, 168 169 "spot": &schema.Schema{ 170 Type: schema.TypeList, 171 Required: true, 172 Elem: &schema.Schema{Type: schema.TypeString}, 173 }, 174 }, 175 }, 176 }, 177 178 "signal": &schema.Schema{ 179 Type: schema.TypeSet, 180 Optional: true, 181 Elem: &schema.Resource{ 182 Schema: map[string]*schema.Schema{ 183 "name": &schema.Schema{ 184 Type: schema.TypeString, 185 Required: true, 186 }, 187 }, 188 }, 189 }, 190 191 "availability_zone": &schema.Schema{ 192 Type: schema.TypeSet, 193 Optional: true, 194 ConflictsWith: []string{"availability_zones"}, 195 Elem: &schema.Resource{ 196 Schema: map[string]*schema.Schema{ 197 "name": &schema.Schema{ 198 Type: schema.TypeString, 199 Required: true, 200 }, 201 202 "subnet_id": &schema.Schema{ 203 Type: schema.TypeString, 204 Optional: true, 205 }, 206 }, 207 }, 208 }, 209 210 "availability_zones": &schema.Schema{ 211 Type: schema.TypeList, 212 Optional: true, 213 Elem: &schema.Schema{Type: schema.TypeString}, 214 ConflictsWith: []string{"availability_zone"}, 215 }, 216 217 "hot_ebs_volume": &schema.Schema{ 218 Type: schema.TypeSet, 219 Optional: true, 220 Elem: &schema.Resource{ 221 Schema: map[string]*schema.Schema{ 222 "device_name": &schema.Schema{ 223 Type: schema.TypeString, 224 Required: true, 225 }, 226 227 "volume_ids": &schema.Schema{ 228 Type: schema.TypeList, 229 Required: true, 230 Elem: &schema.Schema{Type: schema.TypeString}, 231 }, 232 }, 233 }, 234 }, 235 236 "load_balancer": &schema.Schema{ 237 Type: schema.TypeSet, 238 Optional: true, 239 Elem: &schema.Resource{ 240 Schema: map[string]*schema.Schema{ 241 "name": &schema.Schema{ 242 Type: schema.TypeString, 243 Required: true, 244 }, 245 246 "arn": &schema.Schema{ 247 Type: schema.TypeString, 248 Optional: true, 249 }, 250 251 "type": &schema.Schema{ 252 Type: schema.TypeString, 253 Required: true, 254 }, 255 }, 256 }, 257 Set: hashAwsGroupLoadBalancer, 258 }, 259 260 "launch_specification": &schema.Schema{ 261 Type: schema.TypeSet, 262 Required: true, 263 MaxItems: 1, 264 Elem: &schema.Resource{ 265 Schema: map[string]*schema.Schema{ 266 "load_balancer_names": &schema.Schema{ 267 Type: schema.TypeList, 268 Optional: true, 269 Elem: &schema.Schema{Type: schema.TypeString}, 270 }, 271 272 "monitoring": &schema.Schema{ 273 Type: schema.TypeBool, 274 Optional: true, 275 Default: false, 276 }, 277 278 "ebs_optimized": &schema.Schema{ 279 Type: schema.TypeBool, 280 Optional: true, 281 Computed: true, 282 }, 283 284 "image_id": &schema.Schema{ 285 Type: schema.TypeString, 286 Optional: true, 287 ConflictsWith: []string{"image_id"}, 288 }, 289 290 "key_pair": &schema.Schema{ 291 Type: schema.TypeString, 292 Optional: true, 293 }, 294 295 "health_check_type": &schema.Schema{ 296 Type: schema.TypeString, 297 Optional: true, 298 }, 299 300 "health_check_grace_period": &schema.Schema{ 301 Type: schema.TypeInt, 302 Optional: true, 303 }, 304 305 "security_group_ids": &schema.Schema{ 306 Type: schema.TypeList, 307 Required: true, 308 Elem: &schema.Schema{Type: schema.TypeString}, 309 }, 310 311 "user_data": &schema.Schema{ 312 Type: schema.TypeString, 313 Optional: true, 314 StateFunc: func(v interface{}) string { 315 switch v.(type) { 316 case string: 317 hash := sha1.Sum([]byte(v.(string))) 318 return hex.EncodeToString(hash[:]) 319 default: 320 return "" 321 } 322 }, 323 }, 324 325 "iam_role": &schema.Schema{ 326 Type: schema.TypeString, 327 Optional: true, 328 Deprecated: "Attribute iam_role is deprecated. Use iam_instance_profile instead", 329 }, 330 331 "iam_instance_profile": &schema.Schema{ 332 Type: schema.TypeString, 333 Optional: true, 334 }, 335 }, 336 }, 337 }, 338 339 "image_id": &schema.Schema{ 340 Type: schema.TypeString, 341 Optional: true, 342 }, 343 344 "elastic_ips": &schema.Schema{ 345 Type: schema.TypeList, 346 Optional: true, 347 Elem: &schema.Schema{Type: schema.TypeString}, 348 }, 349 350 "tags": &schema.Schema{ 351 Type: schema.TypeMap, 352 Optional: true, 353 }, 354 355 "ebs_block_device": &schema.Schema{ 356 Type: schema.TypeSet, 357 Optional: true, 358 Elem: &schema.Resource{ 359 Schema: map[string]*schema.Schema{ 360 "delete_on_termination": &schema.Schema{ 361 Type: schema.TypeBool, 362 Optional: true, 363 Computed: true, 364 }, 365 366 "device_name": &schema.Schema{ 367 Type: schema.TypeString, 368 Required: true, 369 }, 370 371 "encrypted": &schema.Schema{ 372 Type: schema.TypeBool, 373 Optional: true, 374 Computed: true, 375 }, 376 377 "iops": &schema.Schema{ 378 Type: schema.TypeInt, 379 Optional: true, 380 }, 381 382 "snapshot_id": &schema.Schema{ 383 Type: schema.TypeString, 384 Optional: true, 385 }, 386 387 "volume_size": &schema.Schema{ 388 Type: schema.TypeInt, 389 Optional: true, 390 }, 391 392 "volume_type": &schema.Schema{ 393 Type: schema.TypeString, 394 Optional: true, 395 Computed: true, 396 }, 397 }, 398 }, 399 Set: hashAwsGroupEBSBlockDevice, 400 }, 401 402 "ephemeral_block_device": &schema.Schema{ 403 Type: schema.TypeSet, 404 Optional: true, 405 Elem: &schema.Resource{ 406 Schema: map[string]*schema.Schema{ 407 "device_name": &schema.Schema{ 408 Type: schema.TypeString, 409 Required: true, 410 }, 411 412 "virtual_name": &schema.Schema{ 413 Type: schema.TypeString, 414 Required: true, 415 }, 416 }, 417 }, 418 }, 419 420 "network_interface": &schema.Schema{ 421 Type: schema.TypeSet, 422 Optional: true, 423 Elem: &schema.Resource{ 424 Schema: map[string]*schema.Schema{ 425 "description": &schema.Schema{ 426 Type: schema.TypeString, 427 Required: true, 428 }, 429 430 "device_index": &schema.Schema{ 431 Type: schema.TypeInt, 432 Required: true, 433 }, 434 435 "secondary_private_ip_address_count": &schema.Schema{ 436 Type: schema.TypeInt, 437 Optional: true, 438 }, 439 440 "associate_public_ip_address": &schema.Schema{ 441 Type: schema.TypeBool, 442 Optional: true, 443 }, 444 445 "delete_on_termination": &schema.Schema{ 446 Type: schema.TypeBool, 447 Optional: true, 448 Computed: true, 449 }, 450 451 "security_group_ids": &schema.Schema{ 452 Type: schema.TypeList, 453 Optional: true, 454 Elem: &schema.Schema{Type: schema.TypeString}, 455 }, 456 457 "network_interface_id": &schema.Schema{ 458 Type: schema.TypeString, 459 Optional: true, 460 }, 461 462 "private_ip_address": &schema.Schema{ 463 Type: schema.TypeString, 464 Optional: true, 465 }, 466 467 "subnet_id": &schema.Schema{ 468 Type: schema.TypeString, 469 Optional: true, 470 }, 471 }, 472 }, 473 }, 474 475 "scaling_up_policy": scalingPolicySchema(), 476 477 "scaling_down_policy": scalingPolicySchema(), 478 479 "rancher_integration": &schema.Schema{ 480 Type: schema.TypeSet, 481 Optional: true, 482 MaxItems: 1, 483 Elem: &schema.Resource{ 484 Schema: map[string]*schema.Schema{ 485 "master_host": &schema.Schema{ 486 Type: schema.TypeString, 487 Required: true, 488 }, 489 490 "access_key": &schema.Schema{ 491 Type: schema.TypeString, 492 Required: true, 493 }, 494 495 "secret_key": &schema.Schema{ 496 Type: schema.TypeString, 497 Required: true, 498 }, 499 }, 500 }, 501 }, 502 503 "elastic_beanstalk_integration": &schema.Schema{ 504 Type: schema.TypeSet, 505 Optional: true, 506 MaxItems: 1, 507 Elem: &schema.Resource{ 508 Schema: map[string]*schema.Schema{ 509 "environment_id": &schema.Schema{ 510 Type: schema.TypeString, 511 Required: true, 512 }, 513 }, 514 }, 515 }, 516 517 "ec2_container_service_integration": &schema.Schema{ 518 Type: schema.TypeSet, 519 Optional: true, 520 MaxItems: 1, 521 Elem: &schema.Resource{ 522 Schema: map[string]*schema.Schema{ 523 "cluster_name": &schema.Schema{ 524 Type: schema.TypeString, 525 Required: true, 526 }, 527 }, 528 }, 529 }, 530 531 "kubernetes_integration": &schema.Schema{ 532 Type: schema.TypeSet, 533 Optional: true, 534 MaxItems: 1, 535 Elem: &schema.Resource{ 536 Schema: map[string]*schema.Schema{ 537 "api_server": &schema.Schema{ 538 Type: schema.TypeString, 539 Required: true, 540 }, 541 542 "token": &schema.Schema{ 543 Type: schema.TypeString, 544 Required: true, 545 }, 546 }, 547 }, 548 }, 549 550 "mesosphere_integration": &schema.Schema{ 551 Type: schema.TypeSet, 552 Optional: true, 553 MaxItems: 1, 554 Elem: &schema.Resource{ 555 Schema: map[string]*schema.Schema{ 556 "api_server": &schema.Schema{ 557 Type: schema.TypeString, 558 Required: true, 559 }, 560 }, 561 }, 562 }, 563 }, 564 } 565 } 566 567 func scalingPolicySchema() *schema.Schema { 568 return &schema.Schema{ 569 Type: schema.TypeSet, 570 Optional: true, 571 Elem: &schema.Resource{ 572 Schema: map[string]*schema.Schema{ 573 "policy_name": &schema.Schema{ 574 Type: schema.TypeString, 575 Required: true, 576 }, 577 578 "metric_name": &schema.Schema{ 579 Type: schema.TypeString, 580 Required: true, 581 }, 582 583 "statistic": &schema.Schema{ 584 Type: schema.TypeString, 585 Required: true, 586 }, 587 588 "unit": &schema.Schema{ 589 Type: schema.TypeString, 590 Required: true, 591 }, 592 593 "threshold": &schema.Schema{ 594 Type: schema.TypeFloat, 595 Required: true, 596 }, 597 598 "adjustment": &schema.Schema{ 599 Type: schema.TypeInt, 600 Optional: true, 601 }, 602 603 "min_target_capacity": &schema.Schema{ 604 Type: schema.TypeInt, 605 Optional: true, 606 }, 607 608 "max_target_capacity": &schema.Schema{ 609 Type: schema.TypeInt, 610 Optional: true, 611 }, 612 613 "namespace": &schema.Schema{ 614 Type: schema.TypeString, 615 Required: true, 616 }, 617 618 "operator": &schema.Schema{ 619 Type: schema.TypeString, 620 Optional: true, 621 Computed: true, 622 }, 623 624 "evaluation_periods": &schema.Schema{ 625 Type: schema.TypeInt, 626 Required: true, 627 }, 628 629 "period": &schema.Schema{ 630 Type: schema.TypeInt, 631 Required: true, 632 }, 633 634 "cooldown": &schema.Schema{ 635 Type: schema.TypeInt, 636 Required: true, 637 }, 638 639 "dimensions": &schema.Schema{ 640 Type: schema.TypeMap, 641 Optional: true, 642 }, 643 }, 644 }, 645 Set: hashAwsGroupScalingPolicy, 646 } 647 } 648 649 func resourceSpotinstAwsGroupCreate(d *schema.ResourceData, meta interface{}) error { 650 client := meta.(*spotinst.Client) 651 newAwsGroup, err := buildAwsGroupOpts(d, meta) 652 if err != nil { 653 return err 654 } 655 log.Printf("[DEBUG] AwsGroup create configuration: %s\n", stringutil.Stringify(newAwsGroup)) 656 input := &spotinst.CreateAwsGroupInput{Group: newAwsGroup} 657 resp, err := client.AwsGroupService.Create(input) 658 if err != nil { 659 return fmt.Errorf("Error creating group: %s", err) 660 } 661 d.SetId(spotinst.StringValue(resp.Group.ID)) 662 log.Printf("[INFO] AwsGroup created successfully: %s\n", d.Id()) 663 return resourceSpotinstAwsGroupRead(d, meta) 664 } 665 666 func resourceSpotinstAwsGroupRead(d *schema.ResourceData, meta interface{}) error { 667 client := meta.(*spotinst.Client) 668 input := &spotinst.ReadAwsGroupInput{ID: spotinst.String(d.Id())} 669 resp, err := client.AwsGroupService.Read(input) 670 if err != nil { 671 return fmt.Errorf("Error retrieving group: %s", err) 672 } 673 if g := resp.Group; g != nil { 674 d.Set("name", g.Name) 675 d.Set("description", g.Description) 676 d.Set("product", g.Compute.Product) 677 d.Set("tags", tagsToMap(g.Compute.LaunchSpecification.Tags)) 678 d.Set("elastic_ips", g.Compute.ElasticIPs) 679 680 // Set capacity. 681 if g.Capacity != nil { 682 if err := d.Set("capacity", flattenAwsGroupCapacity(g.Capacity)); err != nil { 683 return fmt.Errorf("Error setting capacity onfiguration: %#v", err) 684 } 685 } 686 687 // Set strategy. 688 if g.Strategy != nil { 689 if err := d.Set("strategy", flattenAwsGroupStrategy(g.Strategy)); err != nil { 690 return fmt.Errorf("Error setting strategy configuration: %#v", err) 691 } 692 } 693 694 // Set signals. 695 if g.Strategy.Signals != nil { 696 if err := d.Set("signal", flattenAwsGroupSignals(g.Strategy.Signals)); err != nil { 697 return fmt.Errorf("Error setting signals configuration: %#v", err) 698 } 699 } 700 701 // Set scaling up policies. 702 if g.Scaling.Up != nil { 703 if err := d.Set("scaling_up_policy", flattenAwsGroupScalingPolicies(g.Scaling.Up)); err != nil { 704 return fmt.Errorf("Error setting scaling up policies configuration: %#v", err) 705 } 706 } 707 708 // Set scaling down policies. 709 if g.Scaling.Down != nil { 710 if err := d.Set("scaling_down_policy", flattenAwsGroupScalingPolicies(g.Scaling.Down)); err != nil { 711 return fmt.Errorf("Error setting scaling down policies configuration: %#v", err) 712 } 713 } 714 715 // Set scheduled tasks. 716 if g.Scheduling.Tasks != nil { 717 if err := d.Set("scheduled_task", flattenAwsGroupScheduledTasks(g.Scheduling.Tasks)); err != nil { 718 return fmt.Errorf("Error setting scheduled tasks configuration: %#v", err) 719 } 720 } 721 722 // Set launch specification. 723 if g.Compute.LaunchSpecification != nil { 724 imageIDSetInLaunchSpec := true 725 if v, ok := d.GetOk("image_id"); ok && v != "" { 726 imageIDSetInLaunchSpec = false 727 } 728 if err := d.Set("launch_specification", flattenAwsGroupLaunchSpecification(g.Compute.LaunchSpecification, imageIDSetInLaunchSpec)); err != nil { 729 return fmt.Errorf("Error setting launch specification configuration: %#v", err) 730 } 731 } 732 733 // Set image ID. 734 if g.Compute.LaunchSpecification.ImageID != nil { 735 if d.Get("image_id") != nil && d.Get("image_id") != "" { 736 d.Set("image_id", g.Compute.LaunchSpecification.ImageID) 737 } 738 } 739 740 // Set load balancers. 741 if g.Compute.LaunchSpecification.LoadBalancersConfig != nil { 742 if err := d.Set("load_balancer", flattenAwsGroupLoadBalancers(g.Compute.LaunchSpecification.LoadBalancersConfig.LoadBalancers)); err != nil { 743 return fmt.Errorf("Error setting load balancers configuration: %#v", err) 744 } 745 } 746 747 // Set EBS volume pool. 748 if g.Compute.EBSVolumePool != nil { 749 if err := d.Set("hot_ebs_volume", flattenAwsGroupEBSVolumePool(g.Compute.EBSVolumePool)); err != nil { 750 return fmt.Errorf("Error setting EBS volume pool configuration: %#v", err) 751 } 752 } 753 754 // Set network interfaces. 755 if g.Compute.LaunchSpecification.NetworkInterfaces != nil { 756 if err := d.Set("network_interface", flattenAwsGroupNetworkInterfaces(g.Compute.LaunchSpecification.NetworkInterfaces)); err != nil { 757 return fmt.Errorf("Error setting network interfaces configuration: %#v", err) 758 } 759 } 760 761 // Set block devices. 762 if g.Compute.LaunchSpecification.BlockDevices != nil { 763 if err := d.Set("ebs_block_device", flattenAwsGroupEBSBlockDevices(g.Compute.LaunchSpecification.BlockDevices)); err != nil { 764 return fmt.Errorf("Error setting EBS block devices configuration: %#v", err) 765 } 766 if err := d.Set("ephemeral_block_device", flattenAwsGroupEphemeralBlockDevices(g.Compute.LaunchSpecification.BlockDevices)); err != nil { 767 return fmt.Errorf("Error setting Ephemeral block devices configuration: %#v", err) 768 } 769 } 770 771 // Set Rancher integration. 772 if g.Integration.Rancher != nil { 773 if err := d.Set("rancher_integration", flattenAwsGroupRancherIntegration(g.Integration.Rancher)); err != nil { 774 return fmt.Errorf("Error setting Rancher configuration: %#v", err) 775 } 776 } 777 778 // Set Elastic Beanstalk integration. 779 if g.Integration.ElasticBeanstalk != nil { 780 if err := d.Set("elastic_beanstalk_integration", flattenAwsGroupElasticBeanstalkIntegration(g.Integration.ElasticBeanstalk)); err != nil { 781 return fmt.Errorf("Error setting Elastic Beanstalk configuration: %#v", err) 782 } 783 } 784 785 // Set EC2 Container Service integration. 786 if g.Integration.EC2ContainerService != nil { 787 if err := d.Set("ec2_container_service_integration", flattenAwsGroupEC2ContainerServiceIntegration(g.Integration.EC2ContainerService)); err != nil { 788 return fmt.Errorf("Error setting EC2 Container Service configuration: %#v", err) 789 } 790 } 791 792 // Set Kubernetes integration. 793 if g.Integration.Kubernetes != nil { 794 if err := d.Set("kubernetes_integration", flattenAwsGroupKubernetesIntegration(g.Integration.Kubernetes)); err != nil { 795 return fmt.Errorf("Error setting Kubernetes configuration: %#v", err) 796 } 797 } 798 799 // Set Mesosphere integration. 800 if g.Integration.Mesosphere != nil { 801 if err := d.Set("mesosphere_integration", flattenAwsGroupMesosphereIntegration(g.Integration.Mesosphere)); err != nil { 802 return fmt.Errorf("Error setting Mesosphere configuration: %#v", err) 803 } 804 } 805 } else { 806 d.SetId("") 807 } 808 return nil 809 } 810 811 func resourceSpotinstAwsGroupUpdate(d *schema.ResourceData, meta interface{}) error { 812 client := meta.(*spotinst.Client) 813 group := &spotinst.AwsGroup{ID: spotinst.String(d.Id())} 814 update := false 815 816 if d.HasChange("name") { 817 group.Name = spotinst.String(d.Get("name").(string)) 818 update = true 819 } 820 821 if d.HasChange("description") { 822 group.Description = spotinst.String(d.Get("description").(string)) 823 update = true 824 } 825 826 if d.HasChange("capacity") { 827 if v, ok := d.GetOk("capacity"); ok { 828 if capacity, err := expandAwsGroupCapacity(v); err != nil { 829 return err 830 } else { 831 group.Capacity = capacity 832 update = true 833 } 834 } 835 } 836 837 if d.HasChange("strategy") { 838 if v, ok := d.GetOk("strategy"); ok { 839 if strategy, err := expandAwsGroupStrategy(v); err != nil { 840 return err 841 } else { 842 group.Strategy = strategy 843 if v, ok := d.GetOk("signal"); ok { 844 if signals, err := expandAwsGroupSignals(v); err != nil { 845 return err 846 } else { 847 group.Strategy.Signals = signals 848 } 849 } 850 update = true 851 } 852 } 853 } 854 855 if d.HasChange("launch_specification") { 856 if v, ok := d.GetOk("launch_specification"); ok { 857 lc, err := expandAwsGroupLaunchSpecification(v) 858 if err != nil { 859 return err 860 } 861 if group.Compute == nil { 862 group.Compute = &spotinst.AwsGroupCompute{} 863 } 864 group.Compute.LaunchSpecification = lc 865 update = true 866 } 867 } 868 869 if d.HasChange("image_id") { 870 if d.Get("image_id") != nil && d.Get("image_id") != "" { 871 if group.Compute == nil { 872 group.Compute = &spotinst.AwsGroupCompute{} 873 } 874 if group.Compute.LaunchSpecification == nil { 875 group.Compute.LaunchSpecification = &spotinst.AwsGroupComputeLaunchSpecification{} 876 } 877 group.Compute.LaunchSpecification.ImageID = spotinst.String(d.Get("image_id").(string)) 878 update = true 879 } 880 } 881 882 if d.HasChange("load_balancer") { 883 if v, ok := d.GetOk("load_balancer"); ok { 884 if lbs, err := expandAwsGroupLoadBalancer(v); err != nil { 885 return err 886 } else { 887 if group.Compute == nil { 888 group.Compute = &spotinst.AwsGroupCompute{} 889 } 890 if group.Compute.LaunchSpecification == nil { 891 group.Compute.LaunchSpecification = &spotinst.AwsGroupComputeLaunchSpecification{} 892 } 893 if group.Compute.LaunchSpecification.LoadBalancersConfig == nil { 894 group.Compute.LaunchSpecification.LoadBalancersConfig = &spotinst.AwsGroupComputeLoadBalancersConfig{} 895 group.Compute.LaunchSpecification.LoadBalancersConfig.LoadBalancers = lbs 896 update = true 897 } 898 } 899 } 900 } 901 902 var blockDevicesExpanded bool 903 904 if d.HasChange("ebs_block_device") { 905 if v, ok := d.GetOk("ebs_block_device"); ok { 906 if devices, err := expandAwsGroupEBSBlockDevices(v); err != nil { 907 return err 908 } else { 909 if group.Compute == nil { 910 group.Compute = &spotinst.AwsGroupCompute{} 911 } 912 if group.Compute.LaunchSpecification == nil { 913 group.Compute.LaunchSpecification = &spotinst.AwsGroupComputeLaunchSpecification{} 914 } 915 if len(group.Compute.LaunchSpecification.BlockDevices) > 0 { 916 group.Compute.LaunchSpecification.BlockDevices = append(group.Compute.LaunchSpecification.BlockDevices, devices...) 917 } else { 918 if v, ok := d.GetOk("ephemeral_block_device"); ok { 919 if ephemeral, err := expandAwsGroupEphemeralBlockDevices(v); err != nil { 920 return err 921 } else { 922 devices = append(devices, ephemeral...) 923 blockDevicesExpanded = true 924 } 925 } 926 group.Compute.LaunchSpecification.BlockDevices = devices 927 } 928 update = true 929 } 930 } 931 } 932 933 if d.HasChange("ephemeral_block_device") && !blockDevicesExpanded { 934 if v, ok := d.GetOk("ephemeral_block_device"); ok { 935 if devices, err := expandAwsGroupEphemeralBlockDevices(v); err != nil { 936 return err 937 } else { 938 if group.Compute == nil { 939 group.Compute = &spotinst.AwsGroupCompute{} 940 } 941 if group.Compute.LaunchSpecification == nil { 942 group.Compute.LaunchSpecification = &spotinst.AwsGroupComputeLaunchSpecification{} 943 } 944 if len(group.Compute.LaunchSpecification.BlockDevices) > 0 { 945 group.Compute.LaunchSpecification.BlockDevices = append(group.Compute.LaunchSpecification.BlockDevices, devices...) 946 } else { 947 if v, ok := d.GetOk("ebs_block_device"); ok { 948 if ebs, err := expandAwsGroupEBSBlockDevices(v); err != nil { 949 return err 950 } else { 951 devices = append(devices, ebs...) 952 } 953 } 954 group.Compute.LaunchSpecification.BlockDevices = devices 955 } 956 update = true 957 } 958 } 959 } 960 961 if d.HasChange("network_interface") { 962 if v, ok := d.GetOk("network_interface"); ok { 963 if interfaces, err := expandAwsGroupNetworkInterfaces(v); err != nil { 964 return err 965 } else { 966 if group.Compute == nil { 967 group.Compute = &spotinst.AwsGroupCompute{} 968 } 969 if group.Compute.LaunchSpecification == nil { 970 group.Compute.LaunchSpecification = &spotinst.AwsGroupComputeLaunchSpecification{} 971 } 972 group.Compute.LaunchSpecification.NetworkInterfaces = interfaces 973 update = true 974 } 975 } 976 } 977 978 if d.HasChange("availability_zone") { 979 if v, ok := d.GetOk("availability_zone"); ok { 980 if zones, err := expandAwsGroupAvailabilityZones(v); err != nil { 981 return err 982 } else { 983 if group.Compute == nil { 984 group.Compute = &spotinst.AwsGroupCompute{} 985 } 986 group.Compute.AvailabilityZones = zones 987 update = true 988 } 989 } 990 } 991 992 if d.HasChange("availability_zones") { 993 if v, ok := d.GetOk("availability_zones"); ok { 994 if zones, err := expandAwsGroupAvailabilityZonesSlice(v); err != nil { 995 return err 996 } else { 997 if group.Compute == nil { 998 group.Compute = &spotinst.AwsGroupCompute{} 999 } 1000 group.Compute.AvailabilityZones = zones 1001 update = true 1002 } 1003 } 1004 } 1005 1006 if d.HasChange("hot_ebs_volume") { 1007 if v, ok := d.GetOk("hot_ebs_volume"); ok { 1008 if ebsVolumePool, err := expandAwsGroupEBSVolumePool(v); err != nil { 1009 return err 1010 } else { 1011 if group.Compute == nil { 1012 group.Compute = &spotinst.AwsGroupCompute{} 1013 } 1014 group.Compute.EBSVolumePool = ebsVolumePool 1015 update = true 1016 } 1017 } 1018 } 1019 1020 if d.HasChange("signal") { 1021 if v, ok := d.GetOk("signal"); ok { 1022 if signals, err := expandAwsGroupSignals(v); err != nil { 1023 return err 1024 } else { 1025 if group.Strategy == nil { 1026 group.Strategy = &spotinst.AwsGroupStrategy{} 1027 } 1028 group.Strategy.Signals = signals 1029 update = true 1030 } 1031 } 1032 } 1033 1034 if d.HasChange("instance_types") { 1035 if v, ok := d.GetOk("instance_types"); ok { 1036 if types, err := expandAwsGroupInstanceTypes(v); err != nil { 1037 return err 1038 } else { 1039 if group.Compute == nil { 1040 group.Compute = &spotinst.AwsGroupCompute{} 1041 } 1042 group.Compute.InstanceTypes = types 1043 update = true 1044 } 1045 } 1046 } 1047 1048 if d.HasChange("tags") { 1049 if v, ok := d.GetOk("tags"); ok { 1050 if tags, err := expandAwsGroupTags(v); err != nil { 1051 return err 1052 } else { 1053 if group.Compute == nil { 1054 group.Compute = &spotinst.AwsGroupCompute{} 1055 } 1056 if group.Compute.LaunchSpecification == nil { 1057 group.Compute.LaunchSpecification = &spotinst.AwsGroupComputeLaunchSpecification{} 1058 } 1059 group.Compute.LaunchSpecification.Tags = tags 1060 update = true 1061 } 1062 } 1063 } 1064 1065 if d.HasChange("elastic_ips") { 1066 if v, ok := d.GetOk("elastic_ips"); ok { 1067 if eips, err := expandAwsGroupElasticIPs(v); err != nil { 1068 return err 1069 } else { 1070 if group.Compute == nil { 1071 group.Compute = &spotinst.AwsGroupCompute{} 1072 } 1073 group.Compute.ElasticIPs = eips 1074 update = true 1075 } 1076 } 1077 } 1078 1079 if d.HasChange("scheduled_task") { 1080 if v, ok := d.GetOk("scheduled_task"); ok { 1081 if tasks, err := expandAwsGroupScheduledTasks(v); err != nil { 1082 return err 1083 } else { 1084 if group.Scheduling == nil { 1085 group.Scheduling = &spotinst.AwsGroupScheduling{} 1086 } 1087 group.Scheduling.Tasks = tasks 1088 update = true 1089 } 1090 } 1091 } 1092 1093 if d.HasChange("scaling_up_policy") { 1094 if v, ok := d.GetOk("scaling_up_policy"); ok { 1095 if policies, err := expandAwsGroupScalingPolicies(v); err != nil { 1096 return err 1097 } else { 1098 if group.Scaling == nil { 1099 group.Scaling = &spotinst.AwsGroupScaling{} 1100 } 1101 group.Scaling.Up = policies 1102 update = true 1103 } 1104 } 1105 } 1106 1107 if d.HasChange("scaling_down_policy") { 1108 if v, ok := d.GetOk("scaling_down_policy"); ok { 1109 if policies, err := expandAwsGroupScalingPolicies(v); err != nil { 1110 return err 1111 } else { 1112 if group.Scaling == nil { 1113 group.Scaling = &spotinst.AwsGroupScaling{} 1114 } 1115 group.Scaling.Down = policies 1116 update = true 1117 } 1118 } 1119 } 1120 1121 if d.HasChange("rancher_integration") { 1122 if v, ok := d.GetOk("rancher_integration"); ok { 1123 if integration, err := expandAwsGroupRancherIntegration(v); err != nil { 1124 return err 1125 } else { 1126 if group.Integration == nil { 1127 group.Integration = &spotinst.AwsGroupIntegration{} 1128 } 1129 group.Integration.Rancher = integration 1130 update = true 1131 } 1132 } 1133 } 1134 1135 if d.HasChange("elastic_eanstalk_integration") { 1136 if v, ok := d.GetOk("elastic_beanstalk_integration"); ok { 1137 if integration, err := expandAwsGroupElasticBeanstalkIntegration(v); err != nil { 1138 return err 1139 } else { 1140 if group.Integration == nil { 1141 group.Integration = &spotinst.AwsGroupIntegration{} 1142 } 1143 group.Integration.ElasticBeanstalk = integration 1144 update = true 1145 } 1146 } 1147 } 1148 1149 if d.HasChange("ec2_container_service_integration") { 1150 if v, ok := d.GetOk("ec2_container_service_integration"); ok { 1151 if integration, err := expandAwsGroupEC2ContainerServiceIntegration(v); err != nil { 1152 return err 1153 } else { 1154 if group.Integration == nil { 1155 group.Integration = &spotinst.AwsGroupIntegration{} 1156 } 1157 group.Integration.EC2ContainerService = integration 1158 update = true 1159 } 1160 } 1161 } 1162 1163 if d.HasChange("kubernetes_integration") { 1164 if v, ok := d.GetOk("kubernetes_integration"); ok { 1165 if integration, err := expandAwsGroupKubernetesIntegration(v); err != nil { 1166 return err 1167 } else { 1168 if group.Integration == nil { 1169 group.Integration = &spotinst.AwsGroupIntegration{} 1170 } 1171 group.Integration.Kubernetes = integration 1172 update = true 1173 } 1174 } 1175 } 1176 1177 if d.HasChange("mesosphere_integration") { 1178 if v, ok := d.GetOk("mesosphere_integration"); ok { 1179 if integration, err := expandAwsGroupMesosphereIntegration(v); err != nil { 1180 return err 1181 } else { 1182 if group.Integration == nil { 1183 group.Integration = &spotinst.AwsGroupIntegration{} 1184 } 1185 group.Integration.Mesosphere = integration 1186 update = true 1187 } 1188 } 1189 } 1190 1191 if update { 1192 log.Printf("[DEBUG] AwsGroup update configuration: %s\n", stringutil.Stringify(group)) 1193 input := &spotinst.UpdateAwsGroupInput{Group: group} 1194 if _, err := client.AwsGroupService.Update(input); err != nil { 1195 return fmt.Errorf("Error updating group %s: %s", d.Id(), err) 1196 } 1197 } 1198 1199 return resourceSpotinstAwsGroupRead(d, meta) 1200 } 1201 1202 func resourceSpotinstAwsGroupDelete(d *schema.ResourceData, meta interface{}) error { 1203 client := meta.(*spotinst.Client) 1204 log.Printf("[INFO] Deleting group: %s\n", d.Id()) 1205 input := &spotinst.DeleteAwsGroupInput{ID: spotinst.String(d.Id())} 1206 if _, err := client.AwsGroupService.Delete(input); err != nil { 1207 return fmt.Errorf("Error deleting group: %s", err) 1208 } 1209 d.SetId("") 1210 return nil 1211 } 1212 1213 func flattenAwsGroupCapacity(capacity *spotinst.AwsGroupCapacity) []interface{} { 1214 result := make(map[string]interface{}) 1215 result["target"] = spotinst.IntValue(capacity.Target) 1216 result["minimum"] = spotinst.IntValue(capacity.Minimum) 1217 result["maximum"] = spotinst.IntValue(capacity.Maximum) 1218 result["unit"] = spotinst.StringValue(capacity.Unit) 1219 return []interface{}{result} 1220 } 1221 1222 func flattenAwsGroupStrategy(strategy *spotinst.AwsGroupStrategy) []interface{} { 1223 result := make(map[string]interface{}) 1224 result["risk"] = spotinst.Float64Value(strategy.Risk) 1225 result["ondemand_count"] = spotinst.IntValue(strategy.OnDemandCount) 1226 result["availability_vs_cost"] = spotinst.StringValue(strategy.AvailabilityVsCost) 1227 result["draining_timeout"] = spotinst.IntValue(strategy.DrainingTimeout) 1228 result["utilize_reserved_instances"] = spotinst.BoolValue(strategy.UtilizeReservedInstances) 1229 result["fallback_to_ondemand"] = spotinst.BoolValue(strategy.FallbackToOnDemand) 1230 return []interface{}{result} 1231 } 1232 1233 func flattenAwsGroupLaunchSpecification(lspec *spotinst.AwsGroupComputeLaunchSpecification, includeImageID bool) []interface{} { 1234 result := make(map[string]interface{}) 1235 result["health_check_grace_period"] = spotinst.IntValue(lspec.HealthCheckGracePeriod) 1236 result["health_check_type"] = spotinst.StringValue(lspec.HealthCheckType) 1237 if includeImageID { 1238 result["image_id"] = spotinst.StringValue(lspec.ImageID) 1239 } 1240 result["key_pair"] = spotinst.StringValue(lspec.KeyPair) 1241 if lspec.UserData != nil && spotinst.StringValue(lspec.UserData) != "" { 1242 decodedUserData, _ := base64.StdEncoding.DecodeString(spotinst.StringValue(lspec.UserData)) 1243 result["user_data"] = string(decodedUserData) 1244 } else { 1245 result["user_data"] = "" 1246 } 1247 result["monitoring"] = spotinst.BoolValue(lspec.Monitoring) 1248 result["ebs_optimized"] = spotinst.BoolValue(lspec.EBSOptimized) 1249 result["load_balancer_names"] = lspec.LoadBalancerNames 1250 result["security_group_ids"] = lspec.SecurityGroupIDs 1251 if lspec.IamInstanceProfile != nil { 1252 if lspec.IamInstanceProfile.Arn != nil { 1253 result["iam_instance_profile"] = spotinst.StringValue(lspec.IamInstanceProfile.Arn) 1254 } else { 1255 result["iam_instance_profile"] = spotinst.StringValue(lspec.IamInstanceProfile.Name) 1256 } 1257 } 1258 return []interface{}{result} 1259 } 1260 1261 func flattenAwsGroupLoadBalancers(balancers []*spotinst.AwsGroupComputeLoadBalancer) []interface{} { 1262 result := make([]interface{}, 0, len(balancers)) 1263 for _, b := range balancers { 1264 m := make(map[string]interface{}) 1265 m["name"] = spotinst.StringValue(b.Name) 1266 m["arn"] = spotinst.StringValue(b.Arn) 1267 m["type"] = strings.ToLower(spotinst.StringValue(b.Type)) 1268 result = append(result, m) 1269 } 1270 return result 1271 } 1272 1273 func flattenAwsGroupEBSVolumePool(volumes []*spotinst.AwsGroupComputeEBSVolume) []interface{} { 1274 result := make([]interface{}, 0, len(volumes)) 1275 for _, v := range volumes { 1276 m := make(map[string]interface{}) 1277 m["device_name"] = spotinst.StringValue(v.DeviceName) 1278 m["volume_ids"] = v.VolumeIDs 1279 result = append(result, m) 1280 } 1281 return result 1282 } 1283 1284 func flattenAwsGroupSignals(signals []*spotinst.AwsGroupStrategySignal) []interface{} { 1285 result := make([]interface{}, 0, len(signals)) 1286 for _, s := range signals { 1287 m := make(map[string]interface{}) 1288 m["name"] = strings.ToLower(spotinst.StringValue(s.Name)) 1289 result = append(result, m) 1290 } 1291 return result 1292 } 1293 1294 func flattenAwsGroupScheduledTasks(tasks []*spotinst.AwsGroupScheduledTask) []interface{} { 1295 result := make([]interface{}, 0, len(tasks)) 1296 for _, t := range tasks { 1297 m := make(map[string]interface{}) 1298 m["task_type"] = spotinst.StringValue(t.TaskType) 1299 m["cron_expression"] = spotinst.StringValue(t.CronExpression) 1300 m["frequency"] = spotinst.StringValue(t.Frequency) 1301 m["scale_target_capacity"] = spotinst.IntValue(t.ScaleTargetCapacity) 1302 m["scale_min_capacity"] = spotinst.IntValue(t.ScaleMinCapacity) 1303 m["scale_max_capacity"] = spotinst.IntValue(t.ScaleMaxCapacity) 1304 result = append(result, m) 1305 } 1306 return result 1307 } 1308 1309 func flattenAwsGroupScalingPolicies(policies []*spotinst.AwsGroupScalingPolicy) []interface{} { 1310 result := make([]interface{}, 0, len(policies)) 1311 for _, p := range policies { 1312 m := make(map[string]interface{}) 1313 m["adjustment"] = spotinst.IntValue(p.Adjustment) 1314 m["cooldown"] = spotinst.IntValue(p.Cooldown) 1315 m["evaluation_periods"] = spotinst.IntValue(p.EvaluationPeriods) 1316 m["min_target_capacity"] = spotinst.IntValue(p.MinTargetCapacity) 1317 m["max_target_capacity"] = spotinst.IntValue(p.MaxTargetCapacity) 1318 m["metric_name"] = spotinst.StringValue(p.MetricName) 1319 m["namespace"] = spotinst.StringValue(p.Namespace) 1320 m["operator"] = spotinst.StringValue(p.Operator) 1321 m["period"] = spotinst.IntValue(p.Period) 1322 m["policy_name"] = spotinst.StringValue(p.PolicyName) 1323 m["statistic"] = spotinst.StringValue(p.Statistic) 1324 m["threshold"] = spotinst.Float64Value(p.Threshold) 1325 m["unit"] = spotinst.StringValue(p.Unit) 1326 if len(p.Dimensions) > 0 { 1327 flatDims := make(map[string]interface{}) 1328 for _, d := range p.Dimensions { 1329 flatDims[spotinst.StringValue(d.Name)] = *d.Value 1330 } 1331 m["dimensions"] = flatDims 1332 } 1333 result = append(result, m) 1334 } 1335 return result 1336 } 1337 1338 func flattenAwsGroupNetworkInterfaces(ifaces []*spotinst.AwsGroupComputeNetworkInterface) []interface{} { 1339 result := make([]interface{}, 0, len(ifaces)) 1340 for _, iface := range ifaces { 1341 m := make(map[string]interface{}) 1342 m["associate_public_ip_address"] = spotinst.BoolValue(iface.AssociatePublicIPAddress) 1343 m["delete_on_termination"] = spotinst.BoolValue(iface.DeleteOnTermination) 1344 m["description"] = spotinst.StringValue(iface.Description) 1345 m["device_index"] = spotinst.IntValue(iface.DeviceIndex) 1346 m["network_interface_id"] = spotinst.StringValue(iface.ID) 1347 m["private_ip_address"] = spotinst.StringValue(iface.PrivateIPAddress) 1348 m["secondary_private_ip_address_count"] = spotinst.IntValue(iface.SecondaryPrivateIPAddressCount) 1349 m["subnet_id"] = spotinst.StringValue(iface.SubnetID) 1350 m["security_group_ids"] = iface.SecurityGroupsIDs 1351 result = append(result, m) 1352 } 1353 return result 1354 } 1355 1356 func flattenAwsGroupEBSBlockDevices(devices []*spotinst.AwsGroupComputeBlockDevice) []interface{} { 1357 result := make([]interface{}, 0, len(devices)) 1358 for _, dev := range devices { 1359 if dev.EBS != nil { 1360 m := make(map[string]interface{}) 1361 m["device_name"] = spotinst.StringValue(dev.DeviceName) 1362 m["delete_on_termination"] = spotinst.BoolValue(dev.EBS.DeleteOnTermination) 1363 m["encrypted"] = spotinst.BoolValue(dev.EBS.Encrypted) 1364 m["iops"] = spotinst.IntValue(dev.EBS.IOPS) 1365 m["snapshot_id"] = spotinst.StringValue(dev.EBS.SnapshotID) 1366 m["volume_type"] = spotinst.StringValue(dev.EBS.VolumeType) 1367 m["volume_size"] = spotinst.IntValue(dev.EBS.VolumeSize) 1368 result = append(result, m) 1369 } 1370 } 1371 return result 1372 } 1373 1374 func flattenAwsGroupEphemeralBlockDevices(devices []*spotinst.AwsGroupComputeBlockDevice) []interface{} { 1375 result := make([]interface{}, 0, len(devices)) 1376 for _, dev := range devices { 1377 if dev.EBS == nil { 1378 m := make(map[string]interface{}) 1379 m["device_name"] = spotinst.StringValue(dev.DeviceName) 1380 m["virtual_name"] = spotinst.StringValue(dev.VirtualName) 1381 result = append(result, m) 1382 } 1383 } 1384 return result 1385 } 1386 1387 func flattenAwsGroupRancherIntegration(integration *spotinst.AwsGroupRancherIntegration) []interface{} { 1388 result := make(map[string]interface{}) 1389 result["master_host"] = spotinst.StringValue(integration.MasterHost) 1390 result["access_key"] = spotinst.StringValue(integration.AccessKey) 1391 result["secret_key"] = spotinst.StringValue(integration.SecretKey) 1392 return []interface{}{result} 1393 } 1394 1395 func flattenAwsGroupElasticBeanstalkIntegration(integration *spotinst.AwsGroupElasticBeanstalkIntegration) []interface{} { 1396 result := make(map[string]interface{}) 1397 result["environment_id"] = spotinst.StringValue(integration.EnvironmentID) 1398 return []interface{}{result} 1399 } 1400 1401 func flattenAwsGroupEC2ContainerServiceIntegration(integration *spotinst.AwsGroupEC2ContainerServiceIntegration) []interface{} { 1402 result := make(map[string]interface{}) 1403 result["cluster_name"] = spotinst.StringValue(integration.ClusterName) 1404 return []interface{}{result} 1405 } 1406 1407 func flattenAwsGroupKubernetesIntegration(integration *spotinst.AwsGroupKubernetesIntegration) []interface{} { 1408 result := make(map[string]interface{}) 1409 result["api_server"] = spotinst.StringValue(integration.Server) 1410 result["token"] = spotinst.StringValue(integration.Token) 1411 return []interface{}{result} 1412 } 1413 1414 func flattenAwsGroupMesosphereIntegration(integration *spotinst.AwsGroupMesosphereIntegration) []interface{} { 1415 result := make(map[string]interface{}) 1416 result["api_server"] = spotinst.StringValue(integration.Server) 1417 return []interface{}{result} 1418 } 1419 1420 // buildAwsGroupOpts builds the Spotinst AWS Group options. 1421 func buildAwsGroupOpts(d *schema.ResourceData, meta interface{}) (*spotinst.AwsGroup, error) { 1422 group := &spotinst.AwsGroup{ 1423 Name: spotinst.String(d.Get("name").(string)), 1424 Description: spotinst.String(d.Get("description").(string)), 1425 Scaling: &spotinst.AwsGroupScaling{}, 1426 Scheduling: &spotinst.AwsGroupScheduling{}, 1427 Integration: &spotinst.AwsGroupIntegration{}, 1428 Compute: &spotinst.AwsGroupCompute{ 1429 Product: spotinst.String(d.Get("product").(string)), 1430 LaunchSpecification: &spotinst.AwsGroupComputeLaunchSpecification{}, 1431 }, 1432 } 1433 1434 if v, ok := d.GetOk("capacity"); ok { 1435 if capacity, err := expandAwsGroupCapacity(v); err != nil { 1436 return nil, err 1437 } else { 1438 group.Capacity = capacity 1439 } 1440 } 1441 1442 if v, ok := d.GetOk("strategy"); ok { 1443 if strategy, err := expandAwsGroupStrategy(v); err != nil { 1444 return nil, err 1445 } else { 1446 group.Strategy = strategy 1447 } 1448 } 1449 1450 if v, ok := d.GetOk("scaling_up_policy"); ok { 1451 if policies, err := expandAwsGroupScalingPolicies(v); err != nil { 1452 return nil, err 1453 } else { 1454 group.Scaling.Up = policies 1455 } 1456 } 1457 1458 if v, ok := d.GetOk("scaling_down_policy"); ok { 1459 if policies, err := expandAwsGroupScalingPolicies(v); err != nil { 1460 return nil, err 1461 } else { 1462 group.Scaling.Down = policies 1463 } 1464 } 1465 1466 if v, ok := d.GetOk("scheduled_task"); ok { 1467 if tasks, err := expandAwsGroupScheduledTasks(v); err != nil { 1468 return nil, err 1469 } else { 1470 group.Scheduling.Tasks = tasks 1471 } 1472 } 1473 1474 if v, ok := d.GetOk("instance_types"); ok { 1475 if types, err := expandAwsGroupInstanceTypes(v); err != nil { 1476 return nil, err 1477 } else { 1478 group.Compute.InstanceTypes = types 1479 } 1480 } 1481 1482 if v, ok := d.GetOk("elastic_ips"); ok { 1483 if eips, err := expandAwsGroupElasticIPs(v); err != nil { 1484 return nil, err 1485 } else { 1486 group.Compute.ElasticIPs = eips 1487 } 1488 } 1489 1490 if v, ok := d.GetOk("availability_zone"); ok { 1491 if zones, err := expandAwsGroupAvailabilityZones(v); err != nil { 1492 return nil, err 1493 } else { 1494 group.Compute.AvailabilityZones = zones 1495 } 1496 } 1497 1498 if v, ok := d.GetOk("availability_zones"); ok { 1499 if zones, err := expandAwsGroupAvailabilityZonesSlice(v); err != nil { 1500 return nil, err 1501 } else { 1502 group.Compute.AvailabilityZones = zones 1503 } 1504 } 1505 1506 if v, ok := d.GetOk("hot_ebs_volume"); ok { 1507 if ebsVolumePool, err := expandAwsGroupEBSVolumePool(v); err != nil { 1508 return nil, err 1509 } else { 1510 group.Compute.EBSVolumePool = ebsVolumePool 1511 } 1512 } 1513 1514 if v, ok := d.GetOk("signal"); ok { 1515 if signals, err := expandAwsGroupSignals(v); err != nil { 1516 return nil, err 1517 } else { 1518 group.Strategy.Signals = signals 1519 } 1520 } 1521 1522 if v, ok := d.GetOk("launch_specification"); ok { 1523 if lc, err := expandAwsGroupLaunchSpecification(v); err != nil { 1524 return nil, err 1525 } else { 1526 group.Compute.LaunchSpecification = lc 1527 } 1528 } 1529 1530 if v, ok := d.GetOk("image_id"); ok { 1531 group.Compute.LaunchSpecification.ImageID = spotinst.String(v.(string)) 1532 } 1533 1534 if v, ok := d.GetOk("load_balancer"); ok { 1535 if lbs, err := expandAwsGroupLoadBalancer(v); err != nil { 1536 return nil, err 1537 } else { 1538 if group.Compute.LaunchSpecification.LoadBalancersConfig == nil { 1539 group.Compute.LaunchSpecification.LoadBalancersConfig = &spotinst.AwsGroupComputeLoadBalancersConfig{} 1540 } 1541 group.Compute.LaunchSpecification.LoadBalancersConfig.LoadBalancers = lbs 1542 } 1543 } 1544 1545 if v, ok := d.GetOk("tags"); ok { 1546 if tags, err := expandAwsGroupTags(v); err != nil { 1547 return nil, err 1548 } else { 1549 group.Compute.LaunchSpecification.Tags = tags 1550 } 1551 } 1552 1553 if v, ok := d.GetOk("network_interface"); ok { 1554 if interfaces, err := expandAwsGroupNetworkInterfaces(v); err != nil { 1555 return nil, err 1556 } else { 1557 group.Compute.LaunchSpecification.NetworkInterfaces = interfaces 1558 } 1559 } 1560 1561 if v, ok := d.GetOk("ebs_block_device"); ok { 1562 if devices, err := expandAwsGroupEBSBlockDevices(v); err != nil { 1563 return nil, err 1564 } else { 1565 group.Compute.LaunchSpecification.BlockDevices = devices 1566 } 1567 } 1568 1569 if v, ok := d.GetOk("ephemeral_block_device"); ok { 1570 if devices, err := expandAwsGroupEphemeralBlockDevices(v); err != nil { 1571 return nil, err 1572 } else { 1573 if len(group.Compute.LaunchSpecification.BlockDevices) > 0 { 1574 group.Compute.LaunchSpecification.BlockDevices = append(group.Compute.LaunchSpecification.BlockDevices, devices...) 1575 } else { 1576 group.Compute.LaunchSpecification.BlockDevices = devices 1577 } 1578 } 1579 } 1580 1581 if v, ok := d.GetOk("rancher_integration"); ok { 1582 if integration, err := expandAwsGroupRancherIntegration(v); err != nil { 1583 return nil, err 1584 } else { 1585 group.Integration.Rancher = integration 1586 } 1587 } 1588 1589 if v, ok := d.GetOk("elastic_beanstalk_integration"); ok { 1590 if integration, err := expandAwsGroupElasticBeanstalkIntegration(v); err != nil { 1591 return nil, err 1592 } else { 1593 group.Integration.ElasticBeanstalk = integration 1594 } 1595 } 1596 1597 if v, ok := d.GetOk("ec2_container_service_integration"); ok { 1598 if integration, err := expandAwsGroupEC2ContainerServiceIntegration(v); err != nil { 1599 return nil, err 1600 } else { 1601 group.Integration.EC2ContainerService = integration 1602 } 1603 } 1604 1605 if v, ok := d.GetOk("kubernetes_integration"); ok { 1606 if integration, err := expandAwsGroupKubernetesIntegration(v); err != nil { 1607 return nil, err 1608 } else { 1609 group.Integration.Kubernetes = integration 1610 } 1611 } 1612 1613 return group, nil 1614 } 1615 1616 // expandAwsGroupCapacity expands the Capacity block. 1617 func expandAwsGroupCapacity(data interface{}) (*spotinst.AwsGroupCapacity, error) { 1618 list := data.(*schema.Set).List() 1619 m := list[0].(map[string]interface{}) 1620 capacity := &spotinst.AwsGroupCapacity{} 1621 1622 if v, ok := m["minimum"].(int); ok && v >= 0 { 1623 capacity.Minimum = spotinst.Int(v) 1624 } 1625 1626 if v, ok := m["maximum"].(int); ok && v >= 0 { 1627 capacity.Maximum = spotinst.Int(v) 1628 } 1629 1630 if v, ok := m["target"].(int); ok && v >= 0 { 1631 capacity.Target = spotinst.Int(v) 1632 } 1633 1634 if v, ok := m["unit"].(string); ok && v != "" { 1635 capacity.Unit = spotinst.String(v) 1636 } 1637 1638 log.Printf("[DEBUG] AwsGroup capacity configuration: %s\n", stringutil.Stringify(capacity)) 1639 return capacity, nil 1640 } 1641 1642 // expandAwsGroupStrategy expands the Strategy block. 1643 func expandAwsGroupStrategy(data interface{}) (*spotinst.AwsGroupStrategy, error) { 1644 list := data.(*schema.Set).List() 1645 m := list[0].(map[string]interface{}) 1646 strategy := &spotinst.AwsGroupStrategy{} 1647 1648 if v, ok := m["risk"].(float64); ok && v >= 0 { 1649 strategy.Risk = spotinst.Float64(v) 1650 } 1651 1652 if v, ok := m["ondemand_count"].(int); ok && v >= 0 && spotinst.Float64Value(strategy.Risk) == 0 { 1653 strategy.OnDemandCount = spotinst.Int(v) 1654 strategy.Risk = nil 1655 } 1656 1657 if v, ok := m["availability_vs_cost"].(string); ok && v != "" { 1658 strategy.AvailabilityVsCost = spotinst.String(v) 1659 } 1660 1661 if v, ok := m["draining_timeout"].(int); ok && v > 0 { 1662 strategy.DrainingTimeout = spotinst.Int(v) 1663 } 1664 1665 if v, ok := m["utilize_reserved_instances"].(bool); ok { 1666 strategy.UtilizeReservedInstances = spotinst.Bool(v) 1667 } 1668 1669 if v, ok := m["fallback_to_ondemand"].(bool); ok { 1670 strategy.FallbackToOnDemand = spotinst.Bool(v) 1671 } 1672 1673 log.Printf("[DEBUG] AwsGroup strategy configuration: %s\n", stringutil.Stringify(strategy)) 1674 return strategy, nil 1675 } 1676 1677 // expandAwsGroupScalingPolicies expands the Scaling Policy block. 1678 func expandAwsGroupScalingPolicies(data interface{}) ([]*spotinst.AwsGroupScalingPolicy, error) { 1679 list := data.(*schema.Set).List() 1680 policies := make([]*spotinst.AwsGroupScalingPolicy, 0, len(list)) 1681 for _, item := range list { 1682 m := item.(map[string]interface{}) 1683 policy := &spotinst.AwsGroupScalingPolicy{} 1684 1685 if v, ok := m["policy_name"].(string); ok && v != "" { 1686 policy.PolicyName = spotinst.String(v) 1687 } 1688 1689 if v, ok := m["metric_name"].(string); ok && v != "" { 1690 policy.MetricName = spotinst.String(v) 1691 } 1692 1693 if v, ok := m["statistic"].(string); ok && v != "" { 1694 policy.Statistic = spotinst.String(v) 1695 } 1696 1697 if v, ok := m["unit"].(string); ok && v != "" { 1698 policy.Unit = spotinst.String(v) 1699 } 1700 1701 if v, ok := m["threshold"].(float64); ok && v > 0 { 1702 policy.Threshold = spotinst.Float64(v) 1703 } 1704 1705 if v, ok := m["adjustment"].(int); ok && v > 0 { 1706 policy.Adjustment = spotinst.Int(v) 1707 } 1708 1709 if v, ok := m["min_target_capacity"].(int); ok && v > 0 { 1710 policy.MinTargetCapacity = spotinst.Int(v) 1711 } 1712 1713 if v, ok := m["max_target_capacity"].(int); ok && v > 0 { 1714 policy.MaxTargetCapacity = spotinst.Int(v) 1715 } 1716 1717 if v, ok := m["namespace"].(string); ok && v != "" { 1718 policy.Namespace = spotinst.String(v) 1719 } 1720 1721 if v, ok := m["operator"].(string); ok && v != "" { 1722 policy.Operator = spotinst.String(v) 1723 } 1724 1725 if v, ok := m["period"].(int); ok && v > 0 { 1726 policy.Period = spotinst.Int(v) 1727 } 1728 1729 if v, ok := m["evaluation_periods"].(int); ok && v > 0 { 1730 policy.EvaluationPeriods = spotinst.Int(v) 1731 } 1732 1733 if v, ok := m["cooldown"].(int); ok && v > 0 { 1734 policy.Cooldown = spotinst.Int(v) 1735 } 1736 1737 if v, ok := m["dimensions"]; ok { 1738 dimensions := expandAwsGroupScalingPolicyDimensions(v.(map[string]interface{})) 1739 policy.Dimensions = dimensions 1740 } 1741 1742 if v, ok := m["namespace"].(string); ok && v != "" { 1743 log.Printf("[DEBUG] AwsGroup scaling policy configuration: %s\n", stringutil.Stringify(policy)) 1744 policies = append(policies, policy) 1745 } 1746 } 1747 1748 return policies, nil 1749 } 1750 1751 func expandAwsGroupScalingPolicyDimensions(list map[string]interface{}) []*spotinst.AwsGroupScalingPolicyDimension { 1752 dimensions := make([]*spotinst.AwsGroupScalingPolicyDimension, 0, len(list)) 1753 for name, val := range list { 1754 dimension := &spotinst.AwsGroupScalingPolicyDimension{ 1755 Name: spotinst.String(name), 1756 Value: spotinst.String(val.(string)), 1757 } 1758 log.Printf("[DEBUG] AwsGroup scaling policy dimension: %s\n", stringutil.Stringify(dimension)) 1759 dimensions = append(dimensions, dimension) 1760 } 1761 return dimensions 1762 } 1763 1764 // expandAwsGroupScheduledTasks expands the Scheduled Task block. 1765 func expandAwsGroupScheduledTasks(data interface{}) ([]*spotinst.AwsGroupScheduledTask, error) { 1766 list := data.(*schema.Set).List() 1767 tasks := make([]*spotinst.AwsGroupScheduledTask, 0, len(list)) 1768 for _, item := range list { 1769 m := item.(map[string]interface{}) 1770 task := &spotinst.AwsGroupScheduledTask{} 1771 1772 if v, ok := m["task_type"].(string); ok && v != "" { 1773 task.TaskType = spotinst.String(v) 1774 } 1775 1776 if v, ok := m["frequency"].(string); ok && v != "" { 1777 task.Frequency = spotinst.String(v) 1778 } 1779 1780 if v, ok := m["cron_expression"].(string); ok && v != "" { 1781 task.CronExpression = spotinst.String(v) 1782 } 1783 1784 if v, ok := m["scale_target_capacity"].(int); ok && v > 0 { 1785 task.ScaleTargetCapacity = spotinst.Int(v) 1786 } 1787 1788 if v, ok := m["scale_min_capacity"].(int); ok && v > 0 { 1789 task.ScaleMinCapacity = spotinst.Int(v) 1790 } 1791 1792 if v, ok := m["scale_max_capacity"].(int); ok && v > 0 { 1793 task.ScaleMaxCapacity = spotinst.Int(v) 1794 } 1795 1796 log.Printf("[DEBUG] AwsGroup scheduled task configuration: %s\n", stringutil.Stringify(task)) 1797 tasks = append(tasks, task) 1798 } 1799 1800 return tasks, nil 1801 } 1802 1803 // expandAwsGroupAvailabilityZones expands the Availability Zone block. 1804 func expandAwsGroupAvailabilityZones(data interface{}) ([]*spotinst.AwsGroupComputeAvailabilityZone, error) { 1805 list := data.(*schema.Set).List() 1806 zones := make([]*spotinst.AwsGroupComputeAvailabilityZone, 0, len(list)) 1807 for _, item := range list { 1808 m := item.(map[string]interface{}) 1809 zone := &spotinst.AwsGroupComputeAvailabilityZone{} 1810 1811 if v, ok := m["name"].(string); ok && v != "" { 1812 zone.Name = spotinst.String(v) 1813 } 1814 1815 if v, ok := m["subnet_id"].(string); ok && v != "" { 1816 zone.SubnetID = spotinst.String(v) 1817 } 1818 1819 log.Printf("[DEBUG] AwsGroup availability zone configuration: %s\n", stringutil.Stringify(zone)) 1820 zones = append(zones, zone) 1821 } 1822 1823 return zones, nil 1824 } 1825 1826 // expandAwsGroupAvailabilityZonesSlice expands the Availability Zone block when provided as a slice. 1827 func expandAwsGroupAvailabilityZonesSlice(data interface{}) ([]*spotinst.AwsGroupComputeAvailabilityZone, error) { 1828 list := data.([]interface{}) 1829 zones := make([]*spotinst.AwsGroupComputeAvailabilityZone, 0, len(list)) 1830 for _, str := range list { 1831 if s, ok := str.(string); ok { 1832 parts := strings.Split(s, ":") 1833 zone := &spotinst.AwsGroupComputeAvailabilityZone{} 1834 if len(parts) >= 1 && parts[0] != "" { 1835 zone.Name = spotinst.String(parts[0]) 1836 } 1837 if len(parts) == 2 && parts[1] != "" { 1838 zone.SubnetID = spotinst.String(parts[1]) 1839 } 1840 log.Printf("[DEBUG] AwsGroup availability zone configuration: %s\n", stringutil.Stringify(zone)) 1841 zones = append(zones, zone) 1842 } 1843 } 1844 1845 return zones, nil 1846 } 1847 1848 // expandAwsGroupEBSVolumePool expands the EBS Volume Pool block. 1849 func expandAwsGroupEBSVolumePool(data interface{}) ([]*spotinst.AwsGroupComputeEBSVolume, error) { 1850 list := data.(*schema.Set).List() 1851 volumes := make([]*spotinst.AwsGroupComputeEBSVolume, 0, len(list)) 1852 for _, item := range list { 1853 m := item.(map[string]interface{}) 1854 volume := &spotinst.AwsGroupComputeEBSVolume{} 1855 1856 if v, ok := m["device_name"].(string); ok && v != "" { 1857 volume.DeviceName = spotinst.String(v) 1858 } 1859 1860 if v, ok := m["volume_ids"].([]interface{}); ok { 1861 ids := make([]string, len(v)) 1862 for i, j := range v { 1863 ids[i] = j.(string) 1864 } 1865 volume.VolumeIDs = ids 1866 } 1867 1868 log.Printf("[DEBUG] AwsGroup EBS volume (pool) configuration: %s\n", stringutil.Stringify(volume)) 1869 volumes = append(volumes, volume) 1870 } 1871 1872 return volumes, nil 1873 } 1874 1875 // expandAwsGroupSignals expands the Signal block. 1876 func expandAwsGroupSignals(data interface{}) ([]*spotinst.AwsGroupStrategySignal, error) { 1877 list := data.(*schema.Set).List() 1878 signals := make([]*spotinst.AwsGroupStrategySignal, 0, len(list)) 1879 for _, item := range list { 1880 m := item.(map[string]interface{}) 1881 signal := &spotinst.AwsGroupStrategySignal{} 1882 1883 if v, ok := m["name"].(string); ok && v != "" { 1884 signal.Name = spotinst.String(strings.ToUpper(v)) 1885 } 1886 1887 log.Printf("[DEBUG] AwsGroup signal configuration: %s\n", stringutil.Stringify(signal)) 1888 signals = append(signals, signal) 1889 } 1890 1891 return signals, nil 1892 } 1893 1894 // expandAwsGroupInstanceTypes expands the Instance Types block. 1895 func expandAwsGroupInstanceTypes(data interface{}) (*spotinst.AwsGroupComputeInstanceType, error) { 1896 list := data.(*schema.Set).List() 1897 m := list[0].(map[string]interface{}) 1898 types := &spotinst.AwsGroupComputeInstanceType{} 1899 if v, ok := m["ondemand"].(string); ok && v != "" { 1900 types.OnDemand = spotinst.String(v) 1901 } 1902 if v, ok := m["spot"].([]interface{}); ok { 1903 it := make([]string, len(v)) 1904 for i, j := range v { 1905 it[i] = j.(string) 1906 } 1907 types.Spot = it 1908 } 1909 1910 log.Printf("[DEBUG] AwsGroup instance types configuration: %s\n", stringutil.Stringify(types)) 1911 return types, nil 1912 } 1913 1914 // expandAwsGroupNetworkInterfaces expands the Elastic Network Interface block. 1915 func expandAwsGroupNetworkInterfaces(data interface{}) ([]*spotinst.AwsGroupComputeNetworkInterface, error) { 1916 list := data.(*schema.Set).List() 1917 interfaces := make([]*spotinst.AwsGroupComputeNetworkInterface, 0, len(list)) 1918 for _, item := range list { 1919 m := item.(map[string]interface{}) 1920 iface := &spotinst.AwsGroupComputeNetworkInterface{} 1921 1922 if v, ok := m["network_interface_id"].(string); ok && v != "" { 1923 iface.ID = spotinst.String(v) 1924 } 1925 1926 if v, ok := m["description"].(string); ok && v != "" { 1927 iface.Description = spotinst.String(v) 1928 } 1929 1930 if v, ok := m["device_index"].(int); ok && v >= 0 { 1931 iface.DeviceIndex = spotinst.Int(v) 1932 } 1933 1934 if v, ok := m["secondary_private_ip_address_count"].(int); ok && v > 0 { 1935 iface.SecondaryPrivateIPAddressCount = spotinst.Int(v) 1936 } 1937 1938 if v, ok := m["associate_public_ip_address"].(bool); ok { 1939 iface.AssociatePublicIPAddress = spotinst.Bool(v) 1940 } 1941 1942 if v, ok := m["delete_on_termination"].(bool); ok { 1943 iface.DeleteOnTermination = spotinst.Bool(v) 1944 } 1945 1946 if v, ok := m["private_ip_address"].(string); ok && v != "" { 1947 iface.PrivateIPAddress = spotinst.String(v) 1948 } 1949 1950 if v, ok := m["subnet_id"].(string); ok && v != "" { 1951 iface.SubnetID = spotinst.String(v) 1952 } 1953 1954 if v, ok := m["security_group_ids"].([]interface{}); ok { 1955 ids := make([]string, len(v)) 1956 for i, j := range v { 1957 ids[i] = j.(string) 1958 } 1959 iface.SecurityGroupsIDs = ids 1960 } 1961 1962 log.Printf("[DEBUG] AwsGroup network interface configuration: %s\n", stringutil.Stringify(iface)) 1963 interfaces = append(interfaces, iface) 1964 } 1965 1966 return interfaces, nil 1967 } 1968 1969 // expandAwsGroupEphemeralBlockDevice expands the Ephemeral Block Device block. 1970 func expandAwsGroupEphemeralBlockDevices(data interface{}) ([]*spotinst.AwsGroupComputeBlockDevice, error) { 1971 list := data.(*schema.Set).List() 1972 devices := make([]*spotinst.AwsGroupComputeBlockDevice, 0, len(list)) 1973 for _, item := range list { 1974 m := item.(map[string]interface{}) 1975 device := &spotinst.AwsGroupComputeBlockDevice{} 1976 1977 if v, ok := m["device_name"].(string); ok && v != "" { 1978 device.DeviceName = spotinst.String(v) 1979 } 1980 1981 if v, ok := m["virtual_name"].(string); ok && v != "" { 1982 device.VirtualName = spotinst.String(v) 1983 } 1984 1985 log.Printf("[DEBUG] AwsGroup ephemeral block device configuration: %s\n", stringutil.Stringify(device)) 1986 devices = append(devices, device) 1987 } 1988 1989 return devices, nil 1990 } 1991 1992 // expandAwsGroupEBSBlockDevices expands the EBS Block Device block. 1993 func expandAwsGroupEBSBlockDevices(data interface{}) ([]*spotinst.AwsGroupComputeBlockDevice, error) { 1994 list := data.(*schema.Set).List() 1995 devices := make([]*spotinst.AwsGroupComputeBlockDevice, 0, len(list)) 1996 for _, item := range list { 1997 m := item.(map[string]interface{}) 1998 device := &spotinst.AwsGroupComputeBlockDevice{EBS: &spotinst.AwsGroupComputeEBS{}} 1999 2000 if v, ok := m["device_name"].(string); ok && v != "" { 2001 device.DeviceName = spotinst.String(v) 2002 } 2003 2004 if v, ok := m["delete_on_termination"].(bool); ok { 2005 device.EBS.DeleteOnTermination = spotinst.Bool(v) 2006 } 2007 2008 if v, ok := m["encrypted"].(bool); ok { 2009 device.EBS.Encrypted = spotinst.Bool(v) 2010 } 2011 2012 if v, ok := m["snapshot_id"].(string); ok && v != "" { 2013 device.EBS.SnapshotID = spotinst.String(v) 2014 } 2015 2016 if v, ok := m["volume_type"].(string); ok && v != "" { 2017 device.EBS.VolumeType = spotinst.String(v) 2018 } 2019 2020 if v, ok := m["volume_size"].(int); ok && v > 0 { 2021 device.EBS.VolumeSize = spotinst.Int(v) 2022 } 2023 2024 if v, ok := m["iops"].(int); ok && v > 0 { 2025 device.EBS.IOPS = spotinst.Int(v) 2026 } 2027 2028 log.Printf("[DEBUG] AwsGroup elastic block device configuration: %s\n", stringutil.Stringify(device)) 2029 devices = append(devices, device) 2030 } 2031 2032 return devices, nil 2033 } 2034 2035 // iprofArnRE is a regular expression for matching IAM instance profile ARNs. 2036 var iprofArnRE = regexp.MustCompile(`arn:aws:iam::\d{12}:instance-profile/?[a-zA-Z_0-9+=,.@\-_/]+`) 2037 2038 // expandAwsGroupLaunchSpecification expands the launch Specification block. 2039 func expandAwsGroupLaunchSpecification(data interface{}) (*spotinst.AwsGroupComputeLaunchSpecification, error) { 2040 list := data.(*schema.Set).List() 2041 m := list[0].(map[string]interface{}) 2042 lc := &spotinst.AwsGroupComputeLaunchSpecification{} 2043 2044 if v, ok := m["monitoring"].(bool); ok { 2045 lc.Monitoring = spotinst.Bool(v) 2046 } 2047 2048 if v, ok := m["ebs_optimized"].(bool); ok { 2049 lc.EBSOptimized = spotinst.Bool(v) 2050 } 2051 2052 if v, ok := m["image_id"].(string); ok && v != "" { 2053 lc.ImageID = spotinst.String(v) 2054 } 2055 2056 if v, ok := m["key_pair"].(string); ok && v != "" { 2057 lc.KeyPair = spotinst.String(v) 2058 } 2059 2060 if v, ok := m["health_check_type"].(string); ok && v != "" { 2061 lc.HealthCheckType = spotinst.String(v) 2062 } 2063 2064 if v, ok := m["health_check_grace_period"].(int); ok && v > 0 { 2065 lc.HealthCheckGracePeriod = spotinst.Int(v) 2066 } 2067 2068 if v, ok := m["iam_instance_profile"].(string); ok && v != "" { 2069 iprof := &spotinst.AwsGroupComputeIamInstanceProfile{} 2070 if iprofArnRE.MatchString(v) { 2071 iprof.Arn = spotinst.String(v) 2072 } else { 2073 iprof.Name = spotinst.String(v) 2074 } 2075 lc.IamInstanceProfile = iprof 2076 } 2077 2078 if v, ok := m["user_data"].(string); ok && v != "" { 2079 lc.UserData = spotinst.String(base64.StdEncoding.EncodeToString([]byte(v))) 2080 } 2081 2082 if v, ok := m["security_group_ids"].([]interface{}); ok { 2083 ids := make([]string, len(v)) 2084 for i, j := range v { 2085 ids[i] = j.(string) 2086 } 2087 lc.SecurityGroupIDs = ids 2088 } 2089 2090 if v, ok := m["load_balancer_names"].([]interface{}); ok { 2091 var names []string 2092 for _, j := range v { 2093 if name, ok := j.(string); ok && name != "" { 2094 names = append(names, name) 2095 } 2096 } 2097 lc.LoadBalancerNames = names 2098 } 2099 2100 log.Printf("[DEBUG] AwsGroup launch specification configuration: %s\n", stringutil.Stringify(lc)) 2101 return lc, nil 2102 } 2103 2104 // expandAwsGroupLoadBalancer expands the Load Balancer block. 2105 func expandAwsGroupLoadBalancer(data interface{}) ([]*spotinst.AwsGroupComputeLoadBalancer, error) { 2106 list := data.(*schema.Set).List() 2107 lbs := make([]*spotinst.AwsGroupComputeLoadBalancer, 0, len(list)) 2108 for _, item := range list { 2109 m := item.(map[string]interface{}) 2110 lb := &spotinst.AwsGroupComputeLoadBalancer{} 2111 2112 if v, ok := m["name"].(string); ok && v != "" { 2113 lb.Name = spotinst.String(v) 2114 } 2115 2116 if v, ok := m["arn"].(string); ok && v != "" { 2117 lb.Arn = spotinst.String(v) 2118 } 2119 2120 if v, ok := m["type"].(string); ok && v != "" { 2121 lb.Type = spotinst.String(strings.ToUpper(v)) 2122 } 2123 2124 log.Printf("[DEBUG] AwsGroup load balancer configuration: %s\n", stringutil.Stringify(lb)) 2125 lbs = append(lbs, lb) 2126 } 2127 2128 return lbs, nil 2129 } 2130 2131 // expandAwsGroupRancherIntegration expands the Rancher Integration block. 2132 func expandAwsGroupRancherIntegration(data interface{}) (*spotinst.AwsGroupRancherIntegration, error) { 2133 list := data.(*schema.Set).List() 2134 m := list[0].(map[string]interface{}) 2135 i := &spotinst.AwsGroupRancherIntegration{} 2136 2137 if v, ok := m["master_host"].(string); ok && v != "" { 2138 i.MasterHost = spotinst.String(v) 2139 } 2140 2141 if v, ok := m["access_key"].(string); ok && v != "" { 2142 i.AccessKey = spotinst.String(v) 2143 } 2144 2145 if v, ok := m["secret_key"].(string); ok && v != "" { 2146 i.SecretKey = spotinst.String(v) 2147 } 2148 2149 log.Printf("[DEBUG] AwsGroup Rancher integration configuration: %s\n", stringutil.Stringify(i)) 2150 return i, nil 2151 } 2152 2153 // expandAwsGroupElasticBeanstalkIntegration expands the Elastic Beanstalk Integration block. 2154 func expandAwsGroupElasticBeanstalkIntegration(data interface{}) (*spotinst.AwsGroupElasticBeanstalkIntegration, error) { 2155 list := data.(*schema.Set).List() 2156 m := list[0].(map[string]interface{}) 2157 i := &spotinst.AwsGroupElasticBeanstalkIntegration{} 2158 2159 if v, ok := m["environment_id"].(string); ok && v != "" { 2160 i.EnvironmentID = spotinst.String(v) 2161 } 2162 2163 log.Printf("[DEBUG] AwsGroup Elastic Beanstalk integration configuration: %s\n", stringutil.Stringify(i)) 2164 return i, nil 2165 } 2166 2167 // expandAwsGroupEC2ContainerServiceIntegration expands the EC2 Container Service Integration block. 2168 func expandAwsGroupEC2ContainerServiceIntegration(data interface{}) (*spotinst.AwsGroupEC2ContainerServiceIntegration, error) { 2169 list := data.(*schema.Set).List() 2170 m := list[0].(map[string]interface{}) 2171 i := &spotinst.AwsGroupEC2ContainerServiceIntegration{} 2172 2173 if v, ok := m["cluster_name"].(string); ok && v != "" { 2174 i.ClusterName = spotinst.String(v) 2175 } 2176 2177 log.Printf("[DEBUG] AwsGroup ECS integration configuration: %s\n", stringutil.Stringify(i)) 2178 return i, nil 2179 } 2180 2181 // expandAwsGroupKubernetesIntegration expands the Kubernetes Integration block. 2182 func expandAwsGroupKubernetesIntegration(data interface{}) (*spotinst.AwsGroupKubernetesIntegration, error) { 2183 list := data.(*schema.Set).List() 2184 m := list[0].(map[string]interface{}) 2185 i := &spotinst.AwsGroupKubernetesIntegration{} 2186 2187 if v, ok := m["api_server"].(string); ok && v != "" { 2188 i.Server = spotinst.String(v) 2189 } 2190 2191 if v, ok := m["token"].(string); ok && v != "" { 2192 i.Token = spotinst.String(v) 2193 } 2194 2195 log.Printf("[DEBUG] AwsGroup Kubernetes integration configuration: %s\n", stringutil.Stringify(i)) 2196 return i, nil 2197 } 2198 2199 // expandAwsGroupMesosphereIntegration expands the Mesosphere Integration block. 2200 func expandAwsGroupMesosphereIntegration(data interface{}) (*spotinst.AwsGroupMesosphereIntegration, error) { 2201 list := data.(*schema.Set).List() 2202 m := list[0].(map[string]interface{}) 2203 i := &spotinst.AwsGroupMesosphereIntegration{} 2204 2205 if v, ok := m["api_server"].(string); ok && v != "" { 2206 i.Server = spotinst.String(v) 2207 } 2208 2209 log.Printf("[DEBUG] AwsGroup Mesosphere integration configuration: %s\n", stringutil.Stringify(i)) 2210 return i, nil 2211 } 2212 2213 // expandAwsGroupElasticIPs expands the Elastic IPs block. 2214 func expandAwsGroupElasticIPs(data interface{}) ([]string, error) { 2215 list := data.([]interface{}) 2216 eips := make([]string, 0, len(list)) 2217 for _, str := range list { 2218 if eip, ok := str.(string); ok { 2219 log.Printf("[DEBUG] AwsGroup elastic IP configuration: %s\n", stringutil.Stringify(eip)) 2220 eips = append(eips, eip) 2221 } 2222 } 2223 2224 return eips, nil 2225 } 2226 2227 // expandAwsGroupTags expands the Tags block. 2228 func expandAwsGroupTags(data interface{}) ([]*spotinst.AwsGroupComputeTag, error) { 2229 list := data.(map[string]interface{}) 2230 tags := make([]*spotinst.AwsGroupComputeTag, 0, len(list)) 2231 for k, v := range list { 2232 tag := &spotinst.AwsGroupComputeTag{ 2233 Key: spotinst.String(k), 2234 Value: spotinst.String(v.(string)), 2235 } 2236 2237 log.Printf("[DEBUG] AwsGroup tag configuration: %s\n", stringutil.Stringify(tag)) 2238 tags = append(tags, tag) 2239 } 2240 2241 return tags, nil 2242 } 2243 2244 func hashAwsGroupCapacity(v interface{}) int { 2245 var buf bytes.Buffer 2246 m := v.(map[string]interface{}) 2247 2248 buf.WriteString(fmt.Sprintf("%d-", m["target"].(int))) 2249 buf.WriteString(fmt.Sprintf("%d-", m["minimum"].(int))) 2250 buf.WriteString(fmt.Sprintf("%d-", m["maximum"].(int))) 2251 2252 return hashcode.String(buf.String()) 2253 } 2254 2255 func hashAwsGroupStrategy(v interface{}) int { 2256 var buf bytes.Buffer 2257 m := v.(map[string]interface{}) 2258 2259 buf.WriteString(fmt.Sprintf("%f-", m["risk"].(float64))) 2260 buf.WriteString(fmt.Sprintf("%d-", m["ondemand_count"].(int))) 2261 buf.WriteString(fmt.Sprintf("%t-", m["utilize_reserved_instances"].(bool))) 2262 buf.WriteString(fmt.Sprintf("%t-", m["fallback_to_ondemand"].(bool))) 2263 2264 return hashcode.String(buf.String()) 2265 } 2266 2267 func hashAwsGroupLoadBalancer(v interface{}) int { 2268 var buf bytes.Buffer 2269 m := v.(map[string]interface{}) 2270 2271 buf.WriteString(fmt.Sprintf("%s-", m["name"].(string))) 2272 buf.WriteString(fmt.Sprintf("%s-", m["type"].(string))) 2273 if v, ok := m["arn"].(string); ok && len(v) > 0 { 2274 buf.WriteString(fmt.Sprintf("%s-", v)) 2275 } 2276 2277 return hashcode.String(buf.String()) 2278 } 2279 2280 func hashAwsGroupEBSBlockDevice(v interface{}) int { 2281 var buf bytes.Buffer 2282 m := v.(map[string]interface{}) 2283 2284 buf.WriteString(fmt.Sprintf("%s-", m["device_name"].(string))) 2285 buf.WriteString(fmt.Sprintf("%s-", m["snapshot_id"].(string))) 2286 buf.WriteString(fmt.Sprintf("%d-", m["volume_size"].(int))) 2287 buf.WriteString(fmt.Sprintf("%t-", m["delete_on_termination"].(bool))) 2288 buf.WriteString(fmt.Sprintf("%t-", m["encrypted"].(bool))) 2289 buf.WriteString(fmt.Sprintf("%d-", m["iops"].(int))) 2290 2291 return hashcode.String(buf.String()) 2292 } 2293 2294 func hashAwsGroupScalingPolicy(v interface{}) int { 2295 var buf bytes.Buffer 2296 m := v.(map[string]interface{}) 2297 2298 buf.WriteString(fmt.Sprintf("%d-", m["adjustment"].(int))) 2299 buf.WriteString(fmt.Sprintf("%d-", m["cooldown"].(int))) 2300 buf.WriteString(fmt.Sprintf("%d-", m["evaluation_periods"].(int))) 2301 buf.WriteString(fmt.Sprintf("%s-", m["metric_name"].(string))) 2302 buf.WriteString(fmt.Sprintf("%s-", m["namespace"].(string))) 2303 buf.WriteString(fmt.Sprintf("%d-", m["period"].(int))) 2304 buf.WriteString(fmt.Sprintf("%s-", m["policy_name"].(string))) 2305 buf.WriteString(fmt.Sprintf("%s-", m["statistic"].(string))) 2306 buf.WriteString(fmt.Sprintf("%f-", m["threshold"].(float64))) 2307 buf.WriteString(fmt.Sprintf("%s-", m["unit"].(string))) 2308 buf.WriteString(fmt.Sprintf("%d-", m["min_target_capacity"].(int))) 2309 buf.WriteString(fmt.Sprintf("%d-", m["max_target_capacity"].(int))) 2310 2311 // if v, ok := m["operator"].(string); ok && len(v) > 0 { 2312 // buf.WriteString(fmt.Sprintf("%s-", v)) 2313 // } 2314 2315 if d, ok := m["dimensions"]; ok { 2316 if len(d.(map[string]interface{})) > 0 { 2317 e := d.(map[string]interface{}) 2318 for k, v := range e { 2319 buf.WriteString(fmt.Sprintf("%s:%s-", k, v.(string))) 2320 } 2321 } 2322 } 2323 2324 return hashcode.String(buf.String()) 2325 } 2326 2327 // tagsToMap turns the list of tags into a map. 2328 func tagsToMap(ts []*spotinst.AwsGroupComputeTag) map[string]string { 2329 result := make(map[string]string) 2330 for _, t := range ts { 2331 result[spotinst.StringValue(t.Key)] = spotinst.StringValue(t.Value) 2332 } 2333 return result 2334 }