Merge pull request #5391 from jtopjian/openstack-secgroup-icmp-zero

provider/openstack: Allow ICMP Security Groups with values of zero
This commit is contained in:
Joe Topjian 2016-03-01 12:48:12 -07:00
commit 986eefcfe2
11 changed files with 236 additions and 92 deletions

144
Godeps/Godeps.json generated
View File

@ -839,183 +839,183 @@
}, },
{ {
"ImportPath": "github.com/rackspace/gophercloud", "ImportPath": "github.com/rackspace/gophercloud",
"Comment": "v1.0.0-803-g6769c3b", "Comment": "v1.0.0-831-gf3d0534",
"Rev": "6769c3b3e54a5cf1b0bdb10ea5b25f5cff0a3134" "Rev": "f3d053460f7c37970af6733bf370a3256e3648fb"
}, },
{ {
"ImportPath": "github.com/rackspace/gophercloud/openstack", "ImportPath": "github.com/rackspace/gophercloud/openstack",
"Comment": "v1.0.0-803-g6769c3b", "Comment": "v1.0.0-831-gf3d0534",
"Rev": "6769c3b3e54a5cf1b0bdb10ea5b25f5cff0a3134" "Rev": "f3d053460f7c37970af6733bf370a3256e3648fb"
}, },
{ {
"ImportPath": "github.com/rackspace/gophercloud/openstack/blockstorage/v1/volumes", "ImportPath": "github.com/rackspace/gophercloud/openstack/blockstorage/v1/volumes",
"Comment": "v1.0.0-803-g6769c3b", "Comment": "v1.0.0-831-gf3d0534",
"Rev": "6769c3b3e54a5cf1b0bdb10ea5b25f5cff0a3134" "Rev": "f3d053460f7c37970af6733bf370a3256e3648fb"
}, },
{ {
"ImportPath": "github.com/rackspace/gophercloud/openstack/compute/v2/extensions/bootfromvolume", "ImportPath": "github.com/rackspace/gophercloud/openstack/compute/v2/extensions/bootfromvolume",
"Comment": "v1.0.0-803-g6769c3b", "Comment": "v1.0.0-831-gf3d0534",
"Rev": "6769c3b3e54a5cf1b0bdb10ea5b25f5cff0a3134" "Rev": "f3d053460f7c37970af6733bf370a3256e3648fb"
}, },
{ {
"ImportPath": "github.com/rackspace/gophercloud/openstack/compute/v2/extensions/floatingip", "ImportPath": "github.com/rackspace/gophercloud/openstack/compute/v2/extensions/floatingip",
"Comment": "v1.0.0-803-g6769c3b", "Comment": "v1.0.0-831-gf3d0534",
"Rev": "6769c3b3e54a5cf1b0bdb10ea5b25f5cff0a3134" "Rev": "f3d053460f7c37970af6733bf370a3256e3648fb"
}, },
{ {
"ImportPath": "github.com/rackspace/gophercloud/openstack/compute/v2/extensions/keypairs", "ImportPath": "github.com/rackspace/gophercloud/openstack/compute/v2/extensions/keypairs",
"Comment": "v1.0.0-803-g6769c3b", "Comment": "v1.0.0-831-gf3d0534",
"Rev": "6769c3b3e54a5cf1b0bdb10ea5b25f5cff0a3134" "Rev": "f3d053460f7c37970af6733bf370a3256e3648fb"
}, },
{ {
"ImportPath": "github.com/rackspace/gophercloud/openstack/compute/v2/extensions/schedulerhints", "ImportPath": "github.com/rackspace/gophercloud/openstack/compute/v2/extensions/schedulerhints",
"Comment": "v1.0.0-803-g6769c3b", "Comment": "v1.0.0-831-gf3d0534",
"Rev": "6769c3b3e54a5cf1b0bdb10ea5b25f5cff0a3134" "Rev": "f3d053460f7c37970af6733bf370a3256e3648fb"
}, },
{ {
"ImportPath": "github.com/rackspace/gophercloud/openstack/compute/v2/extensions/secgroups", "ImportPath": "github.com/rackspace/gophercloud/openstack/compute/v2/extensions/secgroups",
"Comment": "v1.0.0-803-g6769c3b", "Comment": "v1.0.0-831-gf3d0534",
"Rev": "6769c3b3e54a5cf1b0bdb10ea5b25f5cff0a3134" "Rev": "f3d053460f7c37970af6733bf370a3256e3648fb"
}, },
{ {
"ImportPath": "github.com/rackspace/gophercloud/openstack/compute/v2/extensions/servergroups", "ImportPath": "github.com/rackspace/gophercloud/openstack/compute/v2/extensions/servergroups",
"Comment": "v1.0.0-803-g6769c3b", "Comment": "v1.0.0-831-gf3d0534",
"Rev": "6769c3b3e54a5cf1b0bdb10ea5b25f5cff0a3134" "Rev": "f3d053460f7c37970af6733bf370a3256e3648fb"
}, },
{ {
"ImportPath": "github.com/rackspace/gophercloud/openstack/compute/v2/extensions/tenantnetworks", "ImportPath": "github.com/rackspace/gophercloud/openstack/compute/v2/extensions/tenantnetworks",
"Comment": "v1.0.0-803-g6769c3b", "Comment": "v1.0.0-831-gf3d0534",
"Rev": "6769c3b3e54a5cf1b0bdb10ea5b25f5cff0a3134" "Rev": "f3d053460f7c37970af6733bf370a3256e3648fb"
}, },
{ {
"ImportPath": "github.com/rackspace/gophercloud/openstack/compute/v2/extensions/volumeattach", "ImportPath": "github.com/rackspace/gophercloud/openstack/compute/v2/extensions/volumeattach",
"Comment": "v1.0.0-803-g6769c3b", "Comment": "v1.0.0-831-gf3d0534",
"Rev": "6769c3b3e54a5cf1b0bdb10ea5b25f5cff0a3134" "Rev": "f3d053460f7c37970af6733bf370a3256e3648fb"
}, },
{ {
"ImportPath": "github.com/rackspace/gophercloud/openstack/compute/v2/flavors", "ImportPath": "github.com/rackspace/gophercloud/openstack/compute/v2/flavors",
"Comment": "v1.0.0-803-g6769c3b", "Comment": "v1.0.0-831-gf3d0534",
"Rev": "6769c3b3e54a5cf1b0bdb10ea5b25f5cff0a3134" "Rev": "f3d053460f7c37970af6733bf370a3256e3648fb"
}, },
{ {
"ImportPath": "github.com/rackspace/gophercloud/openstack/compute/v2/images", "ImportPath": "github.com/rackspace/gophercloud/openstack/compute/v2/images",
"Comment": "v1.0.0-803-g6769c3b", "Comment": "v1.0.0-831-gf3d0534",
"Rev": "6769c3b3e54a5cf1b0bdb10ea5b25f5cff0a3134" "Rev": "f3d053460f7c37970af6733bf370a3256e3648fb"
}, },
{ {
"ImportPath": "github.com/rackspace/gophercloud/openstack/compute/v2/servers", "ImportPath": "github.com/rackspace/gophercloud/openstack/compute/v2/servers",
"Comment": "v1.0.0-803-g6769c3b", "Comment": "v1.0.0-831-gf3d0534",
"Rev": "6769c3b3e54a5cf1b0bdb10ea5b25f5cff0a3134" "Rev": "f3d053460f7c37970af6733bf370a3256e3648fb"
}, },
{ {
"ImportPath": "github.com/rackspace/gophercloud/openstack/identity/v2/tenants", "ImportPath": "github.com/rackspace/gophercloud/openstack/identity/v2/tenants",
"Comment": "v1.0.0-803-g6769c3b", "Comment": "v1.0.0-831-gf3d0534",
"Rev": "6769c3b3e54a5cf1b0bdb10ea5b25f5cff0a3134" "Rev": "f3d053460f7c37970af6733bf370a3256e3648fb"
}, },
{ {
"ImportPath": "github.com/rackspace/gophercloud/openstack/identity/v2/tokens", "ImportPath": "github.com/rackspace/gophercloud/openstack/identity/v2/tokens",
"Comment": "v1.0.0-803-g6769c3b", "Comment": "v1.0.0-831-gf3d0534",
"Rev": "6769c3b3e54a5cf1b0bdb10ea5b25f5cff0a3134" "Rev": "f3d053460f7c37970af6733bf370a3256e3648fb"
}, },
{ {
"ImportPath": "github.com/rackspace/gophercloud/openstack/identity/v3/tokens", "ImportPath": "github.com/rackspace/gophercloud/openstack/identity/v3/tokens",
"Comment": "v1.0.0-803-g6769c3b", "Comment": "v1.0.0-831-gf3d0534",
"Rev": "6769c3b3e54a5cf1b0bdb10ea5b25f5cff0a3134" "Rev": "f3d053460f7c37970af6733bf370a3256e3648fb"
}, },
{ {
"ImportPath": "github.com/rackspace/gophercloud/openstack/networking/v2/extensions/fwaas/firewalls", "ImportPath": "github.com/rackspace/gophercloud/openstack/networking/v2/extensions/fwaas/firewalls",
"Comment": "v1.0.0-803-g6769c3b", "Comment": "v1.0.0-831-gf3d0534",
"Rev": "6769c3b3e54a5cf1b0bdb10ea5b25f5cff0a3134" "Rev": "f3d053460f7c37970af6733bf370a3256e3648fb"
}, },
{ {
"ImportPath": "github.com/rackspace/gophercloud/openstack/networking/v2/extensions/fwaas/policies", "ImportPath": "github.com/rackspace/gophercloud/openstack/networking/v2/extensions/fwaas/policies",
"Comment": "v1.0.0-803-g6769c3b", "Comment": "v1.0.0-831-gf3d0534",
"Rev": "6769c3b3e54a5cf1b0bdb10ea5b25f5cff0a3134" "Rev": "f3d053460f7c37970af6733bf370a3256e3648fb"
}, },
{ {
"ImportPath": "github.com/rackspace/gophercloud/openstack/networking/v2/extensions/fwaas/rules", "ImportPath": "github.com/rackspace/gophercloud/openstack/networking/v2/extensions/fwaas/rules",
"Comment": "v1.0.0-803-g6769c3b", "Comment": "v1.0.0-831-gf3d0534",
"Rev": "6769c3b3e54a5cf1b0bdb10ea5b25f5cff0a3134" "Rev": "f3d053460f7c37970af6733bf370a3256e3648fb"
}, },
{ {
"ImportPath": "github.com/rackspace/gophercloud/openstack/networking/v2/extensions/layer3/floatingips", "ImportPath": "github.com/rackspace/gophercloud/openstack/networking/v2/extensions/layer3/floatingips",
"Comment": "v1.0.0-803-g6769c3b", "Comment": "v1.0.0-831-gf3d0534",
"Rev": "6769c3b3e54a5cf1b0bdb10ea5b25f5cff0a3134" "Rev": "f3d053460f7c37970af6733bf370a3256e3648fb"
}, },
{ {
"ImportPath": "github.com/rackspace/gophercloud/openstack/networking/v2/extensions/layer3/routers", "ImportPath": "github.com/rackspace/gophercloud/openstack/networking/v2/extensions/layer3/routers",
"Comment": "v1.0.0-803-g6769c3b", "Comment": "v1.0.0-831-gf3d0534",
"Rev": "6769c3b3e54a5cf1b0bdb10ea5b25f5cff0a3134" "Rev": "f3d053460f7c37970af6733bf370a3256e3648fb"
}, },
{ {
"ImportPath": "github.com/rackspace/gophercloud/openstack/networking/v2/extensions/lbaas/members", "ImportPath": "github.com/rackspace/gophercloud/openstack/networking/v2/extensions/lbaas/members",
"Comment": "v1.0.0-803-g6769c3b", "Comment": "v1.0.0-831-gf3d0534",
"Rev": "6769c3b3e54a5cf1b0bdb10ea5b25f5cff0a3134" "Rev": "f3d053460f7c37970af6733bf370a3256e3648fb"
}, },
{ {
"ImportPath": "github.com/rackspace/gophercloud/openstack/networking/v2/extensions/lbaas/monitors", "ImportPath": "github.com/rackspace/gophercloud/openstack/networking/v2/extensions/lbaas/monitors",
"Comment": "v1.0.0-803-g6769c3b", "Comment": "v1.0.0-831-gf3d0534",
"Rev": "6769c3b3e54a5cf1b0bdb10ea5b25f5cff0a3134" "Rev": "f3d053460f7c37970af6733bf370a3256e3648fb"
}, },
{ {
"ImportPath": "github.com/rackspace/gophercloud/openstack/networking/v2/extensions/lbaas/pools", "ImportPath": "github.com/rackspace/gophercloud/openstack/networking/v2/extensions/lbaas/pools",
"Comment": "v1.0.0-803-g6769c3b", "Comment": "v1.0.0-831-gf3d0534",
"Rev": "6769c3b3e54a5cf1b0bdb10ea5b25f5cff0a3134" "Rev": "f3d053460f7c37970af6733bf370a3256e3648fb"
}, },
{ {
"ImportPath": "github.com/rackspace/gophercloud/openstack/networking/v2/extensions/lbaas/vips", "ImportPath": "github.com/rackspace/gophercloud/openstack/networking/v2/extensions/lbaas/vips",
"Comment": "v1.0.0-803-g6769c3b", "Comment": "v1.0.0-831-gf3d0534",
"Rev": "6769c3b3e54a5cf1b0bdb10ea5b25f5cff0a3134" "Rev": "f3d053460f7c37970af6733bf370a3256e3648fb"
}, },
{ {
"ImportPath": "github.com/rackspace/gophercloud/openstack/networking/v2/networks", "ImportPath": "github.com/rackspace/gophercloud/openstack/networking/v2/networks",
"Comment": "v1.0.0-803-g6769c3b", "Comment": "v1.0.0-831-gf3d0534",
"Rev": "6769c3b3e54a5cf1b0bdb10ea5b25f5cff0a3134" "Rev": "f3d053460f7c37970af6733bf370a3256e3648fb"
}, },
{ {
"ImportPath": "github.com/rackspace/gophercloud/openstack/networking/v2/ports", "ImportPath": "github.com/rackspace/gophercloud/openstack/networking/v2/ports",
"Comment": "v1.0.0-803-g6769c3b", "Comment": "v1.0.0-831-gf3d0534",
"Rev": "6769c3b3e54a5cf1b0bdb10ea5b25f5cff0a3134" "Rev": "f3d053460f7c37970af6733bf370a3256e3648fb"
}, },
{ {
"ImportPath": "github.com/rackspace/gophercloud/openstack/networking/v2/subnets", "ImportPath": "github.com/rackspace/gophercloud/openstack/networking/v2/subnets",
"Comment": "v1.0.0-803-g6769c3b", "Comment": "v1.0.0-831-gf3d0534",
"Rev": "6769c3b3e54a5cf1b0bdb10ea5b25f5cff0a3134" "Rev": "f3d053460f7c37970af6733bf370a3256e3648fb"
}, },
{ {
"ImportPath": "github.com/rackspace/gophercloud/openstack/objectstorage/v1/accounts", "ImportPath": "github.com/rackspace/gophercloud/openstack/objectstorage/v1/accounts",
"Comment": "v1.0.0-803-g6769c3b", "Comment": "v1.0.0-831-gf3d0534",
"Rev": "6769c3b3e54a5cf1b0bdb10ea5b25f5cff0a3134" "Rev": "f3d053460f7c37970af6733bf370a3256e3648fb"
}, },
{ {
"ImportPath": "github.com/rackspace/gophercloud/openstack/objectstorage/v1/containers", "ImportPath": "github.com/rackspace/gophercloud/openstack/objectstorage/v1/containers",
"Comment": "v1.0.0-803-g6769c3b", "Comment": "v1.0.0-831-gf3d0534",
"Rev": "6769c3b3e54a5cf1b0bdb10ea5b25f5cff0a3134" "Rev": "f3d053460f7c37970af6733bf370a3256e3648fb"
}, },
{ {
"ImportPath": "github.com/rackspace/gophercloud/openstack/objectstorage/v1/objects", "ImportPath": "github.com/rackspace/gophercloud/openstack/objectstorage/v1/objects",
"Comment": "v1.0.0-803-g6769c3b", "Comment": "v1.0.0-831-gf3d0534",
"Rev": "6769c3b3e54a5cf1b0bdb10ea5b25f5cff0a3134" "Rev": "f3d053460f7c37970af6733bf370a3256e3648fb"
}, },
{ {
"ImportPath": "github.com/rackspace/gophercloud/openstack/utils", "ImportPath": "github.com/rackspace/gophercloud/openstack/utils",
"Comment": "v1.0.0-803-g6769c3b", "Comment": "v1.0.0-831-gf3d0534",
"Rev": "6769c3b3e54a5cf1b0bdb10ea5b25f5cff0a3134" "Rev": "f3d053460f7c37970af6733bf370a3256e3648fb"
}, },
{ {
"ImportPath": "github.com/rackspace/gophercloud/pagination", "ImportPath": "github.com/rackspace/gophercloud/pagination",
"Comment": "v1.0.0-803-g6769c3b", "Comment": "v1.0.0-831-gf3d0534",
"Rev": "6769c3b3e54a5cf1b0bdb10ea5b25f5cff0a3134" "Rev": "f3d053460f7c37970af6733bf370a3256e3648fb"
}, },
{ {
"ImportPath": "github.com/rackspace/gophercloud/testhelper", "ImportPath": "github.com/rackspace/gophercloud/testhelper",
"Comment": "v1.0.0-803-g6769c3b", "Comment": "v1.0.0-831-gf3d0534",
"Rev": "6769c3b3e54a5cf1b0bdb10ea5b25f5cff0a3134" "Rev": "f3d053460f7c37970af6733bf370a3256e3648fb"
}, },
{ {
"ImportPath": "github.com/rackspace/gophercloud/testhelper/client", "ImportPath": "github.com/rackspace/gophercloud/testhelper/client",
"Comment": "v1.0.0-803-g6769c3b", "Comment": "v1.0.0-831-gf3d0534",
"Rev": "6769c3b3e54a5cf1b0bdb10ea5b25f5cff0a3134" "Rev": "f3d053460f7c37970af6733bf370a3256e3648fb"
}, },
{ {
"ImportPath": "github.com/satori/go.uuid", "ImportPath": "github.com/satori/go.uuid",

View File

@ -106,6 +106,24 @@ func TestAccComputeV2SecGroup_self(t *testing.T) {
}) })
} }
func TestAccComputeV2SecGroup_icmpZero(t *testing.T) {
var secgroup secgroups.SecurityGroup
resource.Test(t, resource.TestCase{
PreCheck: func() { testAccPreCheck(t) },
Providers: testAccProviders,
CheckDestroy: testAccCheckComputeV2SecGroupDestroy,
Steps: []resource.TestStep{
resource.TestStep{
Config: testAccComputeV2SecGroup_icmpZero,
Check: resource.ComposeTestCheckFunc(
testAccCheckComputeV2SecGroupExists(t, "openstack_compute_secgroup_v2.test_group_1", &secgroup),
),
},
},
})
}
func testAccCheckComputeV2SecGroupDestroy(s *terraform.State) error { func testAccCheckComputeV2SecGroupDestroy(s *terraform.State) error {
config := testAccProvider.Meta().(*Config) config := testAccProvider.Meta().(*Config)
computeClient, err := config.computeV2Client(OS_REGION_NAME) computeClient, err := config.computeV2Client(OS_REGION_NAME)
@ -304,3 +322,15 @@ var testAccComputeV2SecGroup_self = fmt.Sprintf(`
self = true self = true
} }
}`) }`)
var testAccComputeV2SecGroup_icmpZero = fmt.Sprintf(`
resource "openstack_compute_secgroup_v2" "test_group_1" {
name = "test_group_1"
description = "first test security group"
rule {
from_port = 0
to_port = 0
ip_protocol = "icmp"
cidr = "0.0.0.0/0"
}
}`)

View File

@ -1,16 +1,20 @@
language: go language: go
sudo: false
install: install:
- go get golang.org/x/crypto/ssh
- go get -v -tags 'fixtures acceptance' ./... - go get -v -tags 'fixtures acceptance' ./...
go: go:
- 1.2
- 1.3
- 1.4 - 1.4
- 1.5 - 1.5
script: script/cibuild - tip
after_success: env:
- go get golang.org/x/tools/cmd/cover - COVERALLS_TOKEN=2k7PTU3xa474Hymwgdj6XjqenNfGTNkO8
before_install:
- go get github.com/axw/gocov/gocov - go get github.com/axw/gocov/gocov
- go get github.com/mattn/goveralls - go get github.com/mattn/goveralls
- export PATH=$PATH:$HOME/gopath/bin/ - go get github.com/pierrre/gotestcover
- goveralls 2k7PTU3xa474Hymwgdj6XjqenNfGTNkO8 - if ! go get github.com/golang/tools/cmd/cover; then go get golang.org/x/tools/cmd/cover; fi
sudo: false script:
- $HOME/gopath/bin/gotestcover -v -tags=fixtures -coverprofile=cover.out ./...
after_success:
- $HOME/gopath/bin/goveralls -service=travis-ci -coverprofile=cover.out

View File

@ -11,7 +11,8 @@ As a contributor you will need to setup your workspace in a slightly different
way than just downloading it. Here are the basic installation instructions: way than just downloading it. Here are the basic installation instructions:
1. Configure your `$GOPATH` and run `go get` as described in the main 1. Configure your `$GOPATH` and run `go get` as described in the main
[README](/README.md#how-to-install). [README](/README.md#how-to-install) but add `-tags "fixtures acceptance"` to
get dependencies for unit and acceptance tests.
2. Move into the directory that houses your local repository: 2. Move into the directory that houses your local repository:
@ -158,25 +159,25 @@ deleted after the test suite finishes.
To run all tests: To run all tests:
```bash ```bash
go test ./... go test -tags fixtures ./...
``` ```
To run all tests with verbose output: To run all tests with verbose output:
```bash ```bash
go test -v ./... go test -v -tags fixtures ./...
``` ```
To run tests that match certain [build tags](): To run tests that match certain [build tags]():
```bash ```bash
go test -tags "foo bar" ./... go test -tags "fixtures foo bar" ./...
``` ```
To run tests for a particular sub-package: To run tests for a particular sub-package:
```bash ```bash
cd ./path/to/package && go test . cd ./path/to/package && go test -tags fixtures .
``` ```
## Basic style guide ## Basic style guide

View File

@ -1,5 +1,5 @@
# Gophercloud: an OpenStack SDK for Go # Gophercloud: an OpenStack SDK for Go
[![Build Status](https://travis-ci.org/rackspace/gophercloud.svg?branch=master)](https://travis-ci.org/rackspace/gophercloud) [![Build Status](https://travis-ci.org/rackspace/gophercloud.svg?branch=master)](https://travis-ci.org/rackspace/gophercloud) [![Coverage Status](https://coveralls.io/repos/rackspace/gophercloud/badge.png)](https://coveralls.io/r/rackspace/gophercloud)
Gophercloud is a flexible SDK that allows you to consume and work with OpenStack Gophercloud is a flexible SDK that allows you to consume and work with OpenStack
clouds in a simple and idiomatic way using golang. Many services are supported, clouds in a simple and idiomatic way using golang. Many services are supported,

View File

@ -216,6 +216,42 @@ func mockAddRuleResponse(t *testing.T) {
}) })
} }
func mockAddRuleResponseICMPZero(t *testing.T) {
th.Mux.HandleFunc("/os-security-group-rules", func(w http.ResponseWriter, r *http.Request) {
th.TestMethod(t, r, "POST")
th.TestHeader(t, r, "X-Auth-Token", fake.TokenID)
th.TestJSONRequest(t, r, `
{
"security_group_rule": {
"from_port": 0,
"ip_protocol": "ICMP",
"to_port": 0,
"parent_group_id": "{groupID}",
"cidr": "0.0.0.0/0"
}
} `)
w.Header().Add("Content-Type", "application/json")
w.WriteHeader(http.StatusOK)
fmt.Fprintf(w, `
{
"security_group_rule": {
"from_port": 0,
"group": {},
"ip_protocol": "ICMP",
"to_port": 0,
"parent_group_id": "{groupID}",
"ip_range": {
"cidr": "0.0.0.0/0"
},
"id": "{ruleID}"
}
}`)
})
}
func mockDeleteRuleResponse(t *testing.T, ruleID string) { func mockDeleteRuleResponse(t *testing.T, ruleID string) {
url := fmt.Sprintf("/os-security-group-rules/%s", ruleID) url := fmt.Sprintf("/os-security-group-rules/%s", ruleID)
th.Mux.HandleFunc(url, func(w http.ResponseWriter, r *http.Request) { th.Mux.HandleFunc(url, func(w http.ResponseWriter, r *http.Request) {

View File

@ -2,6 +2,7 @@ package secgroups
import ( import (
"errors" "errors"
"strings"
"github.com/rackspace/gophercloud" "github.com/rackspace/gophercloud"
"github.com/rackspace/gophercloud/pagination" "github.com/rackspace/gophercloud/pagination"
@ -181,10 +182,10 @@ func (opts CreateRuleOpts) ToRuleCreateMap() (map[string]interface{}, error) {
if opts.ParentGroupID == "" { if opts.ParentGroupID == "" {
return rule, errors.New("A ParentGroupID must be set") return rule, errors.New("A ParentGroupID must be set")
} }
if opts.FromPort == 0 { if opts.FromPort == 0 && strings.ToUpper(opts.IPProtocol) != "ICMP" {
return rule, errors.New("A FromPort must be set") return rule, errors.New("A FromPort must be set")
} }
if opts.ToPort == 0 { if opts.ToPort == 0 && strings.ToUpper(opts.IPProtocol) != "ICMP" {
return rule, errors.New("A ToPort must be set") return rule, errors.New("A ToPort must be set")
} }
if opts.IPProtocol == "" { if opts.IPProtocol == "" {

View File

@ -235,6 +235,12 @@ const SingleServerBody = `
} }
` `
const ServerPasswordBody = `
{
"password": "xlozO3wLCBRWAa2yDjCCVx8vwNPypxnypmRYDa/zErlQ+EzPe1S/Gz6nfmC52mOlOSCRuUOmG7kqqgejPof6M7bOezS387zjq4LSvvwp28zUknzy4YzfFGhnHAdai3TxUJ26pfQCYrq8UTzmKF2Bq8ioSEtVVzM0A96pDh8W2i7BOz6MdoiVyiev/I1K2LsuipfxSJR7Wdke4zNXJjHHP2RfYsVbZ/k9ANu+Nz4iIH8/7Cacud/pphH7EjrY6a4RZNrjQskrhKYed0YERpotyjYk1eDtRe72GrSiXteqCM4biaQ5w3ruS+AcX//PXk3uJ5kC7d67fPXaVz4WaQRYMg=="
}
`
var ( var (
// ServerHerp is a Server struct that should correspond to the first result in ServerListBody. // ServerHerp is a Server struct that should correspond to the first result in ServerListBody.
ServerHerp = Server{ ServerHerp = Server{
@ -399,8 +405,8 @@ func HandleServerDeletionSuccessfully(t *testing.T) {
}) })
} }
// HandleAdminPasswordChangeSuccessfully sets up the test server to respond to a server password // HandleServerForceDeletionSuccessfully sets up the test server to respond to a server force deletion
// change request. // request.
func HandleServerForceDeletionSuccessfully(t *testing.T) { func HandleServerForceDeletionSuccessfully(t *testing.T) {
th.Mux.HandleFunc("/servers/asdfasdfasdf/action", func(w http.ResponseWriter, r *http.Request) { th.Mux.HandleFunc("/servers/asdfasdfasdf/action", func(w http.ResponseWriter, r *http.Request) {
th.TestMethod(t, r, "POST") th.TestMethod(t, r, "POST")
@ -674,3 +680,13 @@ func HandleCreateServerImageSuccessfully(t *testing.T) {
}) })
} }
// HandlePasswordGetSuccessfully sets up the test server to respond to a password Get request.
func HandlePasswordGetSuccessfully(t *testing.T) {
th.Mux.HandleFunc("/servers/1234asdf/os-server-password", func(w http.ResponseWriter, r *http.Request) {
th.TestMethod(t, r, "GET")
th.TestHeader(t, r, "X-Auth-Token", client.TokenID)
th.TestHeader(t, r, "Accept", "application/json")
fmt.Fprintf(w, ServerPasswordBody)
})
}

View File

@ -861,3 +861,12 @@ func IDFromName(client *gophercloud.ServiceClient, name string) (string, error)
return "", fmt.Errorf("Found %d servers matching %s", serverCount, name) return "", fmt.Errorf("Found %d servers matching %s", serverCount, name)
} }
} }
// GetPassword makes a request against the nova API to get the encrypted administrative password.
func GetPassword(client *gophercloud.ServiceClient, serverId string) GetPasswordResult {
var res GetPasswordResult
_, res.Err = client.Request("GET", passwordURL(client, serverId), gophercloud.RequestOpts{
JSONResponse: &res.Body,
})
return res
}

