Skip to content

Commit

Permalink
Network v2: RBAC-Create (#755)
Browse files Browse the repository at this point in the history
* [wip] Network v2: RBAC-Create

* Added Acceptance Tests for RBAC.

* Addressed some nits.

* Addressed Review Comments

* Resolved build failure

* Addressed doc nits, RBAC to RBACPolicy naming convention, and restricting the acceptance test to only be run by admin user.
  • Loading branch information
PriyankaJ77 authored and jtopjian committed Feb 20, 2018
1 parent b922c6e commit 1858d1f
Show file tree
Hide file tree
Showing 10 changed files with 313 additions and 0 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
package rbacpolicies
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
package rbacpolicies

import (
"testing"

"github.com/gophercloud/gophercloud"
"github.com/gophercloud/gophercloud/openstack/networking/v2/extensions/rbacpolicies"
)

// CreateRBACPolicy will create a rbac-policy. An error will be returned if the
// rbac-policy could not be created.
func CreateRBACPolicy(t *testing.T, client *gophercloud.ServiceClient, tenantID, networkID string) (*rbacpolicies.RBACPolicy, error) {
createOpts := rbacpolicies.CreateOpts{
Action: rbacpolicies.ActionAccessShared,
ObjectType: "network",
TargetTenant: tenantID,
ObjectID: networkID,
}

t.Logf("Trying to create rbac_policy")

rbacPolicy, err := rbacpolicies.Create(client, createOpts).Extract()
if err != nil {
return rbacPolicy, err
}

t.Logf("Successfully created rbac_policy")
return rbacPolicy, nil
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
// +build acceptance

package rbacpolicies

import (
"os"
"testing"

"github.com/gophercloud/gophercloud/acceptance/clients"
projects "github.com/gophercloud/gophercloud/acceptance/openstack/identity/v3"
networking "github.com/gophercloud/gophercloud/acceptance/openstack/networking/v2"
"github.com/gophercloud/gophercloud/acceptance/tools"
)

func TestRBACPolicyCreate(t *testing.T) {
username := os.Getenv("OS_USERNAME")
if username != "admin" {
t.Skip("must be admin to run this test")
}

client, err := clients.NewNetworkV2Client()
if err != nil {
t.Fatalf("Unable to create a network client: %v", err)
}

// Create a network
network, err := networking.CreateNetwork(t, client)
if err != nil {
t.Fatalf("Unable to create network: %v", err)
}
defer networking.DeleteNetwork(t, client, network.ID)

tools.PrintResource(t, network)

identityClient, err := clients.NewIdentityV3Client()
if err != nil {
t.Fatalf("Unable to obtain an identity client: %v")
}

// Create a project/tenant
project, err := projects.CreateProject(t, identityClient, nil)
if err != nil {
t.Fatalf("Unable to create project: %v", err)
}
defer projects.DeleteProject(t, identityClient, project.ID)

tools.PrintResource(t, project)

// Create a rbac-policy
rbacPolicy, err := CreateRBACPolicy(t, client, project.ID, network.ID)
if err != nil {
t.Fatalf("Unable to create rbac-policy: %v", err)
}

tools.PrintResource(t, rbacPolicy)
}
31 changes: 31 additions & 0 deletions openstack/networking/v2/extensions/rbacpolicies/doc.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
/*
Package rbacpolicies contains functionality for working with Neutron RBAC Policies.
Role-Based Access Control (RBAC) policy framework enables both operators
and users to grant access to resources for specific projects.
Sharing an object with a specific project is accomplished by creating a
policy entry that permits the target project the access_as_shared action
on that object.
To make a network available as an external network for specific projects
rather than all projects, use the access_as_external action.
If a network is marked as external during creation, it now implicitly creates
a wildcard RBAC policy granting everyone access to preserve previous behavior
before this feature was added.
Example to Create a RBAC Policy
createOpts := rbacpolicies.CreateOpts{
Action: rbacpolicies.ActionAccessShared,
ObjectType: "network",
TargetTenant: "6e547a3bcfe44702889fdeff3c3520c3",
ObjectID: "240d22bf-bd17-4238-9758-25f72610ecdc"
}
rbacPolicy, err := rbacpolicies.Create(rbacClient, createOpts).Extract()
if err != nil {
panic(err)
}
*/
package rbacpolicies
51 changes: 51 additions & 0 deletions openstack/networking/v2/extensions/rbacpolicies/requests.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
package rbacpolicies

import (
"github.com/gophercloud/gophercloud"
)

// PolicyAction maps to Action for the RBAC policy.
// Which allows access_as_external or access_as_shared.
type PolicyAction string

const (
// ActionAccessExternal returns Action for the RBAC policy as access_as_external.
ActionAccessExternal PolicyAction = "access_as_external"

// ActionAccessShared returns Action for the RBAC policy as access_as_shared.
ActionAccessShared PolicyAction = "access_as_shared"
)

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

// CreateOpts represents options used to create a rbac-policy.
type CreateOpts struct {
Action PolicyAction `json:"action" required:"true"`
ObjectType string `json:"object_type" required:"true"`
TargetTenant string `json:"target_tenant" required:"true"`
ObjectID string `json:"object_id" required:"true"`
}

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

// Create accepts a CreateOpts struct and creates a new rbac-policy using the values
// provided.
//
// The tenant ID that is contained in the URI is the tenant that creates the
// rbac-policy.
func Create(c *gophercloud.ServiceClient, opts CreateOptsBuilder) (r CreateResult) {
b, err := opts.ToRBACPolicyCreateMap()
if err != nil {
r.Err = err
return
}
_, r.Err = c.Post(createURL(c), b, &r.Body, nil)
return
}
53 changes: 53 additions & 0 deletions openstack/networking/v2/extensions/rbacpolicies/results.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
package rbacpolicies

import (
"github.com/gophercloud/gophercloud"
)

type commonResult struct {
gophercloud.Result
}

// Extract is a function that accepts a result and extracts RBAC Policy resource.
func (r commonResult) Extract() (*RBACPolicy, error) {
var s RBACPolicy
err := r.ExtractInto(&s)
return &s, err
}

func (r commonResult) ExtractInto(v interface{}) error {
return r.Result.ExtractIntoStructPtr(v, "rbac_policy")
}

// CreateResult represents the result of a create operation. Call its Extract
// method to interpret it as a RBAC Policy.
type CreateResult struct {
commonResult
}

// RBACPolicy represents a RBAC policy.
type RBACPolicy struct {
// UUID of the RBAC policy.
ID string `json:"id"`

// Action for the RBAC policy which is access_as_external or access_as_shared.
Action PolicyAction `json:"action"`

// ObjectID is the ID of the object_type resource.
// An object_type of network returns a network ID and
// object_type of qos-policy returns a QoS ID.
ObjectID string `json:"object_id"`

// ObjectType is the type of the object that the RBAC policy affects.
// Types include qos-policy or network.
ObjectType string `json:"object_type"`

// TenantID is the ID of the project that owns the resource.
TenantID string `json:"tenant_id"`

// TargetTenant is the ID of the tenant to which the RBAC policy will be enforced.
TargetTenant string `json:"target_tenant"`

// ProjectID is the ID of the project.
ProjectID string `json:"project_id"`
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
// Package testing includes rbac unit tests
package testing
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
package testing

import (
"github.com/gophercloud/gophercloud/openstack/networking/v2/extensions/rbacpolicies"
)

// CreateRequest is the structure of request body to create rbac-policy.
const CreateRequest = `
{
"rbac_policy": {
"action": "access_as_shared",
"object_type": "network",
"target_tenant": "6e547a3bcfe44702889fdeff3c3520c3",
"object_id": "240d22bf-bd17-4238-9758-25f72610ecdc"
}
}`

// CreateResponse is the structure of response body of rbac-policy create.
const CreateResponse = `
{
"rbac_policy": {
"target_tenant": "6e547a3bcfe44702889fdeff3c3520c3",
"tenant_id": "3de27ce0a2a54cc6ae06dc62dd0ec832",
"object_type": "network",
"object_id": "240d22bf-bd17-4238-9758-25f72610ecdc",
"action": "access_as_shared",
"project_id": "3de27ce0a2a54cc6ae06dc62dd0ec832",
"id": "2cf7523a-93b5-4e69-9360-6c6bf986bb7c"
}
}`

var rbacPolicy1 = rbacpolicies.RBACPolicy{
ID: "2cf7523a-93b5-4e69-9360-6c6bf986bb7c",
Action: rbacpolicies.ActionAccessShared,
ObjectID: "240d22bf-bd17-4238-9758-25f72610ecdc",
ObjectType: "network",
TenantID: "3de27ce0a2a54cc6ae06dc62dd0ec832",
TargetTenant: "6e547a3bcfe44702889fdeff3c3520c3",
ProjectID: "3de27ce0a2a54cc6ae06dc62dd0ec832",
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
package testing

import (
"fmt"
"net/http"
"testing"

fake "github.com/gophercloud/gophercloud/openstack/networking/v2/common"
"github.com/gophercloud/gophercloud/openstack/networking/v2/extensions/rbacpolicies"
th "github.com/gophercloud/gophercloud/testhelper"
)

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

th.Mux.HandleFunc("/v2.0/rbac-policies", 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, CreateRequest)
w.Header().Add("Content-Type", "application/json")
w.WriteHeader(http.StatusCreated)

fmt.Fprintf(w, CreateResponse)
})

options := rbacpolicies.CreateOpts{
Action: rbacpolicies.ActionAccessShared,
ObjectType: "network",
TargetTenant: "6e547a3bcfe44702889fdeff3c3520c3",
ObjectID: "240d22bf-bd17-4238-9758-25f72610ecdc",
}
rbacResult, err := rbacpolicies.Create(fake.ServiceClient(), options).Extract()
th.AssertNoErr(t, err)

th.AssertDeepEquals(t, &rbacPolicy1, rbacResult)
}
11 changes: 11 additions & 0 deletions openstack/networking/v2/extensions/rbacpolicies/urls.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
package rbacpolicies

import "github.com/gophercloud/gophercloud"

func rootURL(c *gophercloud.ServiceClient) string {
return c.ServiceURL("rbac-policies")
}

func createURL(c *gophercloud.ServiceClient) string {
return rootURL(c)
}

0 comments on commit 1858d1f

Please sign in to comment.