Merge pull request #49785 from FengyunPan/fix-getPortByIP

Automatic merge from submit-queue (batch tested with PRs 47724, 49984, 49785, 49803, 49618)

Fix conflict about getPortByIp

**What this PR does / why we need it**:
Currently getPortByIp() get port of instance only based on IP.
If there are two instances in diffent network and the CIDR of
their subnet are same, getPortByIp() will be conflict.
My PR gets port based on IP and Name of instance.

**Which issue this PR fixes** *(optional, in `fixes #<issue number>(, fixes #<issue_number>, ...)` format, will close that issue when PR gets merged)*: fixes #
Fix #43909

**Special notes for your reviewer**:

**Release note**:
```release-note
NONE
```

Kubernetes-commit: a7ce691311f5462cf71d79a1f9431605198803af
This commit is contained in:
Kubernetes Publisher 2017-08-11 18:47:19 -07:00
commit 9f92bb772b
7 changed files with 240 additions and 9 deletions

18
Godeps/Godeps.json generated
View File

@ -172,31 +172,31 @@
},
{
"ImportPath": "github.com/gophercloud/gophercloud",
"Rev": "ed590d9afe113c6107cd60717b196155e6579e78"
"Rev": "c0406a133c4a74a838baf0ddff3c2fab21155fba"
},
{
"ImportPath": "github.com/gophercloud/gophercloud/openstack",
"Rev": "ed590d9afe113c6107cd60717b196155e6579e78"
"Rev": "c0406a133c4a74a838baf0ddff3c2fab21155fba"
},
{
"ImportPath": "github.com/gophercloud/gophercloud/openstack/identity/v2/tenants",
"Rev": "ed590d9afe113c6107cd60717b196155e6579e78"
"Rev": "c0406a133c4a74a838baf0ddff3c2fab21155fba"
},
{
"ImportPath": "github.com/gophercloud/gophercloud/openstack/identity/v2/tokens",
"Rev": "ed590d9afe113c6107cd60717b196155e6579e78"
"Rev": "c0406a133c4a74a838baf0ddff3c2fab21155fba"
},
{
"ImportPath": "github.com/gophercloud/gophercloud/openstack/identity/v3/tokens",
"Rev": "ed590d9afe113c6107cd60717b196155e6579e78"
"Rev": "c0406a133c4a74a838baf0ddff3c2fab21155fba"
},
{
"ImportPath": "github.com/gophercloud/gophercloud/openstack/utils",
"Rev": "ed590d9afe113c6107cd60717b196155e6579e78"
"Rev": "c0406a133c4a74a838baf0ddff3c2fab21155fba"
},
{
"ImportPath": "github.com/gophercloud/gophercloud/pagination",
"Rev": "ed590d9afe113c6107cd60717b196155e6579e78"
"Rev": "c0406a133c4a74a838baf0ddff3c2fab21155fba"
},
{
"ImportPath": "github.com/hashicorp/golang-lru",
@ -418,6 +418,10 @@
"ImportPath": "k8s.io/api/policy/v1beta1",
"Rev": "f30e293246921de7f4ee46bb65b8762b2f890fc4"
},
{
"ImportPath": "k8s.io/api/rbac/v1",
"Rev": "f30e293246921de7f4ee46bb65b8762b2f890fc4"
},
{
"ImportPath": "k8s.io/api/rbac/v1alpha1",
"Rev": "f30e293246921de7f4ee46bb65b8762b2f890fc4"

View File

@ -27,3 +27,81 @@ func List(client *gophercloud.ServiceClient, opts *ListOpts) pagination.Pager {
return TenantPage{pagination.LinkedPageBase{PageResult: r}}
})
}
// CreateOpts represents the options needed when creating new tenant.
type CreateOpts struct {
// Name is the name of the tenant.
Name string `json:"name" required:"true"`
// Description is the description of the tenant.
Description string `json:"description,omitempty"`
// Enabled sets the tenant status to enabled or disabled.
Enabled *bool `json:"enabled,omitempty"`
}
// CreateOptsBuilder describes struct types that can be accepted by the Create call.
type CreateOptsBuilder interface {
ToTenantCreateMap() (map[string]interface{}, error)
}
// ToTenantCreateMap assembles a request body based on the contents of a CreateOpts.
func (opts CreateOpts) ToTenantCreateMap() (map[string]interface{}, error) {
return gophercloud.BuildRequestBody(opts, "tenant")
}
// Create is the operation responsible for creating new tenant.
func Create(client *gophercloud.ServiceClient, opts CreateOptsBuilder) (r CreateResult) {
b, err := opts.ToTenantCreateMap()
if err != nil {
r.Err = err
return
}
_, r.Err = client.Post(createURL(client), b, &r.Body, &gophercloud.RequestOpts{
OkCodes: []int{200, 201},
})
return
}
// Get requests details on a single tenant by ID.
func Get(client *gophercloud.ServiceClient, id string) (r GetResult) {
_, r.Err = client.Get(getURL(client, id), &r.Body, nil)
return
}
// UpdateOptsBuilder allows extensions to add additional attributes to the Update request.
type UpdateOptsBuilder interface {
ToTenantUpdateMap() (map[string]interface{}, error)
}
// UpdateOpts specifies the base attributes that may be updated on an existing server.
type UpdateOpts struct {
// Name is the name of the tenant.
Name string `json:"name,omitempty"`
// Description is the description of the tenant.
Description string `json:"description,omitempty"`
// Enabled sets the tenant status to enabled or disabled.
Enabled *bool `json:"enabled,omitempty"`
}
// ToTenantUpdateMap formats an UpdateOpts structure into a request body.
func (opts UpdateOpts) ToTenantUpdateMap() (map[string]interface{}, error) {
return gophercloud.BuildRequestBody(opts, "tenant")
}
// Update is the operation responsible for updating exist tenants by their TenantID.
func Update(client *gophercloud.ServiceClient, id string, opts UpdateOptsBuilder) (r UpdateResult) {
b, err := opts.ToTenantUpdateMap()
if err != nil {
r.Err = err
return
}
_, r.Err = client.Put(updateURL(client, id), &b, &r.Body, &gophercloud.RequestOpts{
OkCodes: []int{200},
})
return
}
// Delete is the operation responsible for permanently deleting an API tenant.
func Delete(client *gophercloud.ServiceClient, id string) (r DeleteResult) {
_, r.Err = client.Delete(deleteURL(client, id), nil)
return
}

