Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions v3/ecl/network/v2/ports/requests.go
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,7 @@ type CreateOpts struct {
MACAddress string `json:"mac_address,omitempty"`
Name string `json:"name,omitempty"`
NetworkID string `json:"network_id"`
SecurityGroups *[]string `json:"security_groups,omitempty"`
SegmentationID int `json:"segmentation_id,omitempty"`
SegmentationType string `json:"segmentation_type,omitempty"`
Tags map[string]string `json:"tags,omitempty"`
Expand Down Expand Up @@ -118,6 +119,7 @@ type UpdateOpts struct {
DeviceOwner *string `json:"device_owner,omitempty"`
FixedIPs interface{} `json:"fixed_ips,omitempty"`
Name *string `json:"name,omitempty"`
SecurityGroups *[]string `json:"security_groups,omitempty"`
SegmentationID *int `json:"segmentation_id,omitempty"`
SegmentationType *string `json:"segmentation_type,omitempty"`
Tags *map[string]string `json:"tags,omitempty"`
Expand Down
3 changes: 3 additions & 0 deletions v3/ecl/network/v2/ports/results.go
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,9 @@ type Port struct {
// Network that this port is associated with.
NetworkID string `json:"network_id"`

// SecurityGroups is the IDs of security groups applied to the port.
SecurityGroups []string `json:"security_groups"`

// SegmentationID is the segmenation ID used for this port (i.e. for vlan type it is vlan tag)
SegmentationID int `json:"segmentation_id"`

Expand Down
80 changes: 80 additions & 0 deletions v3/ecl/network/v2/ports/testing/fixtures.go
Original file line number Diff line number Diff line change
Expand Up @@ -288,3 +288,83 @@ var Port2 = ports.Port{
}

var ExpectedPortSlice = []ports.Port{Port1, Port2}

const CreateWithSecurityGroupsRequest = `
{
"port":
{
"admin_state_up": true,
"fixed_ips": [
{
"ip_address": "192.168.2.40",
"subnet_id": "ab49eb24-667f-4a4e-9421-b4d915bff416"
}
],
"name": "port_with_sg",
"network_id": "8f36b88a-443f-4d97-9751-34d34af9e782",
"security_groups": ["85cc3048-abc3-43cc-89b3-377341426ac5"],
"tenant_id": "dcb2d589c0c646d0bad45c0cf9f90cf1"
}
}`

const CreateWithSecurityGroupsResponse = `
{
"port": {
"admin_state_up": true,
"allowed_address_pairs": [],
"description": "",
"device_id": "",
"device_owner": "",
"fixed_ips": [
{
"ip_address": "192.168.2.40",
"subnet_id": "ab49eb24-667f-4a4e-9421-b4d915bff416"
}
],
"id": "port-with-sg-id",
"mac_address": "fa:16:3e:b0:ca:f2",
"name": "port_with_sg",
"network_id": "8f36b88a-443f-4d97-9751-34d34af9e782",
"security_groups": ["85cc3048-abc3-43cc-89b3-377341426ac5"],
"segmentation_id": null,
"segmentation_type": null,
"status": "PENDING_CREATE",
"tags": {},
"tenant_id": "dcb2d589c0c646d0bad45c0cf9f90cf1"
}
}`

const UpdateWithSecurityGroupsRequest = `
{
"port": {
"name": "port_with_updated_sg",
"security_groups": ["85cc3048-abc3-43cc-89b3-377341426ac5", "c0e1482e-2e3c-497e-8964-e4f818071700"]
}
}`

const UpdateWithSecurityGroupsResponse = `
{
"port": {
"admin_state_up": true,
"allowed_address_pairs": [],
"description": "",
"device_id": "",
"device_owner": "",
"fixed_ips": [
{
"ip_address": "192.168.2.40",
"subnet_id": "ab49eb24-667f-4a4e-9421-b4d915bff416"
}
],
"id": "port-with-sg-id",
"mac_address": "fa:16:3e:b0:ca:f2",
"name": "port_with_updated_sg",
"network_id": "8f36b88a-443f-4d97-9751-34d34af9e782",
"security_groups": ["85cc3048-abc3-43cc-89b3-377341426ac5", "c0e1482e-2e3c-497e-8964-e4f818071700"],
"segmentation_id": null,
"segmentation_type": null,
"status": "PENDING_CREATE",
"tags": {},
"tenant_id": "dcb2d589c0c646d0bad45c0cf9f90cf1"
}
}`
68 changes: 68 additions & 0 deletions v3/ecl/network/v2/ports/testing/request_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -219,3 +219,71 @@ func TestDeletePort(t *testing.T) {
res := ports.Delete(fake.ServiceClient(), "ac57c5c9-aaf4-4ffc-b8b8-f1ef84656730")
th.AssertNoErr(t, res.Err)
}

func TestCreatePortWithSecurityGroups(t *testing.T) {
th.SetupHTTP()
defer th.TeardownHTTP()

th.Mux.HandleFunc("/v2.0/ports", func(w http.ResponseWriter, r *http.Request) {
th.TestMethod(t, r, "POST")
th.TestHeader(t, r, "X-Auth-Token", fake.TokenID)
th.TestHeader(t, r, "Content-Type", "application/json")
th.TestHeader(t, r, "Accept", "application/json")
th.TestJSONRequest(t, r, CreateWithSecurityGroupsRequest)
w.Header().Add("Content-Type", "application/json")
w.WriteHeader(http.StatusCreated)

fmt.Fprintf(w, CreateWithSecurityGroupsResponse)
})

asu := true
securityGroups := []string{"85cc3048-abc3-43cc-89b3-377341426ac5"}

options := &ports.CreateOpts{
AdminStateUp: &asu,
FixedIPs: []ports.IP{{
IPAddress: "192.168.2.40",
SubnetID: "ab49eb24-667f-4a4e-9421-b4d915bff416",
}},
Name: "port_with_sg",
NetworkID: "8f36b88a-443f-4d97-9751-34d34af9e782",
SecurityGroups: &securityGroups,
TenantID: "dcb2d589c0c646d0bad45c0cf9f90cf1",
}
p, err := ports.Create(fake.ServiceClient(), options).Extract()
th.AssertNoErr(t, err)

th.CheckEquals(t, "port_with_sg", p.Name)
th.CheckDeepEquals(t, securityGroups, p.SecurityGroups)
}

func TestUpdatePortWithSecurityGroups(t *testing.T) {
th.SetupHTTP()
defer th.TeardownHTTP()

th.Mux.HandleFunc("/v2.0/ports/port-with-sg-id", func(w http.ResponseWriter, r *http.Request) {
th.TestMethod(t, r, "PUT")
th.TestHeader(t, r, "X-Auth-Token", fake.TokenID)
th.TestHeader(t, r, "Content-Type", "application/json")
th.TestHeader(t, r, "Accept", "application/json")
th.TestJSONRequest(t, r, UpdateWithSecurityGroupsRequest)

w.Header().Add("Content-Type", "application/json")
w.WriteHeader(http.StatusOK)

fmt.Fprintf(w, UpdateWithSecurityGroupsResponse)
})

name := "port_with_updated_sg"
securityGroups := []string{"85cc3048-abc3-43cc-89b3-377341426ac5", "c0e1482e-2e3c-497e-8964-e4f818071700"}

options := ports.UpdateOpts{
Name: &name,
SecurityGroups: &securityGroups,
}
p, err := ports.Update(fake.ServiceClient(), "port-with-sg-id", options).Extract()
th.AssertNoErr(t, err)

th.CheckEquals(t, name, p.Name)
th.CheckDeepEquals(t, securityGroups, p.SecurityGroups)
}
51 changes: 51 additions & 0 deletions v3/ecl/network/v2/security_group_rules/doc.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
/*
Package security_group_rules contains functionality for working with ECL Security Group Rule resources.

Security Group Rules define specific ingress and egress traffic rules for Security Groups.

Example to List Security Group Rules

listOpts := security_group_rules.ListOpts{
SecurityGroupID: "security-group-id",
}

allPages, err := security_group_rules.List(networkClient, listOpts).AllPages()
if err != nil {
panic(err)
}

allRules, err := security_group_rules.ExtractSecurityGroupRules(allPages)
if err != nil {
panic(err)
}

for _, rule := range allRules {
fmt.Printf("%+v\n", rule)
}

Example to Create a Security Group Rule

createOpts := security_group_rules.CreateOpts{
Direction: "ingress",
SecurityGroupID: "security-group-id",
Ethertype: "IPv4",
Protocol: "tcp",
PortRangeMin: &[]int{22}[0],
PortRangeMax: &[]int{22}[0],
RemoteIPPrefix: &[]string{"0.0.0.0/0"}[0],
}

rule, err := security_group_rules.Create(networkClient, createOpts).Extract()
if err != nil {
panic(err)
}

Example to Delete a Security Group Rule

ruleID := "rule-id"
err := security_group_rules.Delete(networkClient, ruleID).ExtractErr()
if err != nil {
panic(err)
}
*/
package security_group_rules
100 changes: 100 additions & 0 deletions v3/ecl/network/v2/security_group_rules/requests.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
package security_group_rules

import (
"github.com/nttcom/eclcloud/v3"
"github.com/nttcom/eclcloud/v3/pagination"
)

// ListOptsBuilder allows extensions to add additional parameters to the
// List request.
type ListOptsBuilder interface {
ToSecurityGroupRuleListQuery() (string, error)
}

// ListOpts allows the filtering and sorting of paginated collections through
// the API. Filtering is achieved by passing in struct field values that map to
// the security group rule attributes you want to see returned.
type ListOpts struct {
Description string `q:"description"`
Direction string `q:"direction"`
Ethertype string `q:"ethertype"`
ID string `q:"id"`
PortRangeMax int `q:"port_range_max"`
PortRangeMin int `q:"port_range_min"`
Protocol string `q:"protocol"`
RemoteGroupID string `q:"remote_group_id"`
RemoteIPPrefix string `q:"remote_ip_prefix"`
SecurityGroupID string `q:"security_group_id"`
TenantID string `q:"tenant_id"`
}

// ToSecurityGroupRuleListQuery formats a ListOpts into a query string.
func (opts ListOpts) ToSecurityGroupRuleListQuery() (string, error) {
q, err := eclcloud.BuildQueryString(opts)
return q.String(), err
}

// List returns a Pager which allows you to iterate over a collection of
// security group rules. It accepts a ListOpts struct, which allows you to filter
// and sort the returned collection for greater efficiency.
func List(c *eclcloud.ServiceClient, opts ListOptsBuilder) pagination.Pager {
url := listURL(c)
if opts != nil {
query, err := opts.ToSecurityGroupRuleListQuery()
if err != nil {
return pagination.Pager{Err: err}
}
url += query
}
return pagination.NewPager(c, url, func(r pagination.PageResult) pagination.Page {
return SecurityGroupRulePage{pagination.LinkedPageBase{PageResult: r}}
})
}

// Get retrieves a specific security group rule based on its unique ID.
func Get(c *eclcloud.ServiceClient, id string) (r GetResult) {
_, r.Err = c.Get(getURL(c, id), &r.Body, nil)
return
}

// CreateOptsBuilder allows extensions to add additional parameters to the
// Create request.
type CreateOptsBuilder interface {
ToSecurityGroupRuleCreateMap() (map[string]interface{}, error)
}

// CreateOpts represents options used to create a security group rule.
type CreateOpts struct {
Description string `json:"description,omitempty"`
Direction string `json:"direction" required:"true"`
Ethertype string `json:"ethertype,omitempty"`
PortRangeMax *int `json:"port_range_max,omitempty"`
PortRangeMin *int `json:"port_range_min,omitempty"`
Protocol string `json:"protocol,omitempty"`
RemoteGroupID *string `json:"remote_group_id,omitempty"`
RemoteIPPrefix *string `json:"remote_ip_prefix,omitempty"`
SecurityGroupID string `json:"security_group_id" required:"true"`
TenantID string `json:"tenant_id,omitempty"`
}

// ToSecurityGroupRuleCreateMap builds a request body from CreateOpts.
func (opts CreateOpts) ToSecurityGroupRuleCreateMap() (map[string]interface{}, error) {
return eclcloud.BuildRequestBody(opts, "security_group_rule")
}

// Create accepts a CreateOpts struct and creates a new security group rule.
func Create(c *eclcloud.ServiceClient, opts CreateOptsBuilder) (r CreateResult) {
b, err := opts.ToSecurityGroupRuleCreateMap()
if err != nil {
r.Err = err
return
}
_, r.Err = c.Post(createURL(c), b, &r.Body, nil)
return
}

// Delete accepts a unique ID and deletes the security group rule associated with it.
func Delete(c *eclcloud.ServiceClient, id string) (r DeleteResult) {
_, r.Err = c.Delete(deleteURL(c, id), nil)
return
}
Loading
Loading