2017-02-13 17:33:50 +01:00
package azurerm
import (
"fmt"
"log"
"net/http"
"time"
"bytes"
"github.com/Azure/azure-sdk-for-go/arm/containerservice"
"github.com/hashicorp/terraform/helper/hashcode"
"github.com/hashicorp/terraform/helper/resource"
"github.com/hashicorp/terraform/helper/schema"
)
func resourceArmContainerService ( ) * schema . Resource {
return & schema . Resource {
Create : resourceArmContainerServiceCreate ,
Read : resourceArmContainerServiceRead ,
Update : resourceArmContainerServiceCreate ,
Delete : resourceArmContainerServiceDelete ,
Schema : map [ string ] * schema . Schema {
"name" : {
Type : schema . TypeString ,
Required : true ,
ForceNew : true ,
} ,
"location" : locationSchema ( ) ,
"resource_group_name" : {
Type : schema . TypeString ,
Required : true ,
ForceNew : true ,
} ,
"orchestration_platform" : {
Type : schema . TypeString ,
Required : true ,
ForceNew : true ,
ValidateFunc : validateArmContainerServiceOrchestrationPlatform ,
} ,
"master_profile" : {
Type : schema . TypeSet ,
Required : true ,
MaxItems : 1 ,
Elem : & schema . Resource {
Schema : map [ string ] * schema . Schema {
"count" : {
Type : schema . TypeInt ,
Optional : true ,
Default : 1 ,
ValidateFunc : validateArmContainerServiceMasterProfileCount ,
} ,
"dns_prefix" : {
Type : schema . TypeString ,
Required : true ,
} ,
"fqdn" : {
Type : schema . TypeString ,
Computed : true ,
} ,
} ,
} ,
Set : resourceAzureRMContainerServiceMasterProfileHash ,
} ,
"linux_profile" : {
Type : schema . TypeSet ,
Required : true ,
MaxItems : 1 ,
Elem : & schema . Resource {
Schema : map [ string ] * schema . Schema {
"admin_username" : {
Type : schema . TypeString ,
Required : true ,
} ,
"ssh_key" : {
Type : schema . TypeSet ,
Required : true ,
MaxItems : 1 ,
Elem : & schema . Resource {
Schema : map [ string ] * schema . Schema {
"key_data" : {
Type : schema . TypeString ,
Required : true ,
} ,
} ,
} ,
} ,
} ,
} ,
Set : resourceAzureRMContainerServiceLinuxProfilesHash ,
} ,
"agent_pool_profile" : {
Type : schema . TypeSet ,
Required : true ,
MaxItems : 1 ,
Elem : & schema . Resource {
Schema : map [ string ] * schema . Schema {
"name" : {
Type : schema . TypeString ,
Required : true ,
ForceNew : true ,
} ,
"count" : {
Type : schema . TypeInt ,
Optional : true ,
Default : 1 ,
ValidateFunc : validateArmContainerServiceAgentPoolProfileCount ,
} ,
"dns_prefix" : {
Type : schema . TypeString ,
Required : true ,
ForceNew : true ,
} ,
"fqdn" : {
Type : schema . TypeString ,
Computed : true ,
} ,
"vm_size" : {
Type : schema . TypeString ,
Required : true ,
} ,
} ,
} ,
Set : resourceAzureRMContainerServiceAgentPoolProfilesHash ,
} ,
"service_principal" : {
Type : schema . TypeSet ,
Optional : true ,
MaxItems : 1 ,
Elem : & schema . Resource {
Schema : map [ string ] * schema . Schema {
"client_id" : {
Type : schema . TypeString ,
Required : true ,
} ,
"client_secret" : {
Type : schema . TypeString ,
Required : true ,
Sensitive : true ,
} ,
} ,
} ,
Set : resourceAzureRMContainerServiceServicePrincipalProfileHash ,
} ,
"diagnostics_profile" : {
Type : schema . TypeSet ,
Required : true ,
MaxItems : 1 ,
Elem : & schema . Resource {
Schema : map [ string ] * schema . Schema {
"enabled" : {
Type : schema . TypeBool ,
Required : true ,
} ,
"storage_uri" : {
Type : schema . TypeString ,
Computed : true ,
} ,
} ,
} ,
Set : resourceAzureRMContainerServiceDiagnosticProfilesHash ,
} ,
"tags" : tagsSchema ( ) ,
} ,
}
}
func resourceArmContainerServiceCreate ( d * schema . ResourceData , meta interface { } ) error {
client := meta . ( * ArmClient )
containerServiceClient := client . containerServicesClient
log . Printf ( "[INFO] preparing arguments for Azure ARM Container Service creation." )
resGroup := d . Get ( "resource_group_name" ) . ( string )
name := d . Get ( "name" ) . ( string )
location := d . Get ( "location" ) . ( string )
orchestrationPlatform := d . Get ( "orchestration_platform" ) . ( string )
masterProfile := expandAzureRmContainerServiceMasterProfile ( d )
linuxProfile := expandAzureRmContainerServiceLinuxProfile ( d )
agentProfiles := expandAzureRmContainerServiceAgentProfiles ( d )
diagnosticsProfile := expandAzureRmContainerServiceDiagnostics ( d )
tags := d . Get ( "tags" ) . ( map [ string ] interface { } )
parameters := containerservice . ContainerService {
Name : & name ,
Location : & location ,
Properties : & containerservice . Properties {
MasterProfile : & masterProfile ,
LinuxProfile : & linuxProfile ,
OrchestratorProfile : & containerservice . OrchestratorProfile {
OrchestratorType : containerservice . OchestratorTypes ( orchestrationPlatform ) ,
} ,
AgentPoolProfiles : & agentProfiles ,
DiagnosticsProfile : & diagnosticsProfile ,
} ,
Tags : expandTags ( tags ) ,
}
servicePrincipalProfile := expandAzureRmContainerServiceServicePrincipal ( d )
if servicePrincipalProfile != nil {
parameters . ServicePrincipalProfile = servicePrincipalProfile
}
_ , err := containerServiceClient . CreateOrUpdate ( resGroup , name , parameters , make ( chan struct { } ) )
if err != nil {
return err
}
read , err := containerServiceClient . Get ( resGroup , name )
if err != nil {
return err
}
if read . ID == nil {
return fmt . Errorf ( "Cannot read Container Service %s (resource group %s) ID" , name , resGroup )
}
log . Printf ( "[DEBUG] Waiting for Container Service (%s) to become available" , d . Get ( "name" ) )
stateConf := & resource . StateChangeConf {
Pending : [ ] string { "Updating" , "Creating" } ,
Target : [ ] string { "Succeeded" } ,
Refresh : containerServiceStateRefreshFunc ( client , resGroup , name ) ,
Timeout : 30 * time . Minute ,
MinTimeout : 15 * time . Second ,
}
if _ , err := stateConf . WaitForState ( ) ; err != nil {
return fmt . Errorf ( "Error waiting for Container Service (%s) to become available: %s" , d . Get ( "name" ) , err )
}
d . SetId ( * read . ID )
return resourceArmContainerServiceRead ( d , meta )
}
func resourceArmContainerServiceRead ( d * schema . ResourceData , meta interface { } ) error {
containerServiceClient := meta . ( * ArmClient ) . containerServicesClient
id , err := parseAzureResourceID ( d . Id ( ) )
if err != nil {
return err
}
resGroup := id . ResourceGroup
name := id . Path [ "containerServices" ]
resp , err := containerServiceClient . Get ( resGroup , name )
if err != nil {
return fmt . Errorf ( "Error making Read request on Azure Container Service %s: %s" , name , err )
}
if resp . StatusCode == http . StatusNotFound {
d . SetId ( "" )
return nil
}
d . Set ( "name" , resp . Name )
d . Set ( "location" , azureRMNormalizeLocation ( * resp . Location ) )
d . Set ( "resource_group_name" , resGroup )
d . Set ( "orchestration_platform" , string ( resp . Properties . OrchestratorProfile . OrchestratorType ) )
masterProfiles := flattenAzureRmContainerServiceMasterProfile ( * resp . Properties . MasterProfile )
d . Set ( "master_profile" , & masterProfiles )
linuxProfile := flattenAzureRmContainerServiceLinuxProfile ( * resp . Properties . LinuxProfile )
d . Set ( "linux_profile" , & linuxProfile )
agentPoolProfiles := flattenAzureRmContainerServiceAgentPoolProfiles ( resp . Properties . AgentPoolProfiles )
d . Set ( "agent_pool_profile" , & agentPoolProfiles )
servicePrincipal := flattenAzureRmContainerServiceServicePrincipalProfile ( resp . Properties . ServicePrincipalProfile )
if servicePrincipal != nil {
d . Set ( "service_principal" , servicePrincipal )
}
diagnosticProfile := flattenAzureRmContainerServiceDiagnosticsProfile ( resp . Properties . DiagnosticsProfile )
if diagnosticProfile != nil {
d . Set ( "diagnostics_profile" , diagnosticProfile )
}
flattenAndSetTags ( d , resp . Tags )
return nil
}
func resourceArmContainerServiceDelete ( d * schema . ResourceData , meta interface { } ) error {
client := meta . ( * ArmClient )
containerServiceClient := client . containerServicesClient
id , err := parseAzureResourceID ( d . Id ( ) )
if err != nil {
return err
}
resGroup := id . ResourceGroup
name := id . Path [ "containerServices" ]
resp , err := containerServiceClient . Delete ( resGroup , name , make ( chan struct { } ) )
if err != nil {
return err
}
if resp . StatusCode != http . StatusOK {
return fmt . Errorf ( "Error issuing Azure ARM delete request of Container Service '%s': %s" , name , err )
}
return nil
}
2017-02-15 21:03:40 +01:00
func flattenAzureRmContainerServiceMasterProfile ( profile containerservice . MasterProfile ) * schema . Set {
masterProfiles := & schema . Set {
2017-02-13 17:33:50 +01:00
F : resourceAzureRMContainerServiceMasterProfileHash ,
}
masterProfile := make ( map [ string ] interface { } , 2 )
masterProfile [ "count" ] = int ( * profile . Count )
masterProfile [ "dns_prefix" ] = * profile . DNSPrefix
masterProfiles . Add ( masterProfile )
return masterProfiles
}
2017-02-15 21:03:40 +01:00
func flattenAzureRmContainerServiceLinuxProfile ( profile containerservice . LinuxProfile ) * schema . Set {
profiles := & schema . Set {
2017-02-13 17:33:50 +01:00
F : resourceAzureRMContainerServiceLinuxProfilesHash ,
}
values := map [ string ] interface { } { }
2017-02-15 21:03:40 +01:00
sshKeys := & schema . Set {
2017-02-13 17:33:50 +01:00
F : resourceAzureRMContainerServiceLinuxProfilesSSHKeysHash ,
}
for _ , ssh := range * profile . SSH . PublicKeys {
keys := map [ string ] interface { } { }
keys [ "key_data" ] = * ssh . KeyData
sshKeys . Add ( keys )
}
values [ "admin_username" ] = * profile . AdminUsername
values [ "ssh_key" ] = & sshKeys
profiles . Add ( values )
return profiles
}
2017-02-15 21:03:40 +01:00
func flattenAzureRmContainerServiceAgentPoolProfiles ( profiles * [ ] containerservice . AgentPoolProfile ) * schema . Set {
agentPoolProfiles := & schema . Set {
2017-02-13 17:33:50 +01:00
F : resourceAzureRMContainerServiceAgentPoolProfilesHash ,
}
for _ , profile := range * profiles {
agentPoolProfile := map [ string ] interface { } { }
agentPoolProfile [ "count" ] = int ( * profile . Count )
agentPoolProfile [ "dns_prefix" ] = * profile . DNSPrefix
agentPoolProfile [ "fqdn" ] = * profile . Fqdn
agentPoolProfile [ "name" ] = * profile . Name
agentPoolProfile [ "vm_size" ] = string ( profile . VMSize )
agentPoolProfiles . Add ( agentPoolProfile )
}
return agentPoolProfiles
}
func flattenAzureRmContainerServiceServicePrincipalProfile ( profile * containerservice . ServicePrincipalProfile ) * schema . Set {
if profile == nil {
return nil
}
servicePrincipalProfiles := & schema . Set {
F : resourceAzureRMContainerServiceServicePrincipalProfileHash ,
}
values := map [ string ] interface { } { }
values [ "client_id" ] = * profile . ClientID
if profile . Secret != nil {
values [ "client_secret" ] = * profile . Secret
}
servicePrincipalProfiles . Add ( values )
return servicePrincipalProfiles
}
func flattenAzureRmContainerServiceDiagnosticsProfile ( profile * containerservice . DiagnosticsProfile ) * schema . Set {
diagnosticProfiles := & schema . Set {
F : resourceAzureRMContainerServiceDiagnosticProfilesHash ,
}
values := map [ string ] interface { } { }
values [ "enabled" ] = * profile . VMDiagnostics . Enabled
if profile . VMDiagnostics . StorageURI != nil {
values [ "storage_uri" ] = * profile . VMDiagnostics . StorageURI
}
diagnosticProfiles . Add ( values )
return diagnosticProfiles
}
func expandAzureRmContainerServiceDiagnostics ( d * schema . ResourceData ) containerservice . DiagnosticsProfile {
configs := d . Get ( "diagnostics_profile" ) . ( * schema . Set ) . List ( )
profile := containerservice . DiagnosticsProfile { }
data := configs [ 0 ] . ( map [ string ] interface { } )
enabled := data [ "enabled" ] . ( bool )
profile = containerservice . DiagnosticsProfile {
VMDiagnostics : & containerservice . VMDiagnostics {
Enabled : & enabled ,
} ,
}
return profile
}
func expandAzureRmContainerServiceLinuxProfile ( d * schema . ResourceData ) containerservice . LinuxProfile {
profiles := d . Get ( "linux_profile" ) . ( * schema . Set ) . List ( )
config := profiles [ 0 ] . ( map [ string ] interface { } )
adminUsername := config [ "admin_username" ] . ( string )
linuxKeys := config [ "ssh_key" ] . ( * schema . Set ) . List ( )
sshPublicKeys := [ ] containerservice . SSHPublicKey { }
key := linuxKeys [ 0 ] . ( map [ string ] interface { } )
keyData := key [ "key_data" ] . ( string )
sshPublicKey := containerservice . SSHPublicKey {
KeyData : & keyData ,
}
sshPublicKeys = append ( sshPublicKeys , sshPublicKey )
profile := containerservice . LinuxProfile {
AdminUsername : & adminUsername ,
SSH : & containerservice . SSHConfiguration {
PublicKeys : & sshPublicKeys ,
} ,
}
return profile
}
func expandAzureRmContainerServiceMasterProfile ( d * schema . ResourceData ) containerservice . MasterProfile {
configs := d . Get ( "master_profile" ) . ( * schema . Set ) . List ( )
config := configs [ 0 ] . ( map [ string ] interface { } )
count := int32 ( config [ "count" ] . ( int ) )
dnsPrefix := config [ "dns_prefix" ] . ( string )
profile := containerservice . MasterProfile {
Count : & count ,
DNSPrefix : & dnsPrefix ,
}
return profile
}
func expandAzureRmContainerServiceServicePrincipal ( d * schema . ResourceData ) * containerservice . ServicePrincipalProfile {
value , exists := d . GetOk ( "service_principal" )
if ! exists {
return nil
}
configs := value . ( * schema . Set ) . List ( )
config := configs [ 0 ] . ( map [ string ] interface { } )
clientId := config [ "client_id" ] . ( string )
clientSecret := config [ "client_secret" ] . ( string )
principal := containerservice . ServicePrincipalProfile {
ClientID : & clientId ,
Secret : & clientSecret ,
}
return & principal
}
func expandAzureRmContainerServiceAgentProfiles ( d * schema . ResourceData ) [ ] containerservice . AgentPoolProfile {
configs := d . Get ( "agent_pool_profile" ) . ( * schema . Set ) . List ( )
config := configs [ 0 ] . ( map [ string ] interface { } )
profiles := make ( [ ] containerservice . AgentPoolProfile , 0 , len ( configs ) )
name := config [ "name" ] . ( string )
count := int32 ( config [ "count" ] . ( int ) )
dnsPrefix := config [ "dns_prefix" ] . ( string )
vmSize := config [ "vm_size" ] . ( string )
profile := containerservice . AgentPoolProfile {
Name : & name ,
Count : & count ,
VMSize : containerservice . VMSizeTypes ( vmSize ) ,
DNSPrefix : & dnsPrefix ,
}
profiles = append ( profiles , profile )
return profiles
}
func containerServiceStateRefreshFunc ( client * ArmClient , resourceGroupName string , containerServiceName string ) resource . StateRefreshFunc {
return func ( ) ( interface { } , string , error ) {
res , err := client . containerServicesClient . Get ( resourceGroupName , containerServiceName )
if err != nil {
return nil , "" , fmt . Errorf ( "Error issuing read request in containerServiceStateRefreshFunc to Azure ARM for Container Service '%s' (RG: '%s'): %s" , containerServiceName , resourceGroupName , err )
}
return res , * res . Properties . ProvisioningState , nil
}
}
func resourceAzureRMContainerServiceMasterProfileHash ( v interface { } ) int {
var buf bytes . Buffer
m := v . ( map [ string ] interface { } )
count := m [ "count" ] . ( int )
dnsPrefix := m [ "dns_prefix" ] . ( string )
buf . WriteString ( fmt . Sprintf ( "%d-" , count ) )
buf . WriteString ( fmt . Sprintf ( "%s-" , dnsPrefix ) )
return hashcode . String ( buf . String ( ) )
}
func resourceAzureRMContainerServiceLinuxProfilesHash ( v interface { } ) int {
var buf bytes . Buffer
m := v . ( map [ string ] interface { } )
adminUsername := m [ "admin_username" ] . ( string )
buf . WriteString ( fmt . Sprintf ( "%s-" , adminUsername ) )
return hashcode . String ( buf . String ( ) )
}
func resourceAzureRMContainerServiceLinuxProfilesSSHKeysHash ( v interface { } ) int {
var buf bytes . Buffer
m := v . ( map [ string ] interface { } )
keyData := m [ "key_data" ] . ( string )
buf . WriteString ( fmt . Sprintf ( "%s-" , keyData ) )
return hashcode . String ( buf . String ( ) )
}
func resourceAzureRMContainerServiceAgentPoolProfilesHash ( v interface { } ) int {
var buf bytes . Buffer
m := v . ( map [ string ] interface { } )
count := m [ "count" ] . ( int )
dnsPrefix := m [ "dns_prefix" ] . ( string )
name := m [ "name" ] . ( string )
vm_size := m [ "vm_size" ] . ( string )
buf . WriteString ( fmt . Sprintf ( "%d-" , count ) )
buf . WriteString ( fmt . Sprintf ( "%s-" , dnsPrefix ) )
buf . WriteString ( fmt . Sprintf ( "%s-" , name ) )
buf . WriteString ( fmt . Sprintf ( "%s-" , vm_size ) )
return hashcode . String ( buf . String ( ) )
}
func resourceAzureRMContainerServiceServicePrincipalProfileHash ( v interface { } ) int {
var buf bytes . Buffer
m := v . ( map [ string ] interface { } )
clientId := m [ "client_id" ] . ( string )
buf . WriteString ( fmt . Sprintf ( "%s-" , clientId ) )
return hashcode . String ( buf . String ( ) )
}
func resourceAzureRMContainerServiceDiagnosticProfilesHash ( v interface { } ) int {
var buf bytes . Buffer
m := v . ( map [ string ] interface { } )
enabled := m [ "enabled" ] . ( bool )
buf . WriteString ( fmt . Sprintf ( "%t" , enabled ) )
return hashcode . String ( buf . String ( ) )
}
func validateArmContainerServiceOrchestrationPlatform ( v interface { } , k string ) ( ws [ ] string , errors [ ] error ) {
value := v . ( string )
capacities := map [ string ] bool {
"DCOS" : true ,
"Kubernetes" : true ,
"Swarm" : true ,
}
if ! capacities [ value ] {
errors = append ( errors , fmt . Errorf ( "Container Service: Orchestration Platgorm can only be DCOS / Kubernetes / Swarm" ) )
}
return
}
func validateArmContainerServiceMasterProfileCount ( v interface { } , k string ) ( ws [ ] string , errors [ ] error ) {
value := v . ( int )
capacities := map [ int ] bool {
1 : true ,
3 : true ,
5 : true ,
}
if ! capacities [ value ] {
errors = append ( errors , fmt . Errorf ( "The number of master nodes must be 1, 3 or 5." ) )
}
return
}
func validateArmContainerServiceAgentPoolProfileCount ( v interface { } , k string ) ( ws [ ] string , errors [ ] error ) {
value := v . ( int )
if value > 100 || 0 >= value {
errors = append ( errors , fmt . Errorf ( "The Count for an Agent Pool Profile can only be between 1 and 100." ) )
}
return
}