View File

@ -51,3 +51,36 @@ func ExtractTenants(r pagination.Page) ([]Tenant, error) {
err := (r.(TenantPage)).ExtractInto(&s)
return s.Tenants, err
}
type tenantResult struct {
gophercloud.Result
}
// Extract interprets any tenantResults as a tenant.
func (r tenantResult) Extract() (*Tenant, error) {
var s struct {
Tenant *Tenant `json:"tenant"`
}
err := r.ExtractInto(&s)
return s.Tenant, err
}
// GetResult temporarily contains the response from the Get call.
type GetResult struct {
tenantResult
}
// CreateResult temporarily contains the reponse from the Create call.
type CreateResult struct {
tenantResult
}
// DeleteResult temporarily contains the response from the Delete call.
type DeleteResult struct {
gophercloud.ErrResult
}
// UpdateResult temporarily contains the response from the Update call.
type UpdateResult struct {
tenantResult
}

View File

@ -5,3 +5,19 @@ import "github.com/gophercloud/gophercloud"
func listURL(client *gophercloud.ServiceClient) string {
return client.ServiceURL("tenants")
}
func getURL(client *gophercloud.ServiceClient, tenantID string) string {
return client.ServiceURL("tenants", tenantID)
}
func createURL(client *gophercloud.ServiceClient) string {
return client.ServiceURL("tenants")
}
func deleteURL(client *gophercloud.ServiceClient, tenantID string) string {
return client.ServiceURL("tenants", tenantID)
}
func updateURL(client *gophercloud.ServiceClient, tenantID string) string {
return client.ServiceURL("tenants", tenantID)
}

View File

