github.com/koding/terraform@v0.6.4-0.20170608090606-5d7e0339779d/builtin/providers/openstack/resource_openstack_networking_secgroup_rule_v2.go (about)

     1  package openstack
     2  
     3  import (
     4  	"fmt"
     5  	"log"
     6  	"strconv"
     7  	"strings"
     8  	"time"
     9  
    10  	"github.com/hashicorp/terraform/helper/resource"
    11  	"github.com/hashicorp/terraform/helper/schema"
    12  
    13  	"github.com/gophercloud/gophercloud"
    14  	"github.com/gophercloud/gophercloud/openstack/networking/v2/extensions/security/rules"
    15  )
    16  
    17  func resourceNetworkingSecGroupRuleV2() *schema.Resource {
    18  	return &schema.Resource{
    19  		Create: resourceNetworkingSecGroupRuleV2Create,
    20  		Read:   resourceNetworkingSecGroupRuleV2Read,
    21  		Delete: resourceNetworkingSecGroupRuleV2Delete,
    22  		Importer: &schema.ResourceImporter{
    23  			State: schema.ImportStatePassthrough,
    24  		},
    25  
    26  		Timeouts: &schema.ResourceTimeout{
    27  			Delete: schema.DefaultTimeout(10 * time.Minute),
    28  		},
    29  
    30  		Schema: map[string]*schema.Schema{
    31  			"region": &schema.Schema{
    32  				Type:        schema.TypeString,
    33  				Required:    true,
    34  				ForceNew:    true,
    35  				DefaultFunc: schema.EnvDefaultFunc("OS_REGION_NAME", ""),
    36  			},
    37  			"direction": &schema.Schema{
    38  				Type:     schema.TypeString,
    39  				Required: true,
    40  				ForceNew: true,
    41  			},
    42  			"ethertype": &schema.Schema{
    43  				Type:     schema.TypeString,
    44  				Required: true,
    45  				ForceNew: true,
    46  			},
    47  			"port_range_min": &schema.Schema{
    48  				Type:     schema.TypeInt,
    49  				Optional: true,
    50  				ForceNew: true,
    51  				Computed: true,
    52  			},
    53  			"port_range_max": &schema.Schema{
    54  				Type:     schema.TypeInt,
    55  				Optional: true,
    56  				ForceNew: true,
    57  				Computed: true,
    58  			},
    59  			"protocol": &schema.Schema{
    60  				Type:     schema.TypeString,
    61  				Optional: true,
    62  				ForceNew: true,
    63  				Computed: true,
    64  			},
    65  			"remote_group_id": &schema.Schema{
    66  				Type:     schema.TypeString,
    67  				Optional: true,
    68  				ForceNew: true,
    69  				Computed: true,
    70  			},
    71  			"remote_ip_prefix": &schema.Schema{
    72  				Type:     schema.TypeString,
    73  				Optional: true,
    74  				ForceNew: true,
    75  				Computed: true,
    76  				StateFunc: func(v interface{}) string {
    77  					return strings.ToLower(v.(string))
    78  				},
    79  			},
    80  			"security_group_id": &schema.Schema{
    81  				Type:     schema.TypeString,
    82  				Required: true,
    83  				ForceNew: true,
    84  			},
    85  			"tenant_id": &schema.Schema{
    86  				Type:     schema.TypeString,
    87  				Optional: true,
    88  				ForceNew: true,
    89  				Computed: true,
    90  			},
    91  		},
    92  	}
    93  }
    94  
    95  func resourceNetworkingSecGroupRuleV2Create(d *schema.ResourceData, meta interface{}) error {
    96  
    97  	config := meta.(*Config)
    98  	networkingClient, err := config.networkingV2Client(GetRegion(d))
    99  	if err != nil {
   100  		return fmt.Errorf("Error creating OpenStack networking client: %s", err)
   101  	}
   102  
   103  	portRangeMin := d.Get("port_range_min").(int)
   104  	portRangeMax := d.Get("port_range_max").(int)
   105  	protocol := d.Get("protocol").(string)
   106  
   107  	if protocol == "" {
   108  		if portRangeMin != 0 || portRangeMax != 0 {
   109  			return fmt.Errorf("A protocol must be specified when using port_range_min and port_range_max")
   110  		}
   111  	}
   112  
   113  	opts := rules.CreateOpts{
   114  		SecGroupID:     d.Get("security_group_id").(string),
   115  		PortRangeMin:   d.Get("port_range_min").(int),
   116  		PortRangeMax:   d.Get("port_range_max").(int),
   117  		RemoteGroupID:  d.Get("remote_group_id").(string),
   118  		RemoteIPPrefix: d.Get("remote_ip_prefix").(string),
   119  		TenantID:       d.Get("tenant_id").(string),
   120  	}
   121  
   122  	if v, ok := d.GetOk("direction"); ok {
   123  		direction := resourceNetworkingSecGroupRuleV2DetermineDirection(v.(string))
   124  		opts.Direction = direction
   125  	}
   126  
   127  	if v, ok := d.GetOk("ethertype"); ok {
   128  		ethertype := resourceNetworkingSecGroupRuleV2DetermineEtherType(v.(string))
   129  		opts.EtherType = ethertype
   130  	}
   131  
   132  	if v, ok := d.GetOk("protocol"); ok {
   133  		protocol := resourceNetworkingSecGroupRuleV2DetermineProtocol(v.(string))
   134  		opts.Protocol = protocol
   135  	}
   136  
   137  	log.Printf("[DEBUG] Create OpenStack Neutron security group: %#v", opts)
   138  
   139  	security_group_rule, err := rules.Create(networkingClient, opts).Extract()
   140  	if err != nil {
   141  		return err
   142  	}
   143  
   144  	log.Printf("[DEBUG] OpenStack Neutron Security Group Rule created: %#v", security_group_rule)
   145  
   146  	d.SetId(security_group_rule.ID)
   147  
   148  	return resourceNetworkingSecGroupRuleV2Read(d, meta)
   149  }
   150  
   151  func resourceNetworkingSecGroupRuleV2Read(d *schema.ResourceData, meta interface{}) error {
   152  	log.Printf("[DEBUG] Retrieve information about security group rule: %s", d.Id())
   153  
   154  	config := meta.(*Config)
   155  	networkingClient, err := config.networkingV2Client(GetRegion(d))
   156  	if err != nil {
   157  		return fmt.Errorf("Error creating OpenStack networking client: %s", err)
   158  	}
   159  
   160  	security_group_rule, err := rules.Get(networkingClient, d.Id()).Extract()
   161  
   162  	if err != nil {
   163  		return CheckDeleted(d, err, "OpenStack Security Group Rule")
   164  	}
   165  
   166  	d.Set("direction", security_group_rule.Direction)
   167  	d.Set("ethertype", security_group_rule.EtherType)
   168  	d.Set("protocol", security_group_rule.Protocol)
   169  	d.Set("port_range_min", security_group_rule.PortRangeMin)
   170  	d.Set("port_range_max", security_group_rule.PortRangeMax)
   171  	d.Set("remote_group_id", security_group_rule.RemoteGroupID)
   172  	d.Set("remote_ip_prefix", security_group_rule.RemoteIPPrefix)
   173  	d.Set("security_group_id", security_group_rule.SecGroupID)
   174  	d.Set("tenant_id", security_group_rule.TenantID)
   175  	d.Set("region", GetRegion(d))
   176  
   177  	return nil
   178  }
   179  
   180  func resourceNetworkingSecGroupRuleV2Delete(d *schema.ResourceData, meta interface{}) error {
   181  	log.Printf("[DEBUG] Destroy security group rule: %s", d.Id())
   182  
   183  	config := meta.(*Config)
   184  	networkingClient, err := config.networkingV2Client(GetRegion(d))
   185  	if err != nil {
   186  		return fmt.Errorf("Error creating OpenStack networking client: %s", err)
   187  	}
   188  
   189  	stateConf := &resource.StateChangeConf{
   190  		Pending:    []string{"ACTIVE"},
   191  		Target:     []string{"DELETED"},
   192  		Refresh:    waitForSecGroupRuleDelete(networkingClient, d.Id()),
   193  		Timeout:    d.Timeout(schema.TimeoutDelete),
   194  		Delay:      5 * time.Second,
   195  		MinTimeout: 3 * time.Second,
   196  	}
   197  
   198  	_, err = stateConf.WaitForState()
   199  	if err != nil {
   200  		return fmt.Errorf("Error deleting OpenStack Neutron Security Group Rule: %s", err)
   201  	}
   202  
   203  	d.SetId("")
   204  	return err
   205  }
   206  
   207  func resourceNetworkingSecGroupRuleV2DetermineDirection(v string) rules.RuleDirection {
   208  	var direction rules.RuleDirection
   209  	switch v {
   210  	case "ingress":
   211  		direction = rules.DirIngress
   212  	case "egress":
   213  		direction = rules.DirEgress
   214  	}
   215  
   216  	return direction
   217  }
   218  
   219  func resourceNetworkingSecGroupRuleV2DetermineEtherType(v string) rules.RuleEtherType {
   220  	var etherType rules.RuleEtherType
   221  	switch v {
   222  	case "IPv4":
   223  		etherType = rules.EtherType4
   224  	case "IPv6":
   225  		etherType = rules.EtherType6
   226  	}
   227  
   228  	return etherType
   229  }
   230  
   231  func resourceNetworkingSecGroupRuleV2DetermineProtocol(v string) rules.RuleProtocol {
   232  	var protocol rules.RuleProtocol
   233  
   234  	// Check and see if the requested protocol matched a list of known protocol names.
   235  	switch v {
   236  	case "tcp":
   237  		protocol = rules.ProtocolTCP
   238  	case "udp":
   239  		protocol = rules.ProtocolUDP
   240  	case "icmp":
   241  		protocol = rules.ProtocolICMP
   242  	case "ah":
   243  		protocol = rules.ProtocolAH
   244  	case "dccp":
   245  		protocol = rules.ProtocolDCCP
   246  	case "egp":
   247  		protocol = rules.ProtocolEGP
   248  	case "esp":
   249  		protocol = rules.ProtocolESP
   250  	case "gre":
   251  		protocol = rules.ProtocolGRE
   252  	case "igmp":
   253  		protocol = rules.ProtocolIGMP
   254  	case "ipv6-encap":
   255  		protocol = rules.ProtocolIPv6Encap
   256  	case "ipv6-frag":
   257  		protocol = rules.ProtocolIPv6Frag
   258  	case "ipv6-icmp":
   259  		protocol = rules.ProtocolIPv6ICMP
   260  	case "ipv6-nonxt":
   261  		protocol = rules.ProtocolIPv6NoNxt
   262  	case "ipv6-opts":
   263  		protocol = rules.ProtocolIPv6Opts
   264  	case "ipv6-route":
   265  		protocol = rules.ProtocolIPv6Route
   266  	case "ospf":
   267  		protocol = rules.ProtocolOSPF
   268  	case "pgm":
   269  		protocol = rules.ProtocolPGM
   270  	case "rsvp":
   271  		protocol = rules.ProtocolRSVP
   272  	case "sctp":
   273  		protocol = rules.ProtocolSCTP
   274  	case "udplite":
   275  		protocol = rules.ProtocolUDPLite
   276  	case "vrrp":
   277  		protocol = rules.ProtocolVRRP
   278  	}
   279  
   280  	// If the protocol wasn't matched above, see if it's an integer.
   281  	if protocol == "" {
   282  		_, err := strconv.Atoi(v)
   283  		if err == nil {
   284  			protocol = rules.RuleProtocol(v)
   285  		}
   286  	}
   287  
   288  	return protocol
   289  }
   290  
   291  func waitForSecGroupRuleDelete(networkingClient *gophercloud.ServiceClient, secGroupRuleId string) resource.StateRefreshFunc {
   292  	return func() (interface{}, string, error) {
   293  		log.Printf("[DEBUG] Attempting to delete OpenStack Security Group Rule %s.\n", secGroupRuleId)
   294  
   295  		r, err := rules.Get(networkingClient, secGroupRuleId).Extract()
   296  		if err != nil {
   297  			if _, ok := err.(gophercloud.ErrDefault404); ok {
   298  				log.Printf("[DEBUG] Successfully deleted OpenStack Neutron Security Group Rule %s", secGroupRuleId)
   299  				return r, "DELETED", nil
   300  			}
   301  			return r, "ACTIVE", err
   302  		}
   303  
   304  		err = rules.Delete(networkingClient, secGroupRuleId).ExtractErr()
   305  		if err != nil {
   306  			if _, ok := err.(gophercloud.ErrDefault404); ok {
   307  				log.Printf("[DEBUG] Successfully deleted OpenStack Neutron Security Group Rule %s", secGroupRuleId)
   308  				return r, "DELETED", nil
   309  			}
   310  			return r, "ACTIVE", err
   311  		}
   312  
   313  		log.Printf("[DEBUG] OpenStack Neutron Security Group Rule %s still active.\n", secGroupRuleId)
   314  		return r, "ACTIVE", nil
   315  	}
   316  }