View File

@ -1,10 +1,12 @@
package servers package servers
import ( import (
"reflect" "crypto/rsa"
"encoding/base64"
"fmt" "fmt"
"path"
"net/url" "net/url"
"path"
"reflect"
"github.com/mitchellh/mapstructure" "github.com/mitchellh/mapstructure"
"github.com/rackspace/gophercloud" "github.com/rackspace/gophercloud"
@ -82,6 +84,47 @@ type CreateImageResult struct {
gophercloud.Result gophercloud.Result
} }
// GetPasswordResult represent the result of a get os-server-password operation.
type GetPasswordResult struct {
gophercloud.Result
}
// ExtractPassword gets the encrypted password.
// If privateKey != nil the password is decrypted with the private key.
// If privateKey == nil the encrypted password is returned and can be decrypted with:
// echo '<pwd>' | base64 -D | openssl rsautl -decrypt -inkey <private_key>
func (r GetPasswordResult) ExtractPassword(privateKey *rsa.PrivateKey) (string, error) {
if r.Err != nil {
return "", r.Err
}
var response struct {
Password string `mapstructure:"password"`
}
err := mapstructure.Decode(r.Body, &response)
if err == nil && privateKey != nil && response.Password != "" {
return decryptPassword(response.Password, privateKey)
}
return response.Password, err
}
func decryptPassword(encryptedPassword string, privateKey *rsa.PrivateKey) (string, error) {
b64EncryptedPassword := make([]byte, base64.StdEncoding.DecodedLen(len(encryptedPassword)))
n, err := base64.StdEncoding.Decode(b64EncryptedPassword, []byte(encryptedPassword))
if err != nil {
return "", fmt.Errorf("Failed to base64 decode encrypted password: %s", err)
}
password, err := rsa.DecryptPKCS1v15(nil, privateKey, b64EncryptedPassword[0:n])
if err != nil {
return "", fmt.Errorf("Failed to decrypt password: %s", err)
}
return string(password), nil
}
// ExtractImageID gets the ID of the newly created server image from the header // ExtractImageID gets the ID of the newly created server image from the header
func (res CreateImageResult) ExtractImageID() (string, error) { func (res CreateImageResult) ExtractImageID() (string, error) {
if res.Err != nil { if res.Err != nil {

View File

@ -45,3 +45,7 @@ func listAddressesURL(client *gophercloud.ServiceClient, id string) string {
func listAddressesByNetworkURL(client *gophercloud.ServiceClient, id, network string) string { func listAddressesByNetworkURL(client *gophercloud.ServiceClient, id, network string) string {
return client.ServiceURL("servers", id, "ips", network) return client.ServiceURL("servers", id, "ips", network)
} }
func passwordURL(client *gophercloud.ServiceClient, id string) string {
return client.ServiceURL("servers", id, "os-server-password")
}