@ -182,7 +182,7 @@ func Get(c *gophercloud.ServiceClient, token string) (r GetResult) {
func Validate(c *gophercloud.ServiceClient, token string) (bool, error) {
resp, err := c.Request("HEAD", tokenURL(c), &gophercloud.RequestOpts{
MoreHeaders: subjectTokenHeaders(c, token),
OkCodes: []int{200, 204, 400, 401, 403, 404},
OkCodes: []int{200, 204, 404},
})
if err != nil {
return false, err

View File

@ -41,6 +41,32 @@ type ServiceCatalog struct {
Entries []CatalogEntry `json:"catalog"`
}
// Domain provides information about the domain to which this token grants access.
type Domain struct {
ID string `json:"id"`
Name string `json:"name"`
}
// User represents a user resource that exists on the API.
type User struct {
Domain Domain `json:"domain"`
ID string `json:"id"`
Name string `json:"name"`
}
// Role provides information about roles to which User is authorized.
type Role struct {
ID string `json:"id"`
Name string `json:"name"`
}
// Project provides information about project to which User is authorized.
type Project struct {
Domain Domain `json:"domain"`
ID string `json:"id"`
Name string `json:"name"`
}
// commonResult is the deferred result of a Create or a Get call.
type commonResult struct {
gophercloud.Result
@ -67,12 +93,39 @@ func (r commonResult) ExtractToken() (*Token, error) {
}
// ExtractServiceCatalog returns the ServiceCatalog that was generated along with the user's Token.
func (r CreateResult) ExtractServiceCatalog() (*ServiceCatalog, error) {
func (r commonResult) ExtractServiceCatalog() (*ServiceCatalog, error) {
var s ServiceCatalog
err := r.ExtractInto(&s)
return &s, err
}
// ExtractUser returns the User that is the owner of the Token.
func (r commonResult) ExtractUser() (*User, error) {
var s struct {
User *User `json:"user"`
}
err := r.ExtractInto(&s)
return s.User, err
}
// ExtractRoles returns Roles to which User is authorized.
func (r commonResult) ExtractRoles() ([]Role, error) {
var s struct {
Roles []Role `json:"roles"`
}
err := r.ExtractInto(&s)
return s.Roles, err
}
// ExtractProject returns Project to which User is authorized.
func (r commonResult) ExtractProject() (*Project, error) {
var s struct {
Project *Project `json:"project"`
}
err := r.ExtractInto(&s)
return s.Project, err
}
// CreateResult defers the interpretation of a created token.
// Use ExtractToken() to interpret it as a Token, or ExtractServiceCatalog() to interpret it as a service catalog.
type CreateResult struct {

View File

@ -78,6 +78,53 @@ func (r Result) extractIntoPtr(to interface{}, label string) error {
return err
}
toValue := reflect.ValueOf(to)
if toValue.Kind() == reflect.Ptr {
toValue = toValue.Elem()
}
switch toValue.Kind() {
case reflect.Slice:
typeOfV := toValue.Type().Elem()
if typeOfV.Kind() == reflect.Struct {
if typeOfV.NumField() > 0 && typeOfV.Field(0).Anonymous {
newSlice := reflect.MakeSlice(reflect.SliceOf(typeOfV), 0, 0)
newType := reflect.New(typeOfV).Elem()
for _, v := range m[label].([]interface{}) {
b, err := json.Marshal(v)
if err != nil {
return err
}
for i := 0; i < newType.NumField(); i++ {
s := newType.Field(i).Addr().Interface()
err = json.NewDecoder(bytes.NewReader(b)).Decode(s)
if err != nil {
return err
}
}
newSlice = reflect.Append(newSlice, newType)
}
toValue.Set(newSlice)
}
}
case reflect.Struct:
typeOfV := toValue.Type()
if typeOfV.NumField() > 0 && typeOfV.Field(0).Anonymous {
for i := 0; i < toValue.NumField(); i++ {
toField := toValue.Field(i)
if toField.Kind() == reflect.Struct {
s := toField.Addr().Interface()
err = json.NewDecoder(bytes.NewReader(b)).Decode(s)
if err != nil {
return err
}
}
}
}
}
err = json.Unmarshal(b, &to)
return err
}