Use trp to handle network
Change-Id: I1ff5c2d858d4f68a98867ef845887200b9561af0
This commit is contained in:
parent
a68cb327eb
commit
76ef989737
2
.gitignore
vendored
Normal file
2
.gitignore
vendored
Normal file
@ -0,0 +1,2 @@
|
||||
# binaries
|
||||
_output
|
38
Godeps/Godeps.json
generated
38
Godeps/Godeps.json
generated
@ -6,6 +6,16 @@
|
||||
"./..."
|
||||
],
|
||||
"Deps": [
|
||||
{
|
||||
"ImportPath": "cloud.google.com/go/compute/metadata",
|
||||
"Comment": "v0.1.0-115-g3b1ae45",
|
||||
"Rev": "3b1ae45394a234c385be014e9a488f2bb6eef821"
|
||||
},
|
||||
{
|
||||
"ImportPath": "cloud.google.com/go/internal",
|
||||
"Comment": "v0.1.0-115-g3b1ae45",
|
||||
"Rev": "3b1ae45394a234c385be014e9a488f2bb6eef821"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/PuerkitoBio/purell",
|
||||
"Comment": "v1.0.0",
|
||||
@ -116,6 +126,22 @@
|
||||
"ImportPath": "github.com/gophercloud/gophercloud/openstack/identity/v3/tokens",
|
||||
"Rev": "5102b608e3e070dadf65b060362fe4052f0c5967"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/gophercloud/gophercloud/openstack/networking/v2/extensions/layer3/routers",
|
||||
"Rev": "5102b608e3e070dadf65b060362fe4052f0c5967"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/gophercloud/gophercloud/openstack/networking/v2/networks",
|
||||
"Rev": "5102b608e3e070dadf65b060362fe4052f0c5967"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/gophercloud/gophercloud/openstack/networking/v2/ports",
|
||||
"Rev": "5102b608e3e070dadf65b060362fe4052f0c5967"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/gophercloud/gophercloud/openstack/networking/v2/subnets",
|
||||
"Rev": "5102b608e3e070dadf65b060362fe4052f0c5967"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/gophercloud/gophercloud/openstack/utils",
|
||||
"Rev": "5102b608e3e070dadf65b060362fe4052f0c5967"
|
||||
@ -157,6 +183,10 @@
|
||||
"ImportPath": "github.com/mailru/easyjson/jwriter",
|
||||
"Rev": "d5b7844b561a7bc640052f1b935f7b800330d7e0"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/pborman/uuid",
|
||||
"Rev": "ca53cad383cad2479bbba7f7a1a05797ec1386e4"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/spf13/pflag",
|
||||
"Rev": "9ff6c6923cfffbcd502984b8e0c80539a94968b7"
|
||||
@ -173,6 +203,10 @@
|
||||
"ImportPath": "golang.org/x/net/context",
|
||||
"Rev": "f2499483f923065a842d38eb4c7f1927e6fc6e6d"
|
||||
},
|
||||
{
|
||||
"ImportPath": "golang.org/x/net/context/ctxhttp",
|
||||
"Rev": "f2499483f923065a842d38eb4c7f1927e6fc6e6d"
|
||||
},
|
||||
{
|
||||
"ImportPath": "golang.org/x/net/http2",
|
||||
"Rev": "f2499483f923065a842d38eb4c7f1927e6fc6e6d"
|
||||
@ -407,6 +441,10 @@
|
||||
"ImportPath": "k8s.io/apimachinery/pkg/util/sets",
|
||||
"Rev": "2de00c78cb6d6127fb51b9531c1b3def1cbcac8c"
|
||||
},
|
||||
{
|
||||
"ImportPath": "k8s.io/apimachinery/pkg/util/uuid",
|
||||
"Rev": "2de00c78cb6d6127fb51b9531c1b3def1cbcac8c"
|
||||
},
|
||||
{
|
||||
"ImportPath": "k8s.io/apimachinery/pkg/util/validation",
|
||||
"Rev": "2de00c78cb6d6127fb51b9531c1b3def1cbcac8c"
|
||||
|
4
Makefile
4
Makefile
@ -19,6 +19,8 @@ GOFLAGS :=
|
||||
TAGS :=
|
||||
LDFLAGS :=
|
||||
|
||||
OUTPUT := _output
|
||||
|
||||
# Default target
|
||||
.PHONY: all
|
||||
all: build
|
||||
@ -35,7 +37,7 @@ depend-update: work
|
||||
|
||||
.PHONY: build
|
||||
build: depend
|
||||
cd $(DEST) && go build $(GOFLAGS) -tags '$(TAGS)' -ldflags '$(LDFLAGS)' ./...
|
||||
cd $(DEST) && go build $(GOFLAGS) -a -o $(OUTPUT)/stackube-controller ./cmd/stackube-controller
|
||||
|
||||
.PHONY: install
|
||||
install: depend
|
||||
|
@ -10,6 +10,7 @@ import (
|
||||
|
||||
"git.openstack.org/openstack/stackube/pkg/auth-controller/rbacmanager"
|
||||
"git.openstack.org/openstack/stackube/pkg/auth-controller/tenant"
|
||||
"git.openstack.org/openstack/stackube/pkg/network-controller"
|
||||
"git.openstack.org/openstack/stackube/pkg/openstack"
|
||||
"git.openstack.org/openstack/stackube/pkg/util"
|
||||
|
||||
@ -23,12 +24,12 @@ var (
|
||||
)
|
||||
|
||||
func init() {
|
||||
flag.StringVar(&cfg.KubeConfig, "kubeconfig", "", "- path to kubeconfig")
|
||||
flag.StringVar(&cfg.CloudConfig, "cloudconfig", "", "- path to cloudconfig")
|
||||
flag.StringVar(&cfg.KubeConfig, "kubeconfig", "/etc/kubernetes/admin.conf", "- path to kubeconfig")
|
||||
flag.StringVar(&cfg.CloudConfig, "cloudconfig", "/etc/kubestack.conf", "- path to cloudconfig")
|
||||
flag.Parse()
|
||||
}
|
||||
|
||||
func Main() int {
|
||||
func startControllers() int {
|
||||
// Verify client setting at the beginning and fail early if there are errors.
|
||||
err := verifyClientSetting()
|
||||
if err != nil {
|
||||
@ -51,9 +52,22 @@ func Main() int {
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
wg, ctx := errgroup.WithContext(ctx)
|
||||
|
||||
// start auth controllers in stackube
|
||||
wg.Go(func() error { return tc.Run(ctx.Done()) })
|
||||
wg.Go(func() error { return rm.Run(ctx.Done()) })
|
||||
|
||||
networkController, err := network.NewNetworkController(
|
||||
cfg.KubeConfig,
|
||||
cfg.CloudConfig,
|
||||
)
|
||||
if err != nil {
|
||||
glog.Error(err)
|
||||
return 1
|
||||
}
|
||||
|
||||
// start network controller
|
||||
wg.Go(func() error { return networkController.Run(ctx.Done()) })
|
||||
|
||||
term := make(chan os.Signal)
|
||||
signal.Notify(term, os.Interrupt, syscall.SIGTERM)
|
||||
|
||||
@ -89,5 +103,5 @@ func verifyClientSetting() error {
|
||||
}
|
||||
|
||||
func main() {
|
||||
os.Exit(Main())
|
||||
os.Exit(startControllers())
|
||||
}
|
104
doc/source/developer.rst
Normal file
104
doc/source/developer.rst
Normal file
@ -0,0 +1,104 @@
|
||||
Developer Document
|
||||
=====================================
|
||||
|
||||
This page describes how to setup a working development environment that can be used in developing stackube on Ubuntu or CentOS. These instructions assume you're already installed git, golang and python on your host.
|
||||
|
||||
=================
|
||||
Stackube controller
|
||||
=================
|
||||
|
||||
--------
|
||||
Build
|
||||
--------
|
||||
|
||||
::
|
||||
|
||||
make build
|
||||
|
||||
The binary will be placed at:
|
||||
|
||||
::
|
||||
|
||||
_output/stackube-controller
|
||||
|
||||
--------
|
||||
Start
|
||||
--------
|
||||
|
||||
::
|
||||
|
||||
./_output/stackube-controller -v=5 -alsologtostderr=true -logtostderr=true
|
||||
|
||||
|
||||
|
||||
--------
|
||||
Test
|
||||
--------
|
||||
|
||||
1. Prepare Tenant and Network
|
||||
|
||||
::
|
||||
|
||||
$ cat test-tenant.yaml
|
||||
|
||||
apiVersion: "stackube.kubernetes.io/v1"
|
||||
kind: Tenant
|
||||
metadata:
|
||||
name: test
|
||||
spec:
|
||||
username: "test"
|
||||
password: "password"
|
||||
|
||||
|
||||
$ cat test-network.yaml
|
||||
|
||||
apiVersion: "stackube.kubernetes.io/v1"
|
||||
kind: Network
|
||||
metadata:
|
||||
name: test-net
|
||||
namespace: test
|
||||
spec:
|
||||
cidr: "192.168.0.0/24"
|
||||
gateway: "192.168.0.1"
|
||||
|
||||
2. Create new Tenant and its Network in Kubernetes
|
||||
|
||||
::
|
||||
|
||||
$ export KUBECONFIG=/etc/kubernetes/admin.conf
|
||||
$ kubectl create -f ~/test-tenant.yaml
|
||||
$ kubectl create -f ~/test-network.yaml
|
||||
|
||||
3. Check the Network and Tenant is created in Neutron by Stackube controller
|
||||
|
||||
::
|
||||
|
||||
$ source ~/keystonerc_admin
|
||||
$ neutron net-list
|
||||
+--------------------------------------+----------------------+----------------------------------+----------------------------------------------------------+
|
||||
| id | name | tenant_id | subnets |
|
||||
+--------------------------------------+----------------------+----------------------------------+----------------------------------------------------------+
|
||||
| 421d913a-a269-408a-9765-2360e202ad5b | kube_test_test-net | 915b36add7e34018b7241ab63a193530 | bb446a53-de4d-4546-81fc-8736a9a88e3a 192.168.0.0/24 |
|
||||
|
||||
4. Check Network object is created in Kubernetes
|
||||
|
||||
::
|
||||
|
||||
$ kubectl get network test-net --namespace=test
|
||||
NAME KIND
|
||||
test-net Network.v1.stackube.kubernetes.io
|
||||
|
||||
5. Delete the Network from Kubernetes
|
||||
|
||||
::
|
||||
|
||||
$ kubectl delete -f test-network.yaml
|
||||
|
||||
6. Check Network in Neutron is also deleted by Stackube controller
|
||||
|
||||
::
|
||||
|
||||
$ neutron net-list
|
||||
+--------------------------------------+---------+----------------------------------+----------------------------------------------------------+
|
||||
| id | name | tenant_id | subnets |
|
||||
+--------------------------------------+---------+----------------------------------+----------------------------------------------------------+
|
@ -21,3 +21,5 @@ Developer Guide
|
||||
|
||||
setup
|
||||
|
||||
developer
|
||||
|
||||
|
@ -61,4 +61,3 @@ And configure local.conf:
|
||||
- Set `HOST_IP` to local host's IP
|
||||
- Set `SERVICE_HOST` to master's IP
|
||||
- Set `KUBEADM_TOKEN` to kubeadm token
|
||||
|
||||
|
@ -11,6 +11,21 @@ const (
|
||||
TenantResourcePlural = "tenants"
|
||||
)
|
||||
|
||||
// These are the valid phases of a network state.
|
||||
const (
|
||||
// NetworkInitializing means the network is just accepted by system
|
||||
NetworkInitializing = "Initializing"
|
||||
// NetworkActive means the network is available for use in the system
|
||||
NetworkActive = "Active"
|
||||
// NetworkPending means the network is accepted by system, but it is still
|
||||
// processing by network provider
|
||||
NetworkPending = "Pending"
|
||||
// NetworkFailed means the network is not available
|
||||
NetworkFailed = "Failed"
|
||||
// NetworkTerminating means the network is undergoing graceful termination
|
||||
NetworkTerminating = "Terminating"
|
||||
)
|
||||
|
||||
// Network describes a Neutron network.
|
||||
type Network struct {
|
||||
// TypeMeta defines type of the object and its API schema version.
|
||||
@ -19,7 +34,7 @@ type Network struct {
|
||||
metav1.ObjectMeta `json:"metadata"`
|
||||
|
||||
// Spec describes the behavior of a network.
|
||||
Spec NetworkSpec
|
||||
Spec NetworkSpec `json:"spec"`
|
||||
// Status describes the network status.
|
||||
Status NetworkStatus `json:"status,omitempty"`
|
||||
}
|
||||
@ -61,7 +76,7 @@ type Tenant struct {
|
||||
metav1.ObjectMeta `json:"metadata"`
|
||||
|
||||
// Spec defines the behavior of a tenant.
|
||||
Spec TenantSpec
|
||||
Spec TenantSpec `json:"spec"`
|
||||
// Status describes the tenant status.
|
||||
Status TenantStatus `json:"status,omitempty"`
|
||||
}
|
||||
|
29
pkg/network-controller/client/client.go
Normal file
29
pkg/network-controller/client/client.go
Normal file
@ -0,0 +1,29 @@
|
||||
package client
|
||||
|
||||
import (
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
"k8s.io/apimachinery/pkg/runtime/serializer"
|
||||
"k8s.io/client-go/rest"
|
||||
|
||||
tprv1 "git.openstack.org/openstack/stackube/pkg/apis/v1"
|
||||
)
|
||||
|
||||
func NewClient(cfg *rest.Config) (*rest.RESTClient, *runtime.Scheme, error) {
|
||||
scheme := runtime.NewScheme()
|
||||
if err := tprv1.AddToScheme(scheme); err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
config := *cfg
|
||||
config.GroupVersion = &tprv1.SchemeGroupVersion
|
||||
config.APIPath = "/apis"
|
||||
config.ContentType = runtime.ContentTypeJSON
|
||||
config.NegotiatedSerializer = serializer.DirectCodecFactory{CodecFactory: serializer.NewCodecFactory(scheme)}
|
||||
|
||||
client, err := rest.RESTClientFor(&config)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
return client, scheme, nil
|
||||
}
|
58
pkg/network-controller/client/network_tpr.go
Normal file
58
pkg/network-controller/client/network_tpr.go
Normal file
@ -0,0 +1,58 @@
|
||||
package client
|
||||
|
||||
import (
|
||||
"time"
|
||||
|
||||
tprv1 "git.openstack.org/openstack/stackube/pkg/apis/v1"
|
||||
apierrors "k8s.io/apimachinery/pkg/api/errors"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/util/wait"
|
||||
"k8s.io/client-go/kubernetes"
|
||||
apiv1 "k8s.io/client-go/pkg/api/v1"
|
||||
"k8s.io/client-go/pkg/apis/extensions/v1beta1"
|
||||
"k8s.io/client-go/rest"
|
||||
)
|
||||
|
||||
func CreateNetworkTPR(clientset kubernetes.Interface) error {
|
||||
tpr := &v1beta1.ThirdPartyResource{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "network." + tprv1.GroupName,
|
||||
},
|
||||
Versions: []v1beta1.APIVersion{
|
||||
{Name: tprv1.SchemeGroupVersion.Version},
|
||||
},
|
||||
Description: "An Network ThirdPartyResource",
|
||||
}
|
||||
_, err := clientset.ExtensionsV1beta1().ThirdPartyResources().Create(tpr)
|
||||
return err
|
||||
}
|
||||
|
||||
func WaitForNetworkResource(networkClient *rest.RESTClient) error {
|
||||
return wait.Poll(100*time.Millisecond, 60*time.Second, func() (bool, error) {
|
||||
_, err := networkClient.Get().Namespace(apiv1.NamespaceDefault).Resource(tprv1.NetworkResourcePlural).DoRaw()
|
||||
if err == nil {
|
||||
return true, nil
|
||||
}
|
||||
if apierrors.IsNotFound(err) {
|
||||
return false, nil
|
||||
}
|
||||
return false, err
|
||||
})
|
||||
}
|
||||
|
||||
func WaitForNetworkInstanceProcessed(networkClient *rest.RESTClient, name string) error {
|
||||
return wait.Poll(100*time.Millisecond, 10*time.Second, func() (bool, error) {
|
||||
var network tprv1.Network
|
||||
err := networkClient.Get().
|
||||
Resource(tprv1.NetworkResourcePlural).
|
||||
Namespace(apiv1.NamespaceDefault).
|
||||
Name(name).
|
||||
Do().Into(&network)
|
||||
|
||||
if err == nil && network.Status.State == tprv1.NetworkActive {
|
||||
return true, nil
|
||||
}
|
||||
|
||||
return false, err
|
||||
})
|
||||
}
|
143
pkg/network-controller/network_controller.go
Normal file
143
pkg/network-controller/network_controller.go
Normal file
@ -0,0 +1,143 @@
|
||||
package network
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
apierrors "k8s.io/apimachinery/pkg/api/errors"
|
||||
"k8s.io/apimachinery/pkg/fields"
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
utilruntime "k8s.io/apimachinery/pkg/util/runtime"
|
||||
"k8s.io/client-go/kubernetes"
|
||||
apiv1 "k8s.io/client-go/pkg/api/v1"
|
||||
"k8s.io/client-go/rest"
|
||||
"k8s.io/client-go/tools/cache"
|
||||
"k8s.io/client-go/tools/clientcmd"
|
||||
|
||||
tprv1 "git.openstack.org/openstack/stackube/pkg/apis/v1"
|
||||
tprclient "git.openstack.org/openstack/stackube/pkg/network-controller/client"
|
||||
driver "git.openstack.org/openstack/stackube/pkg/openstack"
|
||||
"git.openstack.org/openstack/stackube/pkg/util"
|
||||
|
||||
"github.com/golang/glog"
|
||||
)
|
||||
|
||||
// Watcher is an network of watching on resource create/update/delete events
|
||||
type NetworkController struct {
|
||||
NetworkClient *rest.RESTClient
|
||||
NetworkScheme *runtime.Scheme
|
||||
Driver *driver.Client
|
||||
}
|
||||
|
||||
func (c *NetworkController) Run(stopCh <-chan struct{}) error {
|
||||
defer utilruntime.HandleCrash()
|
||||
|
||||
source := cache.NewListWatchFromClient(
|
||||
c.NetworkClient,
|
||||
tprv1.NetworkResourcePlural,
|
||||
apiv1.NamespaceAll,
|
||||
fields.Everything())
|
||||
|
||||
_, networkInformer := cache.NewInformer(
|
||||
source,
|
||||
&tprv1.Network{},
|
||||
0,
|
||||
cache.ResourceEventHandlerFuncs{
|
||||
AddFunc: c.onAdd,
|
||||
UpdateFunc: c.onUpdate,
|
||||
DeleteFunc: c.onDelete,
|
||||
})
|
||||
|
||||
go networkInformer.Run(stopCh)
|
||||
<-stopCh
|
||||
return nil
|
||||
}
|
||||
|
||||
func buildConfig(kubeconfig string) (*rest.Config, error) {
|
||||
if kubeconfig != "" {
|
||||
return clientcmd.BuildConfigFromFlags("", kubeconfig)
|
||||
}
|
||||
return rest.InClusterConfig()
|
||||
}
|
||||
|
||||
func NewNetworkController(kubeconfig, openstackConfigFile string) (*NetworkController, error) {
|
||||
// Create OpenStack client from config
|
||||
openstack, err := driver.NewClient(openstackConfigFile)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("Couldn't initialize openstack: %#v", err)
|
||||
}
|
||||
|
||||
// Create the client config. Use kubeconfig if given, otherwise assume in-cluster.
|
||||
config, err := buildConfig(kubeconfig)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to build kubeconfig: %v", err)
|
||||
}
|
||||
clientset, err := kubernetes.NewForConfig(config)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to create kubeclient from config: %v", err)
|
||||
}
|
||||
|
||||
// initialize third party resource if it does not exist
|
||||
err = tprclient.CreateNetworkTPR(clientset)
|
||||
if err != nil && !apierrors.IsAlreadyExists(err) {
|
||||
return nil, fmt.Errorf("failed to create TPR to kube-apiserver: %v", err)
|
||||
}
|
||||
|
||||
// make a new config for our extension's API group, using the first config as a baseline
|
||||
networkClient, networkScheme, err := tprclient.NewClient(config)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to create client for TPR: %v", err)
|
||||
}
|
||||
|
||||
// wait until TPR gets processed
|
||||
err = tprclient.WaitForNetworkResource(networkClient)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to wait TPR change to ready status: %v", err)
|
||||
}
|
||||
|
||||
networkController := &NetworkController{
|
||||
NetworkClient: networkClient,
|
||||
NetworkScheme: networkScheme,
|
||||
Driver: openstack,
|
||||
}
|
||||
return networkController, nil
|
||||
}
|
||||
|
||||
func (c *NetworkController) onAdd(obj interface{}) {
|
||||
network := obj.(*tprv1.Network)
|
||||
glog.Infof("[NETWORK CONTROLLER] OnAdd %s\n", network.ObjectMeta.SelfLink)
|
||||
|
||||
// NEVER modify objects from the store. It's a read-only, local cache.
|
||||
// You can use networkScheme.Copy() to make a deep copy of original object and modify this copy
|
||||
// Or create a copy manually for better performance
|
||||
copyObj, err := c.NetworkScheme.Copy(network)
|
||||
if err != nil {
|
||||
glog.Errorf("ERROR creating a deep copy of network object: %v\n", err)
|
||||
return
|
||||
}
|
||||
|
||||
networkCopy := copyObj.(*tprv1.Network)
|
||||
|
||||
// This will:
|
||||
// 1. Create Network in Neutron
|
||||
// 2. Update Network TRP object status to Active or Failed
|
||||
c.addNetworkToNeutron(networkCopy)
|
||||
}
|
||||
|
||||
func (c *NetworkController) onUpdate(oldObj, newObj interface{}) {
|
||||
// NOTE(harry) not supported yet
|
||||
}
|
||||
|
||||
func (c *NetworkController) onDelete(obj interface{}) {
|
||||
if net, ok := obj.(*tprv1.Network); ok {
|
||||
glog.V(4).Infof("NetworkController: network %s deleted", net.Name)
|
||||
if net.Spec.NetworkID == "" {
|
||||
networkName := util.BuildNetworkName(net.GetNamespace(), net.GetName())
|
||||
err := c.Driver.DeleteNetwork(networkName)
|
||||
if err != nil {
|
||||
glog.Errorf("NetworkController: delete network %s failed in networkprovider: %v", networkName, err)
|
||||
} else {
|
||||
glog.V(4).Infof("NetworkController: network %s deleted in networkprovider", networkName)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
122
pkg/network-controller/network_controller_helper.go
Normal file
122
pkg/network-controller/network_controller_helper.go
Normal file
@ -0,0 +1,122 @@
|
||||
package network
|
||||
|
||||
import (
|
||||
"time"
|
||||
|
||||
"k8s.io/apimachinery/pkg/util/wait"
|
||||
|
||||
tprv1 "git.openstack.org/openstack/stackube/pkg/apis/v1"
|
||||
drivertypes "git.openstack.org/openstack/stackube/pkg/openstack/types"
|
||||
"git.openstack.org/openstack/stackube/pkg/util"
|
||||
|
||||
"github.com/golang/glog"
|
||||
)
|
||||
|
||||
const (
|
||||
networkPrefix = "network"
|
||||
subnetSuffix = "subnet"
|
||||
)
|
||||
|
||||
func (c *NetworkController) addNetworkToNeutron(kubeNetwork *tprv1.Network) {
|
||||
// The tenant name is the same with namespace, let's get tenantID by tenantName
|
||||
tenantName := kubeNetwork.GetNamespace()
|
||||
tenantID, err := c.Driver.GetTenantIDFromName(tenantName)
|
||||
if err != nil {
|
||||
// Retry for a while if failed
|
||||
err = wait.Poll(2*time.Second, 10*time.Second, func() (bool, error) {
|
||||
glog.V(3).Infof("failed to fetch tenantID for tenantName: %v, retrying\n", tenantName)
|
||||
if tenantID, err = c.Driver.GetTenantIDFromName(kubeNetwork.GetNamespace()); err != nil {
|
||||
return false, nil
|
||||
}
|
||||
return true, nil
|
||||
})
|
||||
}
|
||||
if err != nil {
|
||||
glog.Errorf("failed to fetch tenantID for tenantName: %v, abort! \n", tenantName)
|
||||
} else {
|
||||
glog.V(3).Infof("Got tenantID: %v for tenantName: %v", tenantID, tenantName)
|
||||
}
|
||||
|
||||
networkName := util.BuildNetworkName(tenantName, kubeNetwork.GetName())
|
||||
|
||||
// Translate Kubernetes network to OpenStack network
|
||||
driverNetwork := &drivertypes.Network{
|
||||
Name: networkName,
|
||||
TenantID: tenantID,
|
||||
Subnets: []*drivertypes.Subnet{
|
||||
{
|
||||
// network: subnet = 1:1
|
||||
Name: networkName + "-" + subnetSuffix,
|
||||
Cidr: kubeNetwork.Spec.CIDR,
|
||||
Gateway: kubeNetwork.Spec.Gateway,
|
||||
Tenantid: tenantID,
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
newNetworkStatus := tprv1.NetworkActive
|
||||
|
||||
glog.V(4).Infof("[NetworkController]: adding network %s", driverNetwork.Name)
|
||||
|
||||
// Check if tenant id exist
|
||||
check, err := c.Driver.CheckTenantID(driverNetwork.TenantID)
|
||||
if err != nil {
|
||||
glog.Errorf("[NetworkController]: check tenantID failed: %v", err)
|
||||
}
|
||||
if !check {
|
||||
glog.Warningf("[NetworkController]: tenantID %s doesn't exit in network provider", driverNetwork.TenantID)
|
||||
kubeNetwork.Status.State = tprv1.NetworkFailed
|
||||
c.updateNetwork(kubeNetwork)
|
||||
return
|
||||
}
|
||||
|
||||
// Check if provider network id exist
|
||||
if kubeNetwork.Spec.NetworkID != "" {
|
||||
_, err := c.Driver.GetNetworkByID(kubeNetwork.Spec.NetworkID)
|
||||
if err != nil {
|
||||
glog.Warningf("[NetworkController]: network %s doesn't exit in network provider", kubeNetwork.Spec.NetworkID)
|
||||
newNetworkStatus = tprv1.NetworkFailed
|
||||
}
|
||||
} else {
|
||||
if len(driverNetwork.Subnets) == 0 {
|
||||
glog.Warningf("[NetworkController]: subnets of %s is null", driverNetwork.Name)
|
||||
newNetworkStatus = tprv1.NetworkFailed
|
||||
} else {
|
||||
// Check if provider network has already created
|
||||
_, err := c.Driver.GetNetwork(networkName)
|
||||
if err == nil {
|
||||
glog.Infof("[NetworkController]: network %s has already created", networkName)
|
||||
} else if err.Error() == util.ErrNotFound.Error() {
|
||||
// Create a new network by network provider
|
||||
err := c.Driver.CreateNetwork(driverNetwork)
|
||||
if err != nil {
|
||||
glog.Warningf("[NetworkController]: create network %s failed: %v", driverNetwork.Name, err)
|
||||
newNetworkStatus = tprv1.NetworkFailed
|
||||
}
|
||||
} else {
|
||||
glog.Warningf("[NetworkController]: get network failed: %v", err)
|
||||
newNetworkStatus = tprv1.NetworkFailed
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
kubeNetwork.Status.State = newNetworkStatus
|
||||
c.updateNetwork(kubeNetwork)
|
||||
}
|
||||
|
||||
// updateNetwork updates Network TPR object by given object
|
||||
func (c *NetworkController) updateNetwork(network *tprv1.Network) {
|
||||
err := c.NetworkClient.Put().
|
||||
Name(network.ObjectMeta.Name).
|
||||
Namespace(network.ObjectMeta.Namespace).
|
||||
Resource(tprv1.NetworkResourcePlural).
|
||||
Body(network).
|
||||
Do().
|
||||
Error()
|
||||
|
||||
if err != nil {
|
||||
glog.Errorf("ERROR updating network status: %v\n", err)
|
||||
} else {
|
||||
glog.V(3).Infof("UPDATED network status: %#v\n", network)
|
||||
}
|
||||
}
|
@ -1,6 +1,7 @@
|
||||
package openstack
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"os"
|
||||
|
||||
"github.com/golang/glog"
|
||||
@ -8,17 +9,41 @@ import (
|
||||
"github.com/gophercloud/gophercloud/openstack"
|
||||
"github.com/gophercloud/gophercloud/openstack/identity/v2/tenants"
|
||||
"github.com/gophercloud/gophercloud/openstack/identity/v2/users"
|
||||
"github.com/gophercloud/gophercloud/openstack/networking/v2/extensions/layer3/routers"
|
||||
"github.com/gophercloud/gophercloud/openstack/networking/v2/networks"
|
||||
"github.com/gophercloud/gophercloud/openstack/networking/v2/ports"
|
||||
"github.com/gophercloud/gophercloud/openstack/networking/v2/subnets"
|
||||
"github.com/gophercloud/gophercloud/pagination"
|
||||
|
||||
drivertypes "git.openstack.org/openstack/stackube/pkg/openstack/types"
|
||||
gcfg "gopkg.in/gcfg.v1"
|
||||
)
|
||||
|
||||
const (
|
||||
StatusCodeAlreadyExists int = 409
|
||||
|
||||
podNamePrefix = "kube"
|
||||
securitygroupName = "kube-securitygroup-default"
|
||||
hostnameMaxLen = 63
|
||||
|
||||
// Service affinities
|
||||
ServiceAffinityNone = "None"
|
||||
ServiceAffinityClientIP = "ClientIP"
|
||||
)
|
||||
|
||||
var (
|
||||
adminStateUp = true
|
||||
|
||||
ErrNotFound = errors.New("NotFound")
|
||||
ErrMultipleResults = errors.New("MultipleResults")
|
||||
)
|
||||
|
||||
type Client struct {
|
||||
Identity *gophercloud.ServiceClient
|
||||
Provider *gophercloud.ProviderClient
|
||||
Network *gophercloud.ServiceClient
|
||||
Region string
|
||||
ExtNetID string
|
||||
}
|
||||
|
||||
type Config struct {
|
||||
@ -27,6 +52,8 @@ type Config struct {
|
||||
Username string `gcfg:"username"`
|
||||
Password string `gcfg: "password"`
|
||||
TenantName string `gcfg:"tenant-name"`
|
||||
Region string `gcfg:"region"`
|
||||
ExtNetID string `gcfg:"ext-net-id"`
|
||||
}
|
||||
}
|
||||
|
||||
@ -41,7 +68,8 @@ func toAuthOptions(cfg Config) gophercloud.AuthOptions {
|
||||
|
||||
func NewClient(config string) (*Client, error) {
|
||||
var opts gophercloud.AuthOptions
|
||||
if cfg, err := readConfig(config); err != nil {
|
||||
cfg, err := readConfig(config)
|
||||
if err != nil {
|
||||
glog.V(0).Info("Failed read cloudconfig: %v. Starting init openstackclient form env", err)
|
||||
opts, err = openstack.AuthOptionsFromEnv()
|
||||
if err != nil {
|
||||
@ -63,9 +91,20 @@ func NewClient(config string) (*Client, error) {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
network, err := openstack.NewNetworkV2(provider, gophercloud.EndpointOpts{
|
||||
Region: cfg.Global.Region,
|
||||
})
|
||||
if err != nil {
|
||||
glog.Warning("Failed to find neutron endpoint: %v", err)
|
||||
return nil, err
|
||||
}
|
||||
|
||||
client := &Client{
|
||||
Identity: identity,
|
||||
Provider: provider,
|
||||
Network: network,
|
||||
Region: cfg.Global.Region,
|
||||
ExtNetID: cfg.Global.ExtNetID,
|
||||
}
|
||||
return client, nil
|
||||
}
|
||||
@ -83,7 +122,7 @@ func readConfig(config string) (Config, error) {
|
||||
return cfg, nil
|
||||
}
|
||||
|
||||
func (c *Client) getTenantID(tenantName string) (string, error) {
|
||||
func (c *Client) GetTenantIDFromName(tenantName string) (string, error) {
|
||||
var tenantID string
|
||||
err := tenants.List(c.Identity, nil).EachPage(func(page pagination.Page) (bool, error) {
|
||||
tenantList, err1 := tenants.ExtractTenants(page)
|
||||
@ -117,7 +156,7 @@ func (c *Client) CreateTenant(tenantName string) (string, error) {
|
||||
return "", err
|
||||
}
|
||||
glog.V(4).Infof("Tenant %s created", tenantName)
|
||||
tenantID, err := c.getTenantID(tenantName)
|
||||
tenantID, err := c.GetTenantIDFromName(tenantName)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
@ -158,7 +197,7 @@ func (c *Client) CreateUser(username, password, tenantID string) error {
|
||||
}
|
||||
|
||||
func (c *Client) DeleteAllUsersOnTenant(tenantName string) error {
|
||||
tenantID, err := c.getTenantID(tenantName)
|
||||
tenantID, err := c.GetTenantIDFromName(tenantName)
|
||||
if err != nil {
|
||||
return nil
|
||||
}
|
||||
@ -190,3 +229,341 @@ func reasonForError(err error) int {
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
// Get openstack network by id
|
||||
func (os *Client) getOpenStackNetworkByID(id string) (*networks.Network, error) {
|
||||
opts := networks.ListOpts{ID: id}
|
||||
return os.getOpenStackNetwork(&opts)
|
||||
}
|
||||
|
||||
// Get openstack network by name
|
||||
func (os *Client) getOpenStackNetworkByName(name string) (*networks.Network, error) {
|
||||
opts := networks.ListOpts{Name: name}
|
||||
return os.getOpenStackNetwork(&opts)
|
||||
}
|
||||
|
||||
// Get openstack network
|
||||
func (os *Client) getOpenStackNetwork(opts *networks.ListOpts) (*networks.Network, error) {
|
||||
var osNetwork *networks.Network
|
||||
pager := networks.List(os.Network, *opts)
|
||||
err := pager.EachPage(func(page pagination.Page) (bool, error) {
|
||||
networkList, e := networks.ExtractNetworks(page)
|
||||
if len(networkList) > 1 {
|
||||
return false, ErrMultipleResults
|
||||
}
|
||||
|
||||
if len(networkList) == 1 {
|
||||
osNetwork = &networkList[0]
|
||||
}
|
||||
|
||||
return true, e
|
||||
})
|
||||
|
||||
if err == nil && osNetwork == nil {
|
||||
return nil, ErrNotFound
|
||||
}
|
||||
|
||||
return osNetwork, err
|
||||
}
|
||||
|
||||
// Get provider subnet by id
|
||||
func (os *Client) getProviderSubnet(osSubnetID string) (*drivertypes.Subnet, error) {
|
||||
s, err := subnets.Get(os.Network, osSubnetID).Extract()
|
||||
if err != nil {
|
||||
glog.Errorf("Get openstack subnet failed: %v", err)
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var routes []*drivertypes.Route
|
||||
for _, r := range s.HostRoutes {
|
||||
route := drivertypes.Route{
|
||||
Nexthop: r.NextHop,
|
||||
DestinationCIDR: r.DestinationCIDR,
|
||||
}
|
||||
routes = append(routes, &route)
|
||||
}
|
||||
|
||||
providerSubnet := drivertypes.Subnet{
|
||||
Uid: s.ID,
|
||||
Cidr: s.CIDR,
|
||||
Gateway: s.GatewayIP,
|
||||
Name: s.Name,
|
||||
Dnsservers: s.DNSNameservers,
|
||||
Routes: routes,
|
||||
}
|
||||
|
||||
return &providerSubnet, nil
|
||||
}
|
||||
|
||||
// Get network by networkID
|
||||
func (os *Client) GetNetworkByID(networkID string) (*drivertypes.Network, error) {
|
||||
osNetwork, err := os.getOpenStackNetworkByID(networkID)
|
||||
if err != nil {
|
||||
glog.Errorf("failed to fetch openstack network by iD: %v, failure: %v", networkID, err)
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return os.OSNetworktoProviderNetwork(osNetwork)
|
||||
}
|
||||
|
||||
// Get network by networkName
|
||||
func (os *Client) GetNetwork(networkName string) (*drivertypes.Network, error) {
|
||||
osNetwork, err := os.getOpenStackNetworkByName(networkName)
|
||||
if err != nil {
|
||||
glog.Warningf("failed to fetch openstack network by name: %v failure: %v", networkName, err)
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return os.OSNetworktoProviderNetwork(osNetwork)
|
||||
}
|
||||
|
||||
func (os *Client) OSNetworktoProviderNetwork(osNetwork *networks.Network) (*drivertypes.Network, error) {
|
||||
var providerNetwork drivertypes.Network
|
||||
var providerSubnets []*drivertypes.Subnet
|
||||
providerNetwork.Name = osNetwork.Name
|
||||
providerNetwork.Uid = osNetwork.ID
|
||||
providerNetwork.Status = os.ToProviderStatus(osNetwork.Status)
|
||||
providerNetwork.TenantID = osNetwork.TenantID
|
||||
|
||||
for _, subnetID := range osNetwork.Subnets {
|
||||
s, err := os.getProviderSubnet(subnetID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
providerSubnets = append(providerSubnets, s)
|
||||
}
|
||||
|
||||
providerNetwork.Subnets = providerSubnets
|
||||
|
||||
return &providerNetwork, nil
|
||||
}
|
||||
|
||||
func (os *Client) ToProviderStatus(status string) string {
|
||||
switch status {
|
||||
case "ACTIVE":
|
||||
return "Active"
|
||||
case "BUILD":
|
||||
return "Pending"
|
||||
case "DOWN", "ERROR":
|
||||
return "Failed"
|
||||
default:
|
||||
return "Failed"
|
||||
}
|
||||
|
||||
return "Failed"
|
||||
}
|
||||
|
||||
// Create network
|
||||
func (os *Client) CreateNetwork(network *drivertypes.Network) error {
|
||||
if len(network.Subnets) == 0 {
|
||||
return errors.New("Subnets is null")
|
||||
}
|
||||
|
||||
// create network
|
||||
opts := networks.CreateOpts{
|
||||
Name: network.Name,
|
||||
AdminStateUp: &adminStateUp,
|
||||
TenantID: network.TenantID,
|
||||
}
|
||||
osNet, err := networks.Create(os.Network, opts).Extract()
|
||||
if err != nil {
|
||||
glog.Errorf("Create openstack network %s failed: %v", network.Name, err)
|
||||
return err
|
||||
}
|
||||
|
||||
// create router
|
||||
routerOpts := routers.CreateOpts{
|
||||
// use network name as router name for convenience
|
||||
Name: network.Name,
|
||||
TenantID: network.TenantID,
|
||||
GatewayInfo: &routers.GatewayInfo{NetworkID: os.ExtNetID},
|
||||
}
|
||||
osRouter, err := routers.Create(os.Network, routerOpts).Extract()
|
||||
if err != nil {
|
||||
glog.Errorf("Create openstack router %s failed: %v", network.Name, err)
|
||||
delErr := os.DeleteNetwork(network.Name)
|
||||
if delErr != nil {
|
||||
glog.Errorf("Delete openstack network %s failed: %v", network.Name, delErr)
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
// create subnets and connect them to router
|
||||
networkID := osNet.ID
|
||||
network.Status = os.ToProviderStatus(osNet.Status)
|
||||
network.Uid = osNet.ID
|
||||
for _, sub := range network.Subnets {
|
||||
// create subnet
|
||||
subnetOpts := subnets.CreateOpts{
|
||||
NetworkID: networkID,
|
||||
CIDR: sub.Cidr,
|
||||
Name: sub.Name,
|
||||
IPVersion: gophercloud.IPv4,
|
||||
TenantID: network.TenantID,
|
||||
GatewayIP: &sub.Gateway,
|
||||
DNSNameservers: sub.Dnsservers,
|
||||
}
|
||||
s, err := subnets.Create(os.Network, subnetOpts).Extract()
|
||||
if err != nil {
|
||||
glog.Errorf("Create openstack subnet %s failed: %v", sub.Name, err)
|
||||
delErr := os.DeleteNetwork(network.Name)
|
||||
if delErr != nil {
|
||||
glog.Errorf("Delete openstack network %s failed: %v", network.Name, delErr)
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
// add subnet to router
|
||||
opts := routers.AddInterfaceOpts{
|
||||
SubnetID: s.ID,
|
||||
}
|
||||
_, err = routers.AddInterface(os.Network, osRouter.ID, opts).Extract()
|
||||
if err != nil {
|
||||
glog.Errorf("Create openstack subnet %s failed: %v", sub.Name, err)
|
||||
delErr := os.DeleteNetwork(network.Name)
|
||||
if delErr != nil {
|
||||
glog.Errorf("Delete openstack network %s failed: %v", network.Name, delErr)
|
||||
}
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// Update network
|
||||
func (os *Client) UpdateNetwork(network *drivertypes.Network) error {
|
||||
// TODO: update network subnets
|
||||
return nil
|
||||
}
|
||||
|
||||
func (os *Client) getRouterByName(name string) (*routers.Router, error) {
|
||||
var result *routers.Router
|
||||
|
||||
opts := routers.ListOpts{Name: name}
|
||||
pager := routers.List(os.Network, opts)
|
||||
err := pager.EachPage(func(page pagination.Page) (bool, error) {
|
||||
routerList, e := routers.ExtractRouters(page)
|
||||
if len(routerList) > 1 {
|
||||
return false, ErrMultipleResults
|
||||
} else if len(routerList) == 1 {
|
||||
result = &routerList[0]
|
||||
}
|
||||
|
||||
return true, e
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return result, nil
|
||||
}
|
||||
|
||||
// Delete network by networkName
|
||||
func (os *Client) DeleteNetwork(networkName string) error {
|
||||
osNetwork, err := os.getOpenStackNetworkByName(networkName)
|
||||
if err != nil {
|
||||
glog.Errorf("Get openstack network failed: %v", err)
|
||||
return err
|
||||
}
|
||||
|
||||
if osNetwork != nil {
|
||||
// Delete ports
|
||||
opts := ports.ListOpts{NetworkID: osNetwork.ID}
|
||||
pager := ports.List(os.Network, opts)
|
||||
err := pager.EachPage(func(page pagination.Page) (bool, error) {
|
||||
portList, err := ports.ExtractPorts(page)
|
||||
if err != nil {
|
||||
glog.Errorf("Get openstack ports error: %v", err)
|
||||
return false, err
|
||||
}
|
||||
|
||||
for _, port := range portList {
|
||||
if port.DeviceOwner == "network:router_interface" {
|
||||
continue
|
||||
}
|
||||
|
||||
err = ports.Delete(os.Network, port.ID).ExtractErr()
|
||||
if err != nil {
|
||||
glog.Warningf("Delete port %v failed: %v", port.ID, err)
|
||||
}
|
||||
}
|
||||
|
||||
return true, nil
|
||||
})
|
||||
if err != nil {
|
||||
glog.Errorf("Delete ports error: %v", err)
|
||||
}
|
||||
|
||||
router, err := os.getRouterByName(networkName)
|
||||
if err != nil {
|
||||
glog.Errorf("Get openstack router %s error: %v", networkName, err)
|
||||
return err
|
||||
}
|
||||
|
||||
// delete all subnets
|
||||
for _, subnet := range osNetwork.Subnets {
|
||||
if router != nil {
|
||||
opts := routers.RemoveInterfaceOpts{SubnetID: subnet}
|
||||
_, err := routers.RemoveInterface(os.Network, router.ID, opts).Extract()
|
||||
if err != nil {
|
||||
glog.Errorf("Get openstack router %s error: %v", networkName, err)
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
err = subnets.Delete(os.Network, subnet).ExtractErr()
|
||||
if err != nil {
|
||||
glog.Errorf("Delete openstack subnet %s error: %v", subnet, err)
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
// delete router
|
||||
if router != nil {
|
||||
err = routers.Delete(os.Network, router.ID).ExtractErr()
|
||||
if err != nil {
|
||||
glog.Errorf("Delete openstack router %s error: %v", router.ID, err)
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
// delete network
|
||||
err = networks.Delete(os.Network, osNetwork.ID).ExtractErr()
|
||||
if err != nil {
|
||||
glog.Errorf("Delete openstack network %s error: %v", osNetwork.ID, err)
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// Check the tenant id exist
|
||||
func (os *Client) CheckTenantID(tenantID string) (bool, error) {
|
||||
opts := tenants.ListOpts{}
|
||||
pager := tenants.List(os.Identity, &opts)
|
||||
|
||||
var found bool
|
||||
err := pager.EachPage(func(page pagination.Page) (bool, error) {
|
||||
|
||||
tenantList, err := tenants.ExtractTenants(page)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
|
||||
if len(tenantList) == 0 {
|
||||
return false, ErrNotFound
|
||||
}
|
||||
|
||||
for _, t := range tenantList {
|
||||
if t.ID == tenantID || t.Name == tenantID {
|
||||
found = true
|
||||
}
|
||||
}
|
||||
|
||||
return true, nil
|
||||
})
|
||||
|
||||
return found, err
|
||||
}
|
||||
|
30
pkg/openstack/types/types.go
Normal file
30
pkg/openstack/types/types.go
Normal file
@ -0,0 +1,30 @@
|
||||
package types
|
||||
|
||||
type Network struct {
|
||||
Name string
|
||||
Uid string
|
||||
TenantID string
|
||||
SegmentID int32
|
||||
Subnets []*Subnet
|
||||
// Status of network
|
||||
// Valid value: Initializing, Active, Pending, Failed, Terminating
|
||||
Status string
|
||||
}
|
||||
|
||||
// Subnet is a representaion of a subnet
|
||||
type Subnet struct {
|
||||
Name string
|
||||
Uid string
|
||||
Cidr string
|
||||
Gateway string
|
||||
Tenantid string
|
||||
Dnsservers []string
|
||||
Routes []*Route
|
||||
}
|
||||
|
||||
// Route is a representation of an advanced routing rule.
|
||||
type Route struct {
|
||||
Name string
|
||||
Nexthop string
|
||||
DestinationCIDR string
|
||||
}
|
20
pkg/util/util.go
Normal file
20
pkg/util/util.go
Normal file
@ -0,0 +1,20 @@
|
||||
package util
|
||||
|
||||
import (
|
||||
"errors"
|
||||
)
|
||||
|
||||
const (
|
||||
namePrefix = "kube"
|
||||
)
|
||||
|
||||
var ErrNotFound = errors.New("NotFound")
|
||||
var ErrMultipleResults = errors.New("MultipleResults")
|
||||
|
||||
func BuildNetworkName(namespace, name string) string {
|
||||
return namePrefix + "_" + namespace + "_" + name
|
||||
}
|
||||
|
||||
func BuildLoadBalancerName(namespace, name string) string {
|
||||
return namePrefix + "_" + namespace + "_" + name
|
||||
}
|
15
vendor/cloud.google.com/go/AUTHORS
generated
vendored
Normal file
15
vendor/cloud.google.com/go/AUTHORS
generated
vendored
Normal file
@ -0,0 +1,15 @@
|
||||
# This is the official list of cloud authors for copyright purposes.
|
||||
# This file is distinct from the CONTRIBUTORS files.
|
||||
# See the latter for an explanation.
|
||||
|
||||
# Names should be added to this file as:
|
||||
# Name or Organization <email address>
|
||||
# The email address is not required for organizations.
|
||||
|
||||
Filippo Valsorda <hi@filippo.io>
|
||||
Google Inc.
|
||||
Ingo Oeser <nightlyone@googlemail.com>
|
||||
Palm Stone Games, Inc.
|
||||
Paweł Knap <pawelknap88@gmail.com>
|
||||
Péter Szilágyi <peterke@gmail.com>
|
||||
Tyler Treat <ttreat31@gmail.com>
|
34
vendor/cloud.google.com/go/CONTRIBUTORS
generated
vendored
Normal file
34
vendor/cloud.google.com/go/CONTRIBUTORS
generated
vendored
Normal file
@ -0,0 +1,34 @@
|
||||
# People who have agreed to one of the CLAs and can contribute patches.
|
||||
# The AUTHORS file lists the copyright holders; this file
|
||||
# lists people. For example, Google employees are listed here
|
||||
# but not in AUTHORS, because Google holds the copyright.
|
||||
#
|
||||
# https://developers.google.com/open-source/cla/individual
|
||||
# https://developers.google.com/open-source/cla/corporate
|
||||
#
|
||||
# Names should be added to this file as:
|
||||
# Name <email address>
|
||||
|
||||
# Keep the list alphabetically sorted.
|
||||
|
||||
Andreas Litt <andreas.litt@gmail.com>
|
||||
Andrew Gerrand <adg@golang.org>
|
||||
Brad Fitzpatrick <bradfitz@golang.org>
|
||||
Burcu Dogan <jbd@google.com>
|
||||
Dave Day <djd@golang.org>
|
||||
David Sansome <me@davidsansome.com>
|
||||
David Symonds <dsymonds@golang.org>
|
||||
Filippo Valsorda <hi@filippo.io>
|
||||
Glenn Lewis <gmlewis@google.com>
|
||||
Ingo Oeser <nightlyone@googlemail.com>
|
||||
Johan Euphrosine <proppy@google.com>
|
||||
Jonathan Amsterdam <jba@google.com>
|
||||
Luna Duclos <luna.duclos@palmstonegames.com>
|
||||
Michael McGreevy <mcgreevy@golang.org>
|
||||
Omar Jarjur <ojarjur@google.com>
|
||||
Paweł Knap <pawelknap88@gmail.com>
|
||||
Péter Szilágyi <peterke@gmail.com>
|
||||
Sarah Adams <shadams@google.com>
|
||||
Toby Burress <kurin@google.com>
|
||||
Tuo Shan <shantuo@google.com>
|
||||
Tyler Treat <ttreat31@gmail.com>
|
202
vendor/cloud.google.com/go/LICENSE
generated
vendored
Normal file
202
vendor/cloud.google.com/go/LICENSE
generated
vendored
Normal file
@ -0,0 +1,202 @@
|
||||
|
||||
Apache License
|
||||
Version 2.0, January 2004
|
||||
http://www.apache.org/licenses/
|
||||
|
||||
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||
|
||||
1. Definitions.
|
||||
|
||||
"License" shall mean the terms and conditions for use, reproduction,
|
||||
and distribution as defined by Sections 1 through 9 of this document.
|
||||
|
||||
"Licensor" shall mean the copyright owner or entity authorized by
|
||||
the copyright owner that is granting the License.
|
||||
|
||||
"Legal Entity" shall mean the union of the acting entity and all
|
||||
other entities that control, are controlled by, or are under common
|
||||
control with that entity. For the purposes of this definition,
|
||||
"control" means (i) the power, direct or indirect, to cause the
|
||||
direction or management of such entity, whether by contract or
|
||||
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||
|
||||
"You" (or "Your") shall mean an individual or Legal Entity
|
||||
exercising permissions granted by this License.
|
||||
|
||||
"Source" form shall mean the preferred form for making modifications,
|
||||
including but not limited to software source code, documentation
|
||||
source, and configuration files.
|
||||
|
||||
"Object" form shall mean any form resulting from mechanical
|
||||
transformation or translation of a Source form, including but
|
||||
not limited to compiled object code, generated documentation,
|
||||
and conversions to other media types.
|
||||
|
||||
"Work" shall mean the work of authorship, whether in Source or
|
||||
Object form, made available under the License, as indicated by a
|
||||
copyright notice that is included in or attached to the work
|
||||
(an example is provided in the Appendix below).
|
||||
|
||||
"Derivative Works" shall mean any work, whether in Source or Object
|
||||
form, that is based on (or derived from) the Work and for which the
|
||||
editorial revisions, annotations, elaborations, or other modifications
|
||||
represent, as a whole, an original work of authorship. For the purposes
|
||||
of this License, Derivative Works shall not include works that remain
|
||||
separable from, or merely link (or bind by name) to the interfaces of,
|
||||
the Work and Derivative Works thereof.
|
||||
|
||||
"Contribution" shall mean any work of authorship, including
|
||||
the original version of the Work and any modifications or additions
|
||||
to that Work or Derivative Works thereof, that is intentionally
|
||||
submitted to Licensor for inclusion in the Work by the copyright owner
|
||||
or by an individual or Legal Entity authorized to submit on behalf of
|
||||
the copyright owner. For the purposes of this definition, "submitted"
|
||||
means any form of electronic, verbal, or written communication sent
|
||||
to the Licensor or its representatives, including but not limited to
|
||||
communication on electronic mailing lists, source code control systems,
|
||||
and issue tracking systems that are managed by, or on behalf of, the
|
||||
Licensor for the purpose of discussing and improving the Work, but
|
||||
excluding communication that is conspicuously marked or otherwise
|
||||
designated in writing by the copyright owner as "Not a Contribution."
|
||||
|
||||
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||||
on behalf of whom a Contribution has been received by Licensor and
|
||||
subsequently incorporated within the Work.
|
||||
|
||||
2. Grant of Copyright License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
copyright license to reproduce, prepare Derivative Works of,
|
||||
publicly display, publicly perform, sublicense, and distribute the
|
||||
Work and such Derivative Works in Source or Object form.
|
||||
|
||||
3. Grant of Patent License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
(except as stated in this section) patent license to make, have made,
|
||||
use, offer to sell, sell, import, and otherwise transfer the Work,
|
||||
where such license applies only to those patent claims licensable
|
||||
by such Contributor that are necessarily infringed by their
|
||||
Contribution(s) alone or by combination of their Contribution(s)
|
||||
with the Work to which such Contribution(s) was submitted. If You
|
||||
institute patent litigation against any entity (including a
|
||||
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
||||
or a Contribution incorporated within the Work constitutes direct
|
||||
or contributory patent infringement, then any patent licenses
|
||||
granted to You under this License for that Work shall terminate
|
||||
as of the date such litigation is filed.
|
||||
|
||||
4. Redistribution. You may reproduce and distribute copies of the
|
||||
Work or Derivative Works thereof in any medium, with or without
|
||||
modifications, and in Source or Object form, provided that You
|
||||
meet the following conditions:
|
||||
|
||||
(a) You must give any other recipients of the Work or
|
||||
Derivative Works a copy of this License; and
|
||||
|
||||
(b) You must cause any modified files to carry prominent notices
|
||||
stating that You changed the files; and
|
||||
|
||||
(c) You must retain, in the Source form of any Derivative Works
|
||||
that You distribute, all copyright, patent, trademark, and
|
||||
attribution notices from the Source form of the Work,
|
||||
excluding those notices that do not pertain to any part of
|
||||
the Derivative Works; and
|
||||
|
||||
(d) If the Work includes a "NOTICE" text file as part of its
|
||||
distribution, then any Derivative Works that You distribute must
|
||||
include a readable copy of the attribution notices contained
|
||||
within such NOTICE file, excluding those notices that do not
|
||||
pertain to any part of the Derivative Works, in at least one
|
||||
of the following places: within a NOTICE text file distributed
|
||||
as part of the Derivative Works; within the Source form or
|
||||
documentation, if provided along with the Derivative Works; or,
|
||||
within a display generated by the Derivative Works, if and
|
||||
wherever such third-party notices normally appear. The contents
|
||||
of the NOTICE file are for informational purposes only and
|
||||
do not modify the License. You may add Your own attribution
|
||||
notices within Derivative Works that You distribute, alongside
|
||||
or as an addendum to the NOTICE text from the Work, provided
|
||||
that such additional attribution notices cannot be construed
|
||||
as modifying the License.
|
||||
|
||||
You may add Your own copyright statement to Your modifications and
|
||||
may provide additional or different license terms and conditions
|
||||
for use, reproduction, or distribution of Your modifications, or
|
||||
for any such Derivative Works as a whole, provided Your use,
|
||||
reproduction, and distribution of the Work otherwise complies with
|
||||
the conditions stated in this License.
|
||||
|
||||
5. Submission of Contributions. Unless You explicitly state otherwise,
|
||||
any Contribution intentionally submitted for inclusion in the Work
|
||||
by You to the Licensor shall be under the terms and conditions of
|
||||
this License, without any additional terms or conditions.
|
||||
Notwithstanding the above, nothing herein shall supersede or modify
|
||||
the terms of any separate license agreement you may have executed
|
||||
with Licensor regarding such Contributions.
|
||||
|
||||
6. Trademarks. This License does not grant permission to use the trade
|
||||
names, trademarks, service marks, or product names of the Licensor,
|
||||
except as required for reasonable and customary use in describing the
|
||||
origin of the Work and reproducing the content of the NOTICE file.
|
||||
|
||||
7. Disclaimer of Warranty. Unless required by applicable law or
|
||||
agreed to in writing, Licensor provides the Work (and each
|
||||
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||
implied, including, without limitation, any warranties or conditions
|
||||
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||
appropriateness of using or redistributing the Work and assume any
|
||||
risks associated with Your exercise of permissions under this License.
|
||||
|
||||
8. Limitation of Liability. In no event and under no legal theory,
|
||||
whether in tort (including negligence), contract, or otherwise,
|
||||
unless required by applicable law (such as deliberate and grossly
|
||||
negligent acts) or agreed to in writing, shall any Contributor be
|
||||
liable to You for damages, including any direct, indirect, special,
|
||||
incidental, or consequential damages of any character arising as a
|
||||
result of this License or out of the use or inability to use the
|
||||
Work (including but not limited to damages for loss of goodwill,
|
||||
work stoppage, computer failure or malfunction, or any and all
|
||||
other commercial damages or losses), even if such Contributor
|
||||
has been advised of the possibility of such damages.
|
||||
|
||||
9. Accepting Warranty or Additional Liability. While redistributing
|
||||
the Work or Derivative Works thereof, You may choose to offer,
|
||||
and charge a fee for, acceptance of support, warranty, indemnity,
|
||||
or other liability obligations and/or rights consistent with this
|
||||
License. However, in accepting such obligations, You may act only
|
||||
on Your own behalf and on Your sole responsibility, not on behalf
|
||||
of any other Contributor, and only if You agree to indemnify,
|
||||
defend, and hold each Contributor harmless for any liability
|
||||
incurred by, or claims asserted against, such Contributor by reason
|
||||
of your accepting any such warranty or additional liability.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
APPENDIX: How to apply the Apache License to your work.
|
||||
|
||||
To apply the Apache License to your work, attach the following
|
||||
boilerplate notice, with the fields enclosed by brackets "[]"
|
||||
replaced with your own identifying information. (Don't include
|
||||
the brackets!) The text should be enclosed in the appropriate
|
||||
comment syntax for the file format. We also recommend that a
|
||||
file or class name and description of purpose be included on the
|
||||
same "printed page" as the copyright notice for easier
|
||||
identification within third-party archives.
|
||||
|
||||
Copyright 2014 Google Inc.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
438
vendor/cloud.google.com/go/compute/metadata/metadata.go
generated
vendored
Normal file
438
vendor/cloud.google.com/go/compute/metadata/metadata.go
generated
vendored
Normal file
@ -0,0 +1,438 @@
|
||||
// Copyright 2014 Google Inc. All Rights Reserved.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
// Package metadata provides access to Google Compute Engine (GCE)
|
||||
// metadata and API service accounts.
|
||||
//
|
||||
// This package is a wrapper around the GCE metadata service,
|
||||
// as documented at https://developers.google.com/compute/docs/metadata.
|
||||
package metadata
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"net"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"os"
|
||||
"runtime"
|
||||
"strings"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"golang.org/x/net/context"
|
||||
"golang.org/x/net/context/ctxhttp"
|
||||
|
||||
"cloud.google.com/go/internal"
|
||||
)
|
||||
|
||||
const (
|
||||
// metadataIP is the documented metadata server IP address.
|
||||
metadataIP = "169.254.169.254"
|
||||
|
||||
// metadataHostEnv is the environment variable specifying the
|
||||
// GCE metadata hostname. If empty, the default value of
|
||||
// metadataIP ("169.254.169.254") is used instead.
|
||||
// This is variable name is not defined by any spec, as far as
|
||||
// I know; it was made up for the Go package.
|
||||
metadataHostEnv = "GCE_METADATA_HOST"
|
||||
)
|
||||
|
||||
type cachedValue struct {
|
||||
k string
|
||||
trim bool
|
||||
mu sync.Mutex
|
||||
v string
|
||||
}
|
||||
|
||||
var (
|
||||
projID = &cachedValue{k: "project/project-id", trim: true}
|
||||
projNum = &cachedValue{k: "project/numeric-project-id", trim: true}
|
||||
instID = &cachedValue{k: "instance/id", trim: true}
|
||||
)
|
||||
|
||||
var (
|
||||
metaClient = &http.Client{
|
||||
Transport: &internal.Transport{
|
||||
Base: &http.Transport{
|
||||
Dial: (&net.Dialer{
|
||||
Timeout: 2 * time.Second,
|
||||
KeepAlive: 30 * time.Second,
|
||||
}).Dial,
|
||||
ResponseHeaderTimeout: 2 * time.Second,
|
||||
},
|
||||
},
|
||||
}
|
||||
subscribeClient = &http.Client{
|
||||
Transport: &internal.Transport{
|
||||
Base: &http.Transport{
|
||||
Dial: (&net.Dialer{
|
||||
Timeout: 2 * time.Second,
|
||||
KeepAlive: 30 * time.Second,
|
||||
}).Dial,
|
||||
},
|
||||
},
|
||||
}
|
||||
)
|
||||
|
||||
// NotDefinedError is returned when requested metadata is not defined.
|
||||
//
|
||||
// The underlying string is the suffix after "/computeMetadata/v1/".
|
||||
//
|
||||
// This error is not returned if the value is defined to be the empty
|
||||
// string.
|
||||
type NotDefinedError string
|
||||
|
||||
func (suffix NotDefinedError) Error() string {
|
||||
return fmt.Sprintf("metadata: GCE metadata %q not defined", string(suffix))
|
||||
}
|
||||
|
||||
// Get returns a value from the metadata service.
|
||||
// The suffix is appended to "http://${GCE_METADATA_HOST}/computeMetadata/v1/".
|
||||
//
|
||||
// If the GCE_METADATA_HOST environment variable is not defined, a default of
|
||||
// 169.254.169.254 will be used instead.
|
||||
//
|
||||
// If the requested metadata is not defined, the returned error will
|
||||
// be of type NotDefinedError.
|
||||
func Get(suffix string) (string, error) {
|
||||
val, _, err := getETag(metaClient, suffix)
|
||||
return val, err
|
||||
}
|
||||
|
||||
// getETag returns a value from the metadata service as well as the associated
|
||||
// ETag using the provided client. This func is otherwise equivalent to Get.
|
||||
func getETag(client *http.Client, suffix string) (value, etag string, err error) {
|
||||
// Using a fixed IP makes it very difficult to spoof the metadata service in
|
||||
// a container, which is an important use-case for local testing of cloud
|
||||
// deployments. To enable spoofing of the metadata service, the environment
|
||||
// variable GCE_METADATA_HOST is first inspected to decide where metadata
|
||||
// requests shall go.
|
||||
host := os.Getenv(metadataHostEnv)
|
||||
if host == "" {
|
||||
// Using 169.254.169.254 instead of "metadata" here because Go
|
||||
// binaries built with the "netgo" tag and without cgo won't
|
||||
// know the search suffix for "metadata" is
|
||||
// ".google.internal", and this IP address is documented as
|
||||
// being stable anyway.
|
||||
host = metadataIP
|
||||
}
|
||||
url := "http://" + host + "/computeMetadata/v1/" + suffix
|
||||
req, _ := http.NewRequest("GET", url, nil)
|
||||
req.Header.Set("Metadata-Flavor", "Google")
|
||||
res, err := client.Do(req)
|
||||
if err != nil {
|
||||
return "", "", err
|
||||
}
|
||||
defer res.Body.Close()
|
||||
if res.StatusCode == http.StatusNotFound {
|
||||
return "", "", NotDefinedError(suffix)
|
||||
}
|
||||
if res.StatusCode != 200 {
|
||||
return "", "", fmt.Errorf("status code %d trying to fetch %s", res.StatusCode, url)
|
||||
}
|
||||
all, err := ioutil.ReadAll(res.Body)
|
||||
if err != nil {
|
||||
return "", "", err
|
||||
}
|
||||
return string(all), res.Header.Get("Etag"), nil
|
||||
}
|
||||
|
||||
func getTrimmed(suffix string) (s string, err error) {
|
||||
s, err = Get(suffix)
|
||||
s = strings.TrimSpace(s)
|
||||
return
|
||||
}
|
||||
|
||||
func (c *cachedValue) get() (v string, err error) {
|
||||
defer c.mu.Unlock()
|
||||
c.mu.Lock()
|
||||
if c.v != "" {
|
||||
return c.v, nil
|
||||
}
|
||||
if c.trim {
|
||||
v, err = getTrimmed(c.k)
|
||||
} else {
|
||||
v, err = Get(c.k)
|
||||
}
|
||||
if err == nil {
|
||||
c.v = v
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
var (
|
||||
onGCEOnce sync.Once
|
||||
onGCE bool
|
||||
)
|
||||
|
||||
// OnGCE reports whether this process is running on Google Compute Engine.
|
||||
func OnGCE() bool {
|
||||
onGCEOnce.Do(initOnGCE)
|
||||
return onGCE
|
||||
}
|
||||
|
||||
func initOnGCE() {
|
||||
onGCE = testOnGCE()
|
||||
}
|
||||
|
||||
func testOnGCE() bool {
|
||||
// The user explicitly said they're on GCE, so trust them.
|
||||
if os.Getenv(metadataHostEnv) != "" {
|
||||
return true
|
||||
}
|
||||
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
defer cancel()
|
||||
|
||||
resc := make(chan bool, 2)
|
||||
|
||||
// Try two strategies in parallel.
|
||||
// See https://github.com/GoogleCloudPlatform/google-cloud-go/issues/194
|
||||
go func() {
|
||||
res, err := ctxhttp.Get(ctx, metaClient, "http://"+metadataIP)
|
||||
if err != nil {
|
||||
resc <- false
|
||||
return
|
||||
}
|
||||
defer res.Body.Close()
|
||||
resc <- res.Header.Get("Metadata-Flavor") == "Google"
|
||||
}()
|
||||
|
||||
go func() {
|
||||
addrs, err := net.LookupHost("metadata.google.internal")
|
||||
if err != nil || len(addrs) == 0 {
|
||||
resc <- false
|
||||
return
|
||||
}
|
||||
resc <- strsContains(addrs, metadataIP)
|
||||
}()
|
||||
|
||||
tryHarder := systemInfoSuggestsGCE()
|
||||
if tryHarder {
|
||||
res := <-resc
|
||||
if res {
|
||||
// The first strategy succeeded, so let's use it.
|
||||
return true
|
||||
}
|
||||
// Wait for either the DNS or metadata server probe to
|
||||
// contradict the other one and say we are running on
|
||||
// GCE. Give it a lot of time to do so, since the system
|
||||
// info already suggests we're running on a GCE BIOS.
|
||||
timer := time.NewTimer(5 * time.Second)
|
||||
defer timer.Stop()
|
||||
select {
|
||||
case res = <-resc:
|
||||
return res
|
||||
case <-timer.C:
|
||||
// Too slow. Who knows what this system is.
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
// There's no hint from the system info that we're running on
|
||||
// GCE, so use the first probe's result as truth, whether it's
|
||||
// true or false. The goal here is to optimize for speed for
|
||||
// users who are NOT running on GCE. We can't assume that
|
||||
// either a DNS lookup or an HTTP request to a blackholed IP
|
||||
// address is fast. Worst case this should return when the
|
||||
// metaClient's Transport.ResponseHeaderTimeout or
|
||||
// Transport.Dial.Timeout fires (in two seconds).
|
||||
return <-resc
|
||||
}
|
||||
|
||||
// systemInfoSuggestsGCE reports whether the local system (without
|
||||
// doing network requests) suggests that we're running on GCE. If this
|
||||
// returns true, testOnGCE tries a bit harder to reach its metadata
|
||||
// server.
|
||||
func systemInfoSuggestsGCE() bool {
|
||||
if runtime.GOOS != "linux" {
|
||||
// We don't have any non-Linux clues available, at least yet.
|
||||
return false
|
||||
}
|
||||
slurp, _ := ioutil.ReadFile("/sys/class/dmi/id/product_name")
|
||||
name := strings.TrimSpace(string(slurp))
|
||||
return name == "Google" || name == "Google Compute Engine"
|
||||
}
|
||||
|
||||
// Subscribe subscribes to a value from the metadata service.
|
||||
// The suffix is appended to "http://${GCE_METADATA_HOST}/computeMetadata/v1/".
|
||||
// The suffix may contain query parameters.
|
||||
//
|
||||
// Subscribe calls fn with the latest metadata value indicated by the provided
|
||||
// suffix. If the metadata value is deleted, fn is called with the empty string
|
||||
// and ok false. Subscribe blocks until fn returns a non-nil error or the value
|
||||
// is deleted. Subscribe returns the error value returned from the last call to
|
||||
// fn, which may be nil when ok == false.
|
||||
func Subscribe(suffix string, fn func(v string, ok bool) error) error {
|
||||
const failedSubscribeSleep = time.Second * 5
|
||||
|
||||
// First check to see if the metadata value exists at all.
|
||||
val, lastETag, err := getETag(subscribeClient, suffix)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := fn(val, true); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
ok := true
|
||||
if strings.ContainsRune(suffix, '?') {
|
||||
suffix += "&wait_for_change=true&last_etag="
|
||||
} else {
|
||||
suffix += "?wait_for_change=true&last_etag="
|
||||
}
|
||||
for {
|
||||
val, etag, err := getETag(subscribeClient, suffix+url.QueryEscape(lastETag))
|
||||
if err != nil {
|
||||
if _, deleted := err.(NotDefinedError); !deleted {
|
||||
time.Sleep(failedSubscribeSleep)
|
||||
continue // Retry on other errors.
|
||||
}
|
||||
ok = false
|
||||
}
|
||||
lastETag = etag
|
||||
|
||||
if err := fn(val, ok); err != nil || !ok {
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ProjectID returns the current instance's project ID string.
|
||||
func ProjectID() (string, error) { return projID.get() }
|
||||
|
||||
// NumericProjectID returns the current instance's numeric project ID.
|
||||
func NumericProjectID() (string, error) { return projNum.get() }
|
||||
|
||||
// InternalIP returns the instance's primary internal IP address.
|
||||
func InternalIP() (string, error) {
|
||||
return getTrimmed("instance/network-interfaces/0/ip")
|
||||
}
|
||||
|
||||
// ExternalIP returns the instance's primary external (public) IP address.
|
||||
func ExternalIP() (string, error) {
|
||||
return getTrimmed("instance/network-interfaces/0/access-configs/0/external-ip")
|
||||
}
|
||||
|
||||
// Hostname returns the instance's hostname. This will be of the form
|
||||
// "<instanceID>.c.<projID>.internal".
|
||||
func Hostname() (string, error) {
|
||||
return getTrimmed("instance/hostname")
|
||||
}
|
||||
|
||||
// InstanceTags returns the list of user-defined instance tags,
|
||||
// assigned when initially creating a GCE instance.
|
||||
func InstanceTags() ([]string, error) {
|
||||
var s []string
|
||||
j, err := Get("instance/tags")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if err := json.NewDecoder(strings.NewReader(j)).Decode(&s); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return s, nil
|
||||
}
|
||||
|
||||
// InstanceID returns the current VM's numeric instance ID.
|
||||
func InstanceID() (string, error) {
|
||||
return instID.get()
|
||||
}
|
||||
|
||||
// InstanceName returns the current VM's instance ID string.
|
||||
func InstanceName() (string, error) {
|
||||
host, err := Hostname()
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
return strings.Split(host, ".")[0], nil
|
||||
}
|
||||
|
||||
// Zone returns the current VM's zone, such as "us-central1-b".
|
||||
func Zone() (string, error) {
|
||||
zone, err := getTrimmed("instance/zone")
|
||||
// zone is of the form "projects/<projNum>/zones/<zoneName>".
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
return zone[strings.LastIndex(zone, "/")+1:], nil
|
||||
}
|
||||
|
||||
// InstanceAttributes returns the list of user-defined attributes,
|
||||
// assigned when initially creating a GCE VM instance. The value of an
|
||||
// attribute can be obtained with InstanceAttributeValue.
|
||||
func InstanceAttributes() ([]string, error) { return lines("instance/attributes/") }
|
||||
|
||||
// ProjectAttributes returns the list of user-defined attributes
|
||||
// applying to the project as a whole, not just this VM. The value of
|
||||
// an attribute can be obtained with ProjectAttributeValue.
|
||||
func ProjectAttributes() ([]string, error) { return lines("project/attributes/") }
|
||||
|
||||
func lines(suffix string) ([]string, error) {
|
||||
j, err := Get(suffix)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
s := strings.Split(strings.TrimSpace(j), "\n")
|
||||
for i := range s {
|
||||
s[i] = strings.TrimSpace(s[i])
|
||||
}
|
||||
return s, nil
|
||||
}
|
||||
|
||||
// InstanceAttributeValue returns the value of the provided VM
|
||||
// instance attribute.
|
||||
//
|
||||
// If the requested attribute is not defined, the returned error will
|
||||
// be of type NotDefinedError.
|
||||
//
|
||||
// InstanceAttributeValue may return ("", nil) if the attribute was
|
||||
// defined to be the empty string.
|
||||
func InstanceAttributeValue(attr string) (string, error) {
|
||||
return Get("instance/attributes/" + attr)
|
||||
}
|
||||
|
||||
// ProjectAttributeValue returns the value of the provided
|
||||
// project attribute.
|
||||
//
|
||||
// If the requested attribute is not defined, the returned error will
|
||||
// be of type NotDefinedError.
|
||||
//
|
||||
// ProjectAttributeValue may return ("", nil) if the attribute was
|
||||
// defined to be the empty string.
|
||||
func ProjectAttributeValue(attr string) (string, error) {
|
||||
return Get("project/attributes/" + attr)
|
||||
}
|
||||
|
||||
// Scopes returns the service account scopes for the given account.
|
||||
// The account may be empty or the string "default" to use the instance's
|
||||
// main account.
|
||||
func Scopes(serviceAccount string) ([]string, error) {
|
||||
if serviceAccount == "" {
|
||||
serviceAccount = "default"
|
||||
}
|
||||
return lines("instance/service-accounts/" + serviceAccount + "/scopes")
|
||||
}
|
||||
|
||||
func strsContains(ss []string, s string) bool {
|
||||
for _, v := range ss {
|
||||
if v == s {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
64
vendor/cloud.google.com/go/internal/cloud.go
generated
vendored
Normal file
64
vendor/cloud.google.com/go/internal/cloud.go
generated
vendored
Normal file
@ -0,0 +1,64 @@
|
||||
// Copyright 2014 Google Inc. All Rights Reserved.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
// Package internal provides support for the cloud packages.
|
||||
//
|
||||
// Users should not import this package directly.
|
||||
package internal
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net/http"
|
||||
)
|
||||
|
||||
const userAgent = "gcloud-golang/0.1"
|
||||
|
||||
// Transport is an http.RoundTripper that appends Google Cloud client's
|
||||
// user-agent to the original request's user-agent header.
|
||||
type Transport struct {
|
||||
// TODO(bradfitz): delete internal.Transport. It's too wrappy for what it does.
|
||||
// Do User-Agent some other way.
|
||||
|
||||
// Base is the actual http.RoundTripper
|
||||
// requests will use. It must not be nil.
|
||||
Base http.RoundTripper
|
||||
}
|
||||
|
||||
// RoundTrip appends a user-agent to the existing user-agent
|
||||
// header and delegates the request to the base http.RoundTripper.
|
||||
func (t *Transport) RoundTrip(req *http.Request) (*http.Response, error) {
|
||||
req = cloneRequest(req)
|
||||
ua := req.Header.Get("User-Agent")
|
||||
if ua == "" {
|
||||
ua = userAgent
|
||||
} else {
|
||||
ua = fmt.Sprintf("%s %s", ua, userAgent)
|
||||
}
|
||||
req.Header.Set("User-Agent", ua)
|
||||
return t.Base.RoundTrip(req)
|
||||
}
|
||||
|
||||
// cloneRequest returns a clone of the provided *http.Request.
|
||||
// The clone is a shallow copy of the struct and its Header map.
|
||||
func cloneRequest(r *http.Request) *http.Request {
|
||||
// shallow copy of the struct
|
||||
r2 := new(http.Request)
|
||||
*r2 = *r
|
||||
// deep copy of the Header
|
||||
r2.Header = make(http.Header)
|
||||
for k, s := range r.Header {
|
||||
r2.Header[k] = s
|
||||
}
|
||||
return r2
|
||||
}
|
223
vendor/github.com/gophercloud/gophercloud/openstack/networking/v2/extensions/layer3/routers/requests.go
generated
vendored
Normal file
223
vendor/github.com/gophercloud/gophercloud/openstack/networking/v2/extensions/layer3/routers/requests.go
generated
vendored
Normal file
@ -0,0 +1,223 @@
|
||||
package routers
|
||||
|
||||
import (
|
||||
"github.com/gophercloud/gophercloud"
|
||||
"github.com/gophercloud/gophercloud/pagination"
|
||||
)
|
||||
|
||||
// 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 floating IP attributes you want to see returned. SortKey allows you to
|
||||
// sort by a particular network attribute. SortDir sets the direction, and is
|
||||
// either `asc' or `desc'. Marker and Limit are used for pagination.
|
||||
type ListOpts struct {
|
||||
ID string `q:"id"`
|
||||
Name string `q:"name"`
|
||||
AdminStateUp *bool `q:"admin_state_up"`
|
||||
Distributed *bool `q:"distributed"`
|
||||
Status string `q:"status"`
|
||||
TenantID string `q:"tenant_id"`
|
||||
Limit int `q:"limit"`
|
||||
Marker string `q:"marker"`
|
||||
SortKey string `q:"sort_key"`
|
||||
SortDir string `q:"sort_dir"`
|
||||
}
|
||||
|
||||
// List returns a Pager which allows you to iterate over a collection of
|
||||
// routers. It accepts a ListOpts struct, which allows you to filter and sort
|
||||
// the returned collection for greater efficiency.
|
||||
//
|
||||
// Default policy settings return only those routers that are owned by the
|
||||
// tenant who submits the request, unless an admin user submits the request.
|
||||
func List(c *gophercloud.ServiceClient, opts ListOpts) pagination.Pager {
|
||||
q, err := gophercloud.BuildQueryString(&opts)
|
||||
if err != nil {
|
||||
return pagination.Pager{Err: err}
|
||||
}
|
||||
u := rootURL(c) + q.String()
|
||||
return pagination.NewPager(c, u, func(r pagination.PageResult) pagination.Page {
|
||||
return RouterPage{pagination.LinkedPageBase{PageResult: r}}
|
||||
})
|
||||
}
|
||||
|
||||
// CreateOptsBuilder is the interface options structs have to satisfy in order
|
||||
// to be used in the main Create operation in this package. Since many
|
||||
// extensions decorate or modify the common logic, it is useful for them to
|
||||
// satisfy a basic interface in order for them to be used.
|
||||
type CreateOptsBuilder interface {
|
||||
ToRouterCreateMap() (map[string]interface{}, error)
|
||||
}
|
||||
|
||||
// CreateOpts contains all the values needed to create a new router. There are
|
||||
// no required values.
|
||||
type CreateOpts struct {
|
||||
Name string `json:"name,omitempty"`
|
||||
AdminStateUp *bool `json:"admin_state_up,omitempty"`
|
||||
Distributed *bool `json:"distributed,omitempty"`
|
||||
TenantID string `json:"tenant_id,omitempty"`
|
||||
GatewayInfo *GatewayInfo `json:"external_gateway_info,omitempty"`
|
||||
}
|
||||
|
||||
func (opts CreateOpts) ToRouterCreateMap() (map[string]interface{}, error) {
|
||||
return gophercloud.BuildRequestBody(opts, "router")
|
||||
}
|
||||
|
||||
// Create accepts a CreateOpts struct and uses the values to create a new
|
||||
// logical router. When it is created, the router does not have an internal
|
||||
// interface - it is not associated to any subnet.
|
||||
//
|
||||
// You can optionally specify an external gateway for a router using the
|
||||
// GatewayInfo struct. The external gateway for the router must be plugged into
|
||||
// an external network (it is external if its `router:external' field is set to
|
||||
// true).
|
||||
func Create(c *gophercloud.ServiceClient, opts CreateOptsBuilder) (r CreateResult) {
|
||||
b, err := opts.ToRouterCreateMap()
|
||||
if err != nil {
|
||||
r.Err = err
|
||||
return
|
||||
}
|
||||
_, r.Err = c.Post(rootURL(c), b, &r.Body, nil)
|
||||
return
|
||||
}
|
||||
|
||||
// Get retrieves a particular router based on its unique ID.
|
||||
func Get(c *gophercloud.ServiceClient, id string) (r GetResult) {
|
||||
_, r.Err = c.Get(resourceURL(c, id), &r.Body, nil)
|
||||
return
|
||||
}
|
||||
|
||||
type UpdateOptsBuilder interface {
|
||||
ToRouterUpdateMap() (map[string]interface{}, error)
|
||||
}
|
||||
|
||||
// UpdateOpts contains the values used when updating a router.
|
||||
type UpdateOpts struct {
|
||||
Name string `json:"name,omitempty"`
|
||||
AdminStateUp *bool `json:"admin_state_up,omitempty"`
|
||||
Distributed *bool `json:"distributed,omitempty"`
|
||||
GatewayInfo *GatewayInfo `json:"external_gateway_info,omitempty"`
|
||||
Routes []Route `json:"routes"`
|
||||
}
|
||||
|
||||
func (opts UpdateOpts) ToRouterUpdateMap() (map[string]interface{}, error) {
|
||||
return gophercloud.BuildRequestBody(opts, "router")
|
||||
}
|
||||
|
||||
// Update allows routers to be updated. You can update the name, administrative
|
||||
// state, and the external gateway. For more information about how to set the
|
||||
// external gateway for a router, see Create. This operation does not enable
|
||||
// the update of router interfaces. To do this, use the AddInterface and
|
||||
// RemoveInterface functions.
|
||||
func Update(c *gophercloud.ServiceClient, id string, opts UpdateOptsBuilder) (r UpdateResult) {
|
||||
b, err := opts.ToRouterUpdateMap()
|
||||
if err != nil {
|
||||
r.Err = err
|
||||
return
|
||||
}
|
||||
_, r.Err = c.Put(resourceURL(c, id), b, &r.Body, &gophercloud.RequestOpts{
|
||||
OkCodes: []int{200},
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
// Delete will permanently delete a particular router based on its unique ID.
|
||||
func Delete(c *gophercloud.ServiceClient, id string) (r DeleteResult) {
|
||||
_, r.Err = c.Delete(resourceURL(c, id), nil)
|
||||
return
|
||||
}
|
||||
|
||||
// AddInterfaceOptsBuilder is what types must satisfy to be used as AddInterface
|
||||
// options.
|
||||
type AddInterfaceOptsBuilder interface {
|
||||
ToRouterAddInterfaceMap() (map[string]interface{}, error)
|
||||
}
|
||||
|
||||
// AddInterfaceOpts allow you to work with operations that either add
|
||||
// an internal interface from a router.
|
||||
type AddInterfaceOpts struct {
|
||||
SubnetID string `json:"subnet_id,omitempty" xor:"PortID"`
|
||||
PortID string `json:"port_id,omitempty" xor:"SubnetID"`
|
||||
}
|
||||
|
||||
// ToRouterAddInterfaceMap allows InterfaceOpts to satisfy the InterfaceOptsBuilder
|
||||
// interface
|
||||
func (opts AddInterfaceOpts) ToRouterAddInterfaceMap() (map[string]interface{}, error) {
|
||||
return gophercloud.BuildRequestBody(opts, "")
|
||||
}
|
||||
|
||||
// AddInterface attaches a subnet to an internal router interface. You must
|
||||
// specify either a SubnetID or PortID in the request body. If you specify both,
|
||||
// the operation will fail and an error will be returned.
|
||||
//
|
||||
// If you specify a SubnetID, the gateway IP address for that particular subnet
|
||||
// is used to create the router interface. Alternatively, if you specify a
|
||||
// PortID, the IP address associated with the port is used to create the router
|
||||
// interface.
|
||||
//
|
||||
// If you reference a port that is associated with multiple IP addresses, or
|
||||
// if the port is associated with zero IP addresses, the operation will fail and
|
||||
// a 400 Bad Request error will be returned.
|
||||
//
|
||||
// If you reference a port already in use, the operation will fail and a 409
|
||||
// Conflict error will be returned.
|
||||
//
|
||||
// The PortID that is returned after using Extract() on the result of this
|
||||
// operation can either be the same PortID passed in or, on the other hand, the
|
||||
// identifier of a new port created by this operation. After the operation
|
||||
// completes, the device ID of the port is set to the router ID, and the
|
||||
// device owner attribute is set to `network:router_interface'.
|
||||
func AddInterface(c *gophercloud.ServiceClient, id string, opts AddInterfaceOptsBuilder) (r InterfaceResult) {
|
||||
b, err := opts.ToRouterAddInterfaceMap()
|
||||
if err != nil {
|
||||
r.Err = err
|
||||
return
|
||||
}
|
||||
_, r.Err = c.Put(addInterfaceURL(c, id), b, &r.Body, &gophercloud.RequestOpts{
|
||||
OkCodes: []int{200},
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
// RemoveInterfaceOptsBuilder is what types must satisfy to be used as RemoveInterface
|
||||
// options.
|
||||
type RemoveInterfaceOptsBuilder interface {
|
||||
ToRouterRemoveInterfaceMap() (map[string]interface{}, error)
|
||||
}
|
||||
|
||||
// RemoveInterfaceOpts allow you to work with operations that either add or remote
|
||||
// an internal interface from a router.
|
||||
type RemoveInterfaceOpts struct {
|
||||
SubnetID string `json:"subnet_id,omitempty" or:"PortID"`
|
||||
PortID string `json:"port_id,omitempty" or:"SubnetID"`
|
||||
}
|
||||
|
||||
// ToRouterRemoveInterfaceMap allows RemoveInterfaceOpts to satisfy the RemoveInterfaceOptsBuilder
|
||||
// interface
|
||||
func (opts RemoveInterfaceOpts) ToRouterRemoveInterfaceMap() (map[string]interface{}, error) {
|
||||
return gophercloud.BuildRequestBody(opts, "")
|
||||
}
|
||||
|
||||
// RemoveInterface removes an internal router interface, which detaches a
|
||||
// subnet from the router. You must specify either a SubnetID or PortID, since
|
||||
// these values are used to identify the router interface to remove.
|
||||
//
|
||||
// Unlike AddInterface, you can also specify both a SubnetID and PortID. If you
|
||||
// choose to specify both, the subnet ID must correspond to the subnet ID of
|
||||
// the first IP address on the port specified by the port ID. Otherwise, the
|
||||
// operation will fail and return a 409 Conflict error.
|
||||
//
|
||||
// If the router, subnet or port which are referenced do not exist or are not
|
||||
// visible to you, the operation will fail and a 404 Not Found error will be
|
||||
// returned. After this operation completes, the port connecting the router
|
||||
// with the subnet is removed from the subnet for the network.
|
||||
func RemoveInterface(c *gophercloud.ServiceClient, id string, opts RemoveInterfaceOptsBuilder) (r InterfaceResult) {
|
||||
b, err := opts.ToRouterRemoveInterfaceMap()
|
||||
if err != nil {
|
||||
r.Err = err
|
||||
return
|
||||
}
|
||||
_, r.Err = c.Put(removeInterfaceURL(c, id), b, &r.Body, &gophercloud.RequestOpts{
|
||||
OkCodes: []int{200},
|
||||
})
|
||||
return
|
||||
}
|
152
vendor/github.com/gophercloud/gophercloud/openstack/networking/v2/extensions/layer3/routers/results.go
generated
vendored
Normal file
152
vendor/github.com/gophercloud/gophercloud/openstack/networking/v2/extensions/layer3/routers/results.go
generated
vendored
Normal file
@ -0,0 +1,152 @@
|
||||
package routers
|
||||
|
||||
import (
|
||||
"github.com/gophercloud/gophercloud"
|
||||
"github.com/gophercloud/gophercloud/pagination"
|
||||
)
|
||||
|
||||
// GatewayInfo represents the information of an external gateway for any
|
||||
// particular network router.
|
||||
type GatewayInfo struct {
|
||||
NetworkID string `json:"network_id"`
|
||||
}
|
||||
|
||||
// Route is a possible route in a router.
|
||||
type Route struct {
|
||||
NextHop string `json:"nexthop"`
|
||||
DestinationCIDR string `json:"destination"`
|
||||
}
|
||||
|
||||
// Router represents a Neutron router. A router is a logical entity that
|
||||
// forwards packets across internal subnets and NATs (network address
|
||||
// translation) them on external networks through an appropriate gateway.
|
||||
//
|
||||
// A router has an interface for each subnet with which it is associated. By
|
||||
// default, the IP address of such interface is the subnet's gateway IP. Also,
|
||||
// whenever a router is associated with a subnet, a port for that router
|
||||
// interface is added to the subnet's network.
|
||||
type Router struct {
|
||||
// Indicates whether or not a router is currently operational.
|
||||
Status string `json:"status"`
|
||||
|
||||
// Information on external gateway for the router.
|
||||
GatewayInfo GatewayInfo `json:"external_gateway_info"`
|
||||
|
||||
// Administrative state of the router.
|
||||
AdminStateUp bool `json:"admin_state_up"`
|
||||
|
||||
// Whether router is disitrubted or not..
|
||||
Distributed bool `json:"distributed"`
|
||||
|
||||
// Human readable name for the router. Does not have to be unique.
|
||||
Name string `json:"name"`
|
||||
|
||||
// Unique identifier for the router.
|
||||
ID string `json:"id"`
|
||||
|
||||
// Owner of the router. Only admin users can specify a tenant identifier
|
||||
// other than its own.
|
||||
TenantID string `json:"tenant_id"`
|
||||
|
||||
Routes []Route `json:"routes"`
|
||||
}
|
||||
|
||||
// RouterPage is the page returned by a pager when traversing over a
|
||||
// collection of routers.
|
||||
type RouterPage struct {
|
||||
pagination.LinkedPageBase
|
||||
}
|
||||
|
||||
// NextPageURL is invoked when a paginated collection of routers has reached
|
||||
// the end of a page and the pager seeks to traverse over a new one. In order
|
||||
// to do this, it needs to construct the next page's URL.
|
||||
func (r RouterPage) NextPageURL() (string, error) {
|
||||
var s struct {
|
||||
Links []gophercloud.Link `json:"routers_links"`
|
||||
}
|
||||
err := r.ExtractInto(&s)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
return gophercloud.ExtractNextURL(s.Links)
|
||||
}
|
||||
|
||||
// IsEmpty checks whether a RouterPage struct is empty.
|
||||
func (r RouterPage) IsEmpty() (bool, error) {
|
||||
is, err := ExtractRouters(r)
|
||||
return len(is) == 0, err
|
||||
}
|
||||
|
||||
// ExtractRouters accepts a Page struct, specifically a RouterPage struct,
|
||||
// and extracts the elements into a slice of Router structs. In other words,
|
||||
// a generic collection is mapped into a relevant slice.
|
||||
func ExtractRouters(r pagination.Page) ([]Router, error) {
|
||||
var s struct {
|
||||
Routers []Router `json:"routers"`
|
||||
}
|
||||
err := (r.(RouterPage)).ExtractInto(&s)
|
||||
return s.Routers, err
|
||||
}
|
||||
|
||||
type commonResult struct {
|
||||
gophercloud.Result
|
||||
}
|
||||
|
||||
// Extract is a function that accepts a result and extracts a router.
|
||||
func (r commonResult) Extract() (*Router, error) {
|
||||
var s struct {
|
||||
Router *Router `json:"router"`
|
||||
}
|
||||
err := r.ExtractInto(&s)
|
||||
return s.Router, err
|
||||
}
|
||||
|
||||
// CreateResult represents the result of a create operation.
|
||||
type CreateResult struct {
|
||||
commonResult
|
||||
}
|
||||
|
||||
// GetResult represents the result of a get operation.
|
||||
type GetResult struct {
|
||||
commonResult
|
||||
}
|
||||
|
||||
// UpdateResult represents the result of an update operation.
|
||||
type UpdateResult struct {
|
||||
commonResult
|
||||
}
|
||||
|
||||
// DeleteResult represents the result of a delete operation.
|
||||
type DeleteResult struct {
|
||||
gophercloud.ErrResult
|
||||
}
|
||||
|
||||
// InterfaceInfo represents information about a particular router interface. As
|
||||
// mentioned above, in order for a router to forward to a subnet, it needs an
|
||||
// interface.
|
||||
type InterfaceInfo struct {
|
||||
// The ID of the subnet which this interface is associated with.
|
||||
SubnetID string `json:"subnet_id"`
|
||||
|
||||
// The ID of the port that is a part of the subnet.
|
||||
PortID string `json:"port_id"`
|
||||
|
||||
// The UUID of the interface.
|
||||
ID string `json:"id"`
|
||||
|
||||
// Owner of the interface.
|
||||
TenantID string `json:"tenant_id"`
|
||||
}
|
||||
|
||||
// InterfaceResult represents the result of interface operations, such as
|
||||
// AddInterface() and RemoveInterface().
|
||||
type InterfaceResult struct {
|
||||
gophercloud.Result
|
||||
}
|
||||
|
||||
// Extract is a function that accepts a result and extracts an information struct.
|
||||
func (r InterfaceResult) Extract() (*InterfaceInfo, error) {
|
||||
var s InterfaceInfo
|
||||
err := r.ExtractInto(&s)
|
||||
return &s, err
|
||||
}
|
21
vendor/github.com/gophercloud/gophercloud/openstack/networking/v2/extensions/layer3/routers/urls.go
generated
vendored
Normal file
21
vendor/github.com/gophercloud/gophercloud/openstack/networking/v2/extensions/layer3/routers/urls.go
generated
vendored
Normal file
@ -0,0 +1,21 @@
|
||||
package routers
|
||||
|
||||
import "github.com/gophercloud/gophercloud"
|
||||
|
||||
const resourcePath = "routers"
|
||||
|
||||
func rootURL(c *gophercloud.ServiceClient) string {
|
||||
return c.ServiceURL(resourcePath)
|
||||
}
|
||||
|
||||
func resourceURL(c *gophercloud.ServiceClient, id string) string {
|
||||
return c.ServiceURL(resourcePath, id)
|
||||
}
|
||||
|
||||
func addInterfaceURL(c *gophercloud.ServiceClient, id string) string {
|
||||
return c.ServiceURL(resourcePath, id, "add_router_interface")
|
||||
}
|
||||
|
||||
func removeInterfaceURL(c *gophercloud.ServiceClient, id string) string {
|
||||
return c.ServiceURL(resourcePath, id, "remove_router_interface")
|
||||
}
|
9
vendor/github.com/gophercloud/gophercloud/openstack/networking/v2/networks/doc.go
generated
vendored
Normal file
9
vendor/github.com/gophercloud/gophercloud/openstack/networking/v2/networks/doc.go
generated
vendored
Normal file
@ -0,0 +1,9 @@
|
||||
// Package networks contains functionality for working with Neutron network
|
||||
// resources. A network is an isolated virtual layer-2 broadcast domain that is
|
||||
// typically reserved for the tenant who created it (unless you configure the
|
||||
// network to be shared). Tenants can create multiple networks until the
|
||||
// thresholds per-tenant quota is reached.
|
||||
//
|
||||
// In the v2.0 Networking API, the network is the main entity. Ports and subnets
|
||||
// are always associated with a network.
|
||||
package networks
|
168
vendor/github.com/gophercloud/gophercloud/openstack/networking/v2/networks/requests.go
generated
vendored
Normal file
168
vendor/github.com/gophercloud/gophercloud/openstack/networking/v2/networks/requests.go
generated
vendored
Normal file
@ -0,0 +1,168 @@
|
||||
package networks
|
||||
|
||||
import (
|
||||
"github.com/gophercloud/gophercloud"
|
||||
"github.com/gophercloud/gophercloud/pagination"
|
||||
)
|
||||
|
||||
// ListOptsBuilder allows extensions to add additional parameters to the
|
||||
// List request.
|
||||
type ListOptsBuilder interface {
|
||||
ToNetworkListQuery() (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 network attributes you want to see returned. SortKey allows you to sort
|
||||
// by a particular network attribute. SortDir sets the direction, and is either
|
||||
// `asc' or `desc'. Marker and Limit are used for pagination.
|
||||
type ListOpts struct {
|
||||
Status string `q:"status"`
|
||||
Name string `q:"name"`
|
||||
AdminStateUp *bool `q:"admin_state_up"`
|
||||
TenantID string `q:"tenant_id"`
|
||||
Shared *bool `q:"shared"`
|
||||
ID string `q:"id"`
|
||||
Marker string `q:"marker"`
|
||||
Limit int `q:"limit"`
|
||||
SortKey string `q:"sort_key"`
|
||||
SortDir string `q:"sort_dir"`
|
||||
}
|
||||
|
||||
// ToNetworkListQuery formats a ListOpts into a query string.
|
||||
func (opts ListOpts) ToNetworkListQuery() (string, error) {
|
||||
q, err := gophercloud.BuildQueryString(opts)
|
||||
return q.String(), err
|
||||
}
|
||||
|
||||
// List returns a Pager which allows you to iterate over a collection of
|
||||
// networks. It accepts a ListOpts struct, which allows you to filter and sort
|
||||
// the returned collection for greater efficiency.
|
||||
func List(c *gophercloud.ServiceClient, opts ListOptsBuilder) pagination.Pager {
|
||||
url := listURL(c)
|
||||
if opts != nil {
|
||||
query, err := opts.ToNetworkListQuery()
|
||||
if err != nil {
|
||||
return pagination.Pager{Err: err}
|
||||
}
|
||||
url += query
|
||||
}
|
||||
return pagination.NewPager(c, url, func(r pagination.PageResult) pagination.Page {
|
||||
return NetworkPage{pagination.LinkedPageBase{PageResult: r}}
|
||||
})
|
||||
}
|
||||
|
||||
// Get retrieves a specific network based on its unique ID.
|
||||
func Get(c *gophercloud.ServiceClient, id string) (r GetResult) {
|
||||
_, r.Err = c.Get(getURL(c, id), &r.Body, nil)
|
||||
return
|
||||
}
|
||||
|
||||
// CreateOptsBuilder is the interface options structs have to satisfy in order
|
||||
// to be used in the main Create operation in this package. Since many
|
||||
// extensions decorate or modify the common logic, it is useful for them to
|
||||
// satisfy a basic interface in order for them to be used.
|
||||
type CreateOptsBuilder interface {
|
||||
ToNetworkCreateMap() (map[string]interface{}, error)
|
||||
}
|
||||
|
||||
// CreateOpts satisfies the CreateOptsBuilder interface
|
||||
type CreateOpts struct {
|
||||
AdminStateUp *bool `json:"admin_state_up,omitempty"`
|
||||
Name string `json:"name,omitempty"`
|
||||
Shared *bool `json:"shared,omitempty"`
|
||||
TenantID string `json:"tenant_id,omitempty"`
|
||||
}
|
||||
|
||||
// ToNetworkCreateMap casts a CreateOpts struct to a map.
|
||||
func (opts CreateOpts) ToNetworkCreateMap() (map[string]interface{}, error) {
|
||||
return gophercloud.BuildRequestBody(opts, "network")
|
||||
}
|
||||
|
||||
// Create accepts a CreateOpts struct and creates a new network using the values
|
||||
// provided. This operation does not actually require a request body, i.e. the
|
||||
// CreateOpts struct argument can be empty.
|
||||
//
|
||||
// The tenant ID that is contained in the URI is the tenant that creates the
|
||||
// network. An admin user, however, has the option of specifying another tenant
|
||||
// ID in the CreateOpts struct.
|
||||
func Create(c *gophercloud.ServiceClient, opts CreateOptsBuilder) (r CreateResult) {
|
||||
b, err := opts.ToNetworkCreateMap()
|
||||
if err != nil {
|
||||
r.Err = err
|
||||
return
|
||||
}
|
||||
_, r.Err = c.Post(createURL(c), b, &r.Body, nil)
|
||||
return
|
||||
}
|
||||
|
||||
// UpdateOptsBuilder is the interface options structs have to satisfy in order
|
||||
// to be used in the main Update operation in this package. Since many
|
||||
// extensions decorate or modify the common logic, it is useful for them to
|
||||
// satisfy a basic interface in order for them to be used.
|
||||
type UpdateOptsBuilder interface {
|
||||
ToNetworkUpdateMap() (map[string]interface{}, error)
|
||||
}
|
||||
|
||||
// UpdateOpts satisfies the UpdateOptsBuilder interface
|
||||
type UpdateOpts struct {
|
||||
AdminStateUp *bool `json:"admin_state_up,omitempty"`
|
||||
Name string `json:"name,omitempty"`
|
||||
Shared *bool `json:"shared,omitempty"`
|
||||
}
|
||||
|
||||
// ToNetworkUpdateMap casts a UpdateOpts struct to a map.
|
||||
func (opts UpdateOpts) ToNetworkUpdateMap() (map[string]interface{}, error) {
|
||||
return gophercloud.BuildRequestBody(opts, "network")
|
||||
}
|
||||
|
||||
// Update accepts a UpdateOpts struct and updates an existing network using the
|
||||
// values provided. For more information, see the Create function.
|
||||
func Update(c *gophercloud.ServiceClient, networkID string, opts UpdateOptsBuilder) (r UpdateResult) {
|
||||
b, err := opts.ToNetworkUpdateMap()
|
||||
if err != nil {
|
||||
r.Err = err
|
||||
return
|
||||
}
|
||||
_, r.Err = c.Put(updateURL(c, networkID), b, &r.Body, &gophercloud.RequestOpts{
|
||||
OkCodes: []int{200, 201},
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
// Delete accepts a unique ID and deletes the network associated with it.
|
||||
func Delete(c *gophercloud.ServiceClient, networkID string) (r DeleteResult) {
|
||||
_, r.Err = c.Delete(deleteURL(c, networkID), nil)
|
||||
return
|
||||
}
|
||||
|
||||
// IDFromName is a convenience function that returns a network's ID given its name.
|
||||
func IDFromName(client *gophercloud.ServiceClient, name string) (string, error) {
|
||||
count := 0
|
||||
id := ""
|
||||
pages, err := List(client, nil).AllPages()
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
all, err := ExtractNetworks(pages)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
for _, s := range all {
|
||||
if s.Name == name {
|
||||
count++
|
||||
id = s.ID
|
||||
}
|
||||
}
|
||||
|
||||
switch count {
|
||||
case 0:
|
||||
return "", gophercloud.ErrResourceNotFound{Name: name, ResourceType: "network"}
|
||||
case 1:
|
||||
return id, nil
|
||||
default:
|
||||
return "", gophercloud.ErrMultipleResourcesFound{Name: name, Count: count, ResourceType: "network"}
|
||||
}
|
||||
}
|
101
vendor/github.com/gophercloud/gophercloud/openstack/networking/v2/networks/results.go
generated
vendored
Normal file
101
vendor/github.com/gophercloud/gophercloud/openstack/networking/v2/networks/results.go
generated
vendored
Normal file
@ -0,0 +1,101 @@
|
||||
package networks
|
||||
|
||||
import (
|
||||
"github.com/gophercloud/gophercloud"
|
||||
"github.com/gophercloud/gophercloud/pagination"
|
||||
)
|
||||
|
||||
type commonResult struct {
|
||||
gophercloud.Result
|
||||
}
|
||||
|
||||
// Extract is a function that accepts a result and extracts a network resource.
|
||||
func (r commonResult) Extract() (*Network, error) {
|
||||
var s struct {
|
||||
Network *Network `json:"network"`
|
||||
}
|
||||
err := r.ExtractInto(&s)
|
||||
return s.Network, err
|
||||
}
|
||||
|
||||
// CreateResult represents the result of a create operation.
|
||||
type CreateResult struct {
|
||||
commonResult
|
||||
}
|
||||
|
||||
// GetResult represents the result of a get operation.
|
||||
type GetResult struct {
|
||||
commonResult
|
||||
}
|
||||
|
||||
// UpdateResult represents the result of an update operation.
|
||||
type UpdateResult struct {
|
||||
commonResult
|
||||
}
|
||||
|
||||
// DeleteResult represents the result of a delete operation.
|
||||
type DeleteResult struct {
|
||||
gophercloud.ErrResult
|
||||
}
|
||||
|
||||
// Network represents, well, a network.
|
||||
type Network struct {
|
||||
// UUID for the network
|
||||
ID string `json:"id"`
|
||||
|
||||
// Human-readable name for the network. Might not be unique.
|
||||
Name string `json:"name"`
|
||||
|
||||
// The administrative state of network. If false (down), the network does not forward packets.
|
||||
AdminStateUp bool `json:"admin_state_up"`
|
||||
|
||||
// Indicates whether network is currently operational. Possible values include
|
||||
// `ACTIVE', `DOWN', `BUILD', or `ERROR'. Plug-ins might define additional values.
|
||||
Status string `json:"status"`
|
||||
|
||||
// Subnets associated with this network.
|
||||
Subnets []string `json:"subnets"`
|
||||
|
||||
// Owner of network. Only admin users can specify a tenant_id other than its own.
|
||||
TenantID string `json:"tenant_id"`
|
||||
|
||||
// Specifies whether the network resource can be accessed by any tenant or not.
|
||||
Shared bool `json:"shared"`
|
||||
}
|
||||
|
||||
// NetworkPage is the page returned by a pager when traversing over a
|
||||
// collection of networks.
|
||||
type NetworkPage struct {
|
||||
pagination.LinkedPageBase
|
||||
}
|
||||
|
||||
// NextPageURL is invoked when a paginated collection of networks has reached
|
||||
// the end of a page and the pager seeks to traverse over a new one. In order
|
||||
// to do this, it needs to construct the next page's URL.
|
||||
func (r NetworkPage) NextPageURL() (string, error) {
|
||||
var s struct {
|
||||
Links []gophercloud.Link `json:"networks_links"`
|
||||
}
|
||||
err := r.ExtractInto(&s)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
return gophercloud.ExtractNextURL(s.Links)
|
||||
}
|
||||
|
||||
// IsEmpty checks whether a NetworkPage struct is empty.
|
||||
func (r NetworkPage) IsEmpty() (bool, error) {
|
||||
is, err := ExtractNetworks(r)
|
||||
return len(is) == 0, err
|
||||
}
|
||||
|
||||
// ExtractNetworks accepts a Page struct, specifically a NetworkPage struct,
|
||||
// and extracts the elements into a slice of Network structs. In other words,
|
||||
// a generic collection is mapped into a relevant slice.
|
||||
func ExtractNetworks(r pagination.Page) ([]Network, error) {
|
||||
var s struct {
|
||||
Networks []Network `json:"networks"`
|
||||
}
|
||||
err := (r.(NetworkPage)).ExtractInto(&s)
|
||||
return s.Networks, err
|
||||
}
|
31
vendor/github.com/gophercloud/gophercloud/openstack/networking/v2/networks/urls.go
generated
vendored
Normal file
31
vendor/github.com/gophercloud/gophercloud/openstack/networking/v2/networks/urls.go
generated
vendored
Normal file
@ -0,0 +1,31 @@
|
||||
package networks
|
||||
|
||||
import "github.com/gophercloud/gophercloud"
|
||||
|
||||
func resourceURL(c *gophercloud.ServiceClient, id string) string {
|
||||
return c.ServiceURL("networks", id)
|
||||
}
|
||||
|
||||
func rootURL(c *gophercloud.ServiceClient) string {
|
||||
return c.ServiceURL("networks")
|
||||
}
|
||||
|
||||
func getURL(c *gophercloud.ServiceClient, id string) string {
|
||||
return resourceURL(c, id)
|
||||
}
|
||||
|
||||
func listURL(c *gophercloud.ServiceClient) string {
|
||||
return rootURL(c)
|
||||
}
|
||||
|
||||
func createURL(c *gophercloud.ServiceClient) string {
|
||||
return rootURL(c)
|
||||
}
|
||||
|
||||
func updateURL(c *gophercloud.ServiceClient, id string) string {
|
||||
return resourceURL(c, id)
|
||||
}
|
||||
|
||||
func deleteURL(c *gophercloud.ServiceClient, id string) string {
|
||||
return resourceURL(c, id)
|
||||
}
|
8
vendor/github.com/gophercloud/gophercloud/openstack/networking/v2/ports/doc.go
generated
vendored
Normal file
8
vendor/github.com/gophercloud/gophercloud/openstack/networking/v2/ports/doc.go
generated
vendored
Normal file
@ -0,0 +1,8 @@
|
||||
// Package ports contains functionality for working with Neutron port resources.
|
||||
// A port represents a virtual switch port on a logical network switch. Virtual
|
||||
// instances attach their interfaces into ports. The logical port also defines
|
||||
// the MAC address and the IP address(es) to be assigned to the interfaces
|
||||
// plugged into them. When IP addresses are associated to a port, this also
|
||||
// implies the port is associated with a subnet, as the IP address was taken
|
||||
// from the allocation pool for a specific subnet.
|
||||
package ports
|
180
vendor/github.com/gophercloud/gophercloud/openstack/networking/v2/ports/requests.go
generated
vendored
Normal file
180
vendor/github.com/gophercloud/gophercloud/openstack/networking/v2/ports/requests.go
generated
vendored
Normal file
@ -0,0 +1,180 @@
|
||||
package ports
|
||||
|
||||
import (
|
||||
"github.com/gophercloud/gophercloud"
|
||||
"github.com/gophercloud/gophercloud/pagination"
|
||||
)
|
||||
|
||||
// ListOptsBuilder allows extensions to add additional parameters to the
|
||||
// List request.
|
||||
type ListOptsBuilder interface {
|
||||
ToPortListQuery() (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 port attributes you want to see returned. SortKey allows you to sort
|
||||
// by a particular port attribute. SortDir sets the direction, and is either
|
||||
// `asc' or `desc'. Marker and Limit are used for pagination.
|
||||
type ListOpts struct {
|
||||
Status string `q:"status"`
|
||||
Name string `q:"name"`
|
||||
AdminStateUp *bool `q:"admin_state_up"`
|
||||
NetworkID string `q:"network_id"`
|
||||
TenantID string `q:"tenant_id"`
|
||||
DeviceOwner string `q:"device_owner"`
|
||||
MACAddress string `q:"mac_address"`
|
||||
ID string `q:"id"`
|
||||
DeviceID string `q:"device_id"`
|
||||
Limit int `q:"limit"`
|
||||
Marker string `q:"marker"`
|
||||
SortKey string `q:"sort_key"`
|
||||
SortDir string `q:"sort_dir"`
|
||||
}
|
||||
|
||||
// ToPortListQuery formats a ListOpts into a query string.
|
||||
func (opts ListOpts) ToPortListQuery() (string, error) {
|
||||
q, err := gophercloud.BuildQueryString(opts)
|
||||
return q.String(), err
|
||||
}
|
||||
|
||||
// List returns a Pager which allows you to iterate over a collection of
|
||||
// ports. It accepts a ListOpts struct, which allows you to filter and sort
|
||||
// the returned collection for greater efficiency.
|
||||
//
|
||||
// Default policy settings return only those ports that are owned by the tenant
|
||||
// who submits the request, unless the request is submitted by a user with
|
||||
// administrative rights.
|
||||
func List(c *gophercloud.ServiceClient, opts ListOptsBuilder) pagination.Pager {
|
||||
url := listURL(c)
|
||||
if opts != nil {
|
||||
query, err := opts.ToPortListQuery()
|
||||
if err != nil {
|
||||
return pagination.Pager{Err: err}
|
||||
}
|
||||
url += query
|
||||
}
|
||||
return pagination.NewPager(c, url, func(r pagination.PageResult) pagination.Page {
|
||||
return PortPage{pagination.LinkedPageBase{PageResult: r}}
|
||||
})
|
||||
}
|
||||
|
||||
// Get retrieves a specific port based on its unique ID.
|
||||
func Get(c *gophercloud.ServiceClient, id string) (r GetResult) {
|
||||
_, r.Err = c.Get(getURL(c, id), &r.Body, nil)
|
||||
return
|
||||
}
|
||||
|
||||
// CreateOptsBuilder is the interface options structs have to satisfy in order
|
||||
// to be used in the main Create operation in this package. Since many
|
||||
// extensions decorate or modify the common logic, it is useful for them to
|
||||
// satisfy a basic interface in order for them to be used.
|
||||
type CreateOptsBuilder interface {
|
||||
ToPortCreateMap() (map[string]interface{}, error)
|
||||
}
|
||||
|
||||
// CreateOpts represents the attributes used when creating a new port.
|
||||
type CreateOpts struct {
|
||||
NetworkID string `json:"network_id" required:"true"`
|
||||
Name string `json:"name,omitempty"`
|
||||
AdminStateUp *bool `json:"admin_state_up,omitempty"`
|
||||
MACAddress string `json:"mac_address,omitempty"`
|
||||
FixedIPs interface{} `json:"fixed_ips,omitempty"`
|
||||
DeviceID string `json:"device_id,omitempty"`
|
||||
DeviceOwner string `json:"device_owner,omitempty"`
|
||||
TenantID string `json:"tenant_id,omitempty"`
|
||||
SecurityGroups []string `json:"security_groups,omitempty"`
|
||||
AllowedAddressPairs []AddressPair `json:"allowed_address_pairs,omitempty"`
|
||||
}
|
||||
|
||||
// ToPortCreateMap casts a CreateOpts struct to a map.
|
||||
func (opts CreateOpts) ToPortCreateMap() (map[string]interface{}, error) {
|
||||
return gophercloud.BuildRequestBody(opts, "port")
|
||||
}
|
||||
|
||||
// Create accepts a CreateOpts struct and creates a new network using the values
|
||||
// provided. You must remember to provide a NetworkID value.
|
||||
func Create(c *gophercloud.ServiceClient, opts CreateOptsBuilder) (r CreateResult) {
|
||||
b, err := opts.ToPortCreateMap()
|
||||
if err != nil {
|
||||
r.Err = err
|
||||
return
|
||||
}
|
||||
_, r.Err = c.Post(createURL(c), b, &r.Body, nil)
|
||||
return
|
||||
}
|
||||
|
||||
// UpdateOptsBuilder is the interface options structs have to satisfy in order
|
||||
// to be used in the main Update operation in this package. Since many
|
||||
// extensions decorate or modify the common logic, it is useful for them to
|
||||
// satisfy a basic interface in order for them to be used.
|
||||
type UpdateOptsBuilder interface {
|
||||
ToPortUpdateMap() (map[string]interface{}, error)
|
||||
}
|
||||
|
||||
// UpdateOpts represents the attributes used when updating an existing port.
|
||||
type UpdateOpts struct {
|
||||
Name string `json:"name,omitempty"`
|
||||
AdminStateUp *bool `json:"admin_state_up,omitempty"`
|
||||
FixedIPs interface{} `json:"fixed_ips,omitempty"`
|
||||
DeviceID string `json:"device_id,omitempty"`
|
||||
DeviceOwner string `json:"device_owner,omitempty"`
|
||||
SecurityGroups []string `json:"security_groups"`
|
||||
AllowedAddressPairs []AddressPair `json:"allowed_address_pairs"`
|
||||
}
|
||||
|
||||
// ToPortUpdateMap casts an UpdateOpts struct to a map.
|
||||
func (opts UpdateOpts) ToPortUpdateMap() (map[string]interface{}, error) {
|
||||
return gophercloud.BuildRequestBody(opts, "port")
|
||||
}
|
||||
|
||||
// Update accepts a UpdateOpts struct and updates an existing port using the
|
||||
// values provided.
|
||||
func Update(c *gophercloud.ServiceClient, id string, opts UpdateOptsBuilder) (r UpdateResult) {
|
||||
b, err := opts.ToPortUpdateMap()
|
||||
if err != nil {
|
||||
r.Err = err
|
||||
return
|
||||
}
|
||||
_, r.Err = c.Put(updateURL(c, id), b, &r.Body, &gophercloud.RequestOpts{
|
||||
OkCodes: []int{200, 201},
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
// Delete accepts a unique ID and deletes the port associated with it.
|
||||
func Delete(c *gophercloud.ServiceClient, id string) (r DeleteResult) {
|
||||
_, r.Err = c.Delete(deleteURL(c, id), nil)
|
||||
return
|
||||
}
|
||||
|
||||
// IDFromName is a convenience function that returns a port's ID given its name.
|
||||
func IDFromName(client *gophercloud.ServiceClient, name string) (string, error) {
|
||||
count := 0
|
||||
id := ""
|
||||
pages, err := List(client, nil).AllPages()
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
all, err := ExtractPorts(pages)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
for _, s := range all {
|
||||
if s.Name == name {
|
||||
count++
|
||||
id = s.ID
|
||||
}
|
||||
}
|
||||
|
||||
switch count {
|
||||
case 0:
|
||||
return "", gophercloud.ErrResourceNotFound{Name: name, ResourceType: "port"}
|
||||
case 1:
|
||||
return id, nil
|
||||
default:
|
||||
return "", gophercloud.ErrMultipleResourcesFound{Name: name, Count: count, ResourceType: "port"}
|
||||
}
|
||||
}
|
119
vendor/github.com/gophercloud/gophercloud/openstack/networking/v2/ports/results.go
generated
vendored
Normal file
119
vendor/github.com/gophercloud/gophercloud/openstack/networking/v2/ports/results.go
generated
vendored
Normal file
@ -0,0 +1,119 @@
|
||||
package ports
|
||||
|
||||
import (
|
||||
"github.com/gophercloud/gophercloud"
|
||||
"github.com/gophercloud/gophercloud/pagination"
|
||||
)
|
||||
|
||||
type commonResult struct {
|
||||
gophercloud.Result
|
||||
}
|
||||
|
||||
// Extract is a function that accepts a result and extracts a port resource.
|
||||
func (r commonResult) Extract() (*Port, error) {
|
||||
var s struct {
|
||||
Port *Port `json:"port"`
|
||||
}
|
||||
err := r.ExtractInto(&s)
|
||||
return s.Port, err
|
||||
}
|
||||
|
||||
// CreateResult represents the result of a create operation.
|
||||
type CreateResult struct {
|
||||
commonResult
|
||||
}
|
||||
|
||||
// GetResult represents the result of a get operation.
|
||||
type GetResult struct {
|
||||
commonResult
|
||||
}
|
||||
|
||||
// UpdateResult represents the result of an update operation.
|
||||
type UpdateResult struct {
|
||||
commonResult
|
||||
}
|
||||
|
||||
// DeleteResult represents the result of a delete operation.
|
||||
type DeleteResult struct {
|
||||
gophercloud.ErrResult
|
||||
}
|
||||
|
||||
// IP is a sub-struct that represents an individual IP.
|
||||
type IP struct {
|
||||
SubnetID string `json:"subnet_id"`
|
||||
IPAddress string `json:"ip_address,omitempty"`
|
||||
}
|
||||
|
||||
// AddressPair contains the IP Address and the MAC address.
|
||||
type AddressPair struct {
|
||||
IPAddress string `json:"ip_address,omitempty"`
|
||||
MACAddress string `json:"mac_address,omitempty"`
|
||||
}
|
||||
|
||||
// Port represents a Neutron port. See package documentation for a top-level
|
||||
// description of what this is.
|
||||
type Port struct {
|
||||
// UUID for the port.
|
||||
ID string `json:"id"`
|
||||
// Network that this port is associated with.
|
||||
NetworkID string `json:"network_id"`
|
||||
// Human-readable name for the port. Might not be unique.
|
||||
Name string `json:"name"`
|
||||
// Administrative state of port. If false (down), port does not forward packets.
|
||||
AdminStateUp bool `json:"admin_state_up"`
|
||||
// Indicates whether network is currently operational. Possible values include
|
||||
// `ACTIVE', `DOWN', `BUILD', or `ERROR'. Plug-ins might define additional values.
|
||||
Status string `json:"status"`
|
||||
// Mac address to use on this port.
|
||||
MACAddress string `json:"mac_address"`
|
||||
// Specifies IP addresses for the port thus associating the port itself with
|
||||
// the subnets where the IP addresses are picked from
|
||||
FixedIPs []IP `json:"fixed_ips"`
|
||||
// Owner of network. Only admin users can specify a tenant_id other than its own.
|
||||
TenantID string `json:"tenant_id"`
|
||||
// Identifies the entity (e.g.: dhcp agent) using this port.
|
||||
DeviceOwner string `json:"device_owner"`
|
||||
// Specifies the IDs of any security groups associated with a port.
|
||||
SecurityGroups []string `json:"security_groups"`
|
||||
// Identifies the device (e.g., virtual server) using this port.
|
||||
DeviceID string `json:"device_id"`
|
||||
// Identifies the list of IP addresses the port will recognize/accept
|
||||
AllowedAddressPairs []AddressPair `json:"allowed_address_pairs"`
|
||||
}
|
||||
|
||||
// PortPage is the page returned by a pager when traversing over a collection
|
||||
// of network ports.
|
||||
type PortPage struct {
|
||||
pagination.LinkedPageBase
|
||||
}
|
||||
|
||||
// NextPageURL is invoked when a paginated collection of ports has reached
|
||||
// the end of a page and the pager seeks to traverse over a new one. In order
|
||||
// to do this, it needs to construct the next page's URL.
|
||||
func (r PortPage) NextPageURL() (string, error) {
|
||||
var s struct {
|
||||
Links []gophercloud.Link `json:"ports_links"`
|
||||
}
|
||||
err := r.ExtractInto(&s)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
return gophercloud.ExtractNextURL(s.Links)
|
||||
}
|
||||
|
||||
// IsEmpty checks whether a PortPage struct is empty.
|
||||
func (r PortPage) IsEmpty() (bool, error) {
|
||||
is, err := ExtractPorts(r)
|
||||
return len(is) == 0, err
|
||||
}
|
||||
|
||||
// ExtractPorts accepts a Page struct, specifically a PortPage struct,
|
||||
// and extracts the elements into a slice of Port structs. In other words,
|
||||
// a generic collection is mapped into a relevant slice.
|
||||
func ExtractPorts(r pagination.Page) ([]Port, error) {
|
||||
var s struct {
|
||||
Ports []Port `json:"ports"`
|
||||
}
|
||||
err := (r.(PortPage)).ExtractInto(&s)
|
||||
return s.Ports, err
|
||||
}
|
31
vendor/github.com/gophercloud/gophercloud/openstack/networking/v2/ports/urls.go
generated
vendored
Normal file
31
vendor/github.com/gophercloud/gophercloud/openstack/networking/v2/ports/urls.go
generated
vendored
Normal file
@ -0,0 +1,31 @@
|
||||
package ports
|
||||
|
||||
import "github.com/gophercloud/gophercloud"
|
||||
|
||||
func resourceURL(c *gophercloud.ServiceClient, id string) string {
|
||||
return c.ServiceURL("ports", id)
|
||||
}
|
||||
|
||||
func rootURL(c *gophercloud.ServiceClient) string {
|
||||
return c.ServiceURL("ports")
|
||||
}
|
||||
|
||||
func listURL(c *gophercloud.ServiceClient) string {
|
||||
return rootURL(c)
|
||||
}
|
||||
|
||||
func getURL(c *gophercloud.ServiceClient, id string) string {
|
||||
return resourceURL(c, id)
|
||||
}
|
||||
|
||||
func createURL(c *gophercloud.ServiceClient) string {
|
||||
return rootURL(c)
|
||||
}
|
||||
|
||||
func updateURL(c *gophercloud.ServiceClient, id string) string {
|
||||
return resourceURL(c, id)
|
||||
}
|
||||
|
||||
func deleteURL(c *gophercloud.ServiceClient, id string) string {
|
||||
return resourceURL(c, id)
|
||||
}
|
10
vendor/github.com/gophercloud/gophercloud/openstack/networking/v2/subnets/doc.go
generated
vendored
Normal file
10
vendor/github.com/gophercloud/gophercloud/openstack/networking/v2/subnets/doc.go
generated
vendored
Normal file
@ -0,0 +1,10 @@
|
||||
// Package subnets contains functionality for working with Neutron subnet
|
||||
// resources. A subnet represents an IP address block that can be used to
|
||||
// assign IP addresses to virtual instances. Each subnet must have a CIDR and
|
||||
// must be associated with a network. IPs can either be selected from the whole
|
||||
// subnet CIDR or from allocation pools specified by the user.
|
||||
//
|
||||
// A subnet can also have a gateway, a list of DNS name servers, and host routes.
|
||||
// This information is pushed to instances whose interfaces are associated with
|
||||
// the subnet.
|
||||
package subnets
|
194
vendor/github.com/gophercloud/gophercloud/openstack/networking/v2/subnets/requests.go
generated
vendored
Normal file
194
vendor/github.com/gophercloud/gophercloud/openstack/networking/v2/subnets/requests.go
generated
vendored
Normal file
@ -0,0 +1,194 @@
|
||||
package subnets
|
||||
|
||||
import (
|
||||
"github.com/gophercloud/gophercloud"
|
||||
"github.com/gophercloud/gophercloud/pagination"
|
||||
)
|
||||
|
||||
// ListOptsBuilder allows extensions to add additional parameters to the
|
||||
// List request.
|
||||
type ListOptsBuilder interface {
|
||||
ToSubnetListQuery() (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 subnet attributes you want to see returned. SortKey allows you to sort
|
||||
// by a particular subnet attribute. SortDir sets the direction, and is either
|
||||
// `asc' or `desc'. Marker and Limit are used for pagination.
|
||||
type ListOpts struct {
|
||||
Name string `q:"name"`
|
||||
EnableDHCP *bool `q:"enable_dhcp"`
|
||||
NetworkID string `q:"network_id"`
|
||||
TenantID string `q:"tenant_id"`
|
||||
IPVersion int `q:"ip_version"`
|
||||
GatewayIP string `q:"gateway_ip"`
|
||||
CIDR string `q:"cidr"`
|
||||
ID string `q:"id"`
|
||||
Limit int `q:"limit"`
|
||||
Marker string `q:"marker"`
|
||||
SortKey string `q:"sort_key"`
|
||||
SortDir string `q:"sort_dir"`
|
||||
}
|
||||
|
||||
// ToSubnetListQuery formats a ListOpts into a query string.
|
||||
func (opts ListOpts) ToSubnetListQuery() (string, error) {
|
||||
q, err := gophercloud.BuildQueryString(opts)
|
||||
return q.String(), err
|
||||
}
|
||||
|
||||
// List returns a Pager which allows you to iterate over a collection of
|
||||
// subnets. It accepts a ListOpts struct, which allows you to filter and sort
|
||||
// the returned collection for greater efficiency.
|
||||
//
|
||||
// Default policy settings return only those subnets that are owned by the tenant
|
||||
// who submits the request, unless the request is submitted by a user with
|
||||
// administrative rights.
|
||||
func List(c *gophercloud.ServiceClient, opts ListOptsBuilder) pagination.Pager {
|
||||
url := listURL(c)
|
||||
if opts != nil {
|
||||
query, err := opts.ToSubnetListQuery()
|
||||
if err != nil {
|
||||
return pagination.Pager{Err: err}
|
||||
}
|
||||
url += query
|
||||
}
|
||||
return pagination.NewPager(c, url, func(r pagination.PageResult) pagination.Page {
|
||||
return SubnetPage{pagination.LinkedPageBase{PageResult: r}}
|
||||
})
|
||||
}
|
||||
|
||||
// Get retrieves a specific subnet based on its unique ID.
|
||||
func Get(c *gophercloud.ServiceClient, id string) (r GetResult) {
|
||||
_, r.Err = c.Get(getURL(c, id), &r.Body, nil)
|
||||
return
|
||||
}
|
||||
|
||||
// CreateOptsBuilder is the interface options structs have to satisfy in order
|
||||
// to be used in the main Create operation in this package. Since many
|
||||
// extensions decorate or modify the common logic, it is useful for them to
|
||||
// satisfy a basic interface in order for them to be used.
|
||||
type CreateOptsBuilder interface {
|
||||
ToSubnetCreateMap() (map[string]interface{}, error)
|
||||
}
|
||||
|
||||
// CreateOpts represents the attributes used when creating a new subnet.
|
||||
type CreateOpts struct {
|
||||
NetworkID string `json:"network_id" required:"true"`
|
||||
CIDR string `json:"cidr" required:"true"`
|
||||
Name string `json:"name,omitempty"`
|
||||
TenantID string `json:"tenant_id,omitempty"`
|
||||
AllocationPools []AllocationPool `json:"allocation_pools,omitempty"`
|
||||
GatewayIP *string `json:"gateway_ip,omitempty"`
|
||||
IPVersion gophercloud.IPVersion `json:"ip_version,omitempty"`
|
||||
EnableDHCP *bool `json:"enable_dhcp,omitempty"`
|
||||
DNSNameservers []string `json:"dns_nameservers,omitempty"`
|
||||
HostRoutes []HostRoute `json:"host_routes,omitempty"`
|
||||
}
|
||||
|
||||
// ToSubnetCreateMap casts a CreateOpts struct to a map.
|
||||
func (opts CreateOpts) ToSubnetCreateMap() (map[string]interface{}, error) {
|
||||
b, err := gophercloud.BuildRequestBody(opts, "subnet")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if m := b["subnet"].(map[string]interface{}); m["gateway_ip"] == "" {
|
||||
m["gateway_ip"] = nil
|
||||
}
|
||||
|
||||
return b, nil
|
||||
}
|
||||
|
||||
// Create accepts a CreateOpts struct and creates a new subnet using the values
|
||||
// provided. You must remember to provide a valid NetworkID, CIDR and IP version.
|
||||
func Create(c *gophercloud.ServiceClient, opts CreateOptsBuilder) (r CreateResult) {
|
||||
b, err := opts.ToSubnetCreateMap()
|
||||
if err != nil {
|
||||
r.Err = err
|
||||
return
|
||||
}
|
||||
_, r.Err = c.Post(createURL(c), b, &r.Body, nil)
|
||||
return
|
||||
}
|
||||
|
||||
// UpdateOptsBuilder allows extensions to add additional parameters to the
|
||||
// Update request.
|
||||
type UpdateOptsBuilder interface {
|
||||
ToSubnetUpdateMap() (map[string]interface{}, error)
|
||||
}
|
||||
|
||||
// UpdateOpts represents the attributes used when updating an existing subnet.
|
||||
type UpdateOpts struct {
|
||||
Name string `json:"name,omitempty"`
|
||||
AllocationPools []AllocationPool `json:"allocation_pools,omitempty"`
|
||||
GatewayIP *string `json:"gateway_ip,omitempty"`
|
||||
DNSNameservers []string `json:"dns_nameservers,omitempty"`
|
||||
HostRoutes []HostRoute `json:"host_routes,omitempty"`
|
||||
EnableDHCP *bool `json:"enable_dhcp,omitempty"`
|
||||
}
|
||||
|
||||
// ToSubnetUpdateMap casts an UpdateOpts struct to a map.
|
||||
func (opts UpdateOpts) ToSubnetUpdateMap() (map[string]interface{}, error) {
|
||||
b, err := gophercloud.BuildRequestBody(opts, "subnet")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if m := b["subnet"].(map[string]interface{}); m["gateway_ip"] == "" {
|
||||
m["gateway_ip"] = nil
|
||||
}
|
||||
|
||||
return b, nil
|
||||
}
|
||||
|
||||
// Update accepts a UpdateOpts struct and updates an existing subnet using the
|
||||
// values provided.
|
||||
func Update(c *gophercloud.ServiceClient, id string, opts UpdateOptsBuilder) (r UpdateResult) {
|
||||
b, err := opts.ToSubnetUpdateMap()
|
||||
if err != nil {
|
||||
r.Err = err
|
||||
return
|
||||
}
|
||||
_, r.Err = c.Put(updateURL(c, id), b, &r.Body, &gophercloud.RequestOpts{
|
||||
OkCodes: []int{200, 201},
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
// Delete accepts a unique ID and deletes the subnet associated with it.
|
||||
func Delete(c *gophercloud.ServiceClient, id string) (r DeleteResult) {
|
||||
_, r.Err = c.Delete(deleteURL(c, id), nil)
|
||||
return
|
||||
}
|
||||
|
||||
// IDFromName is a convenience function that returns a subnet's ID given its name.
|
||||
func IDFromName(client *gophercloud.ServiceClient, name string) (string, error) {
|
||||
count := 0
|
||||
id := ""
|
||||
pages, err := List(client, nil).AllPages()
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
all, err := ExtractSubnets(pages)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
for _, s := range all {
|
||||
if s.Name == name {
|
||||
count++
|
||||
id = s.ID
|
||||
}
|
||||
}
|
||||
|
||||
switch count {
|
||||
case 0:
|
||||
return "", gophercloud.ErrResourceNotFound{Name: name, ResourceType: "subnet"}
|
||||
case 1:
|
||||
return id, nil
|
||||
default:
|
||||
return "", gophercloud.ErrMultipleResourcesFound{Name: name, Count: count, ResourceType: "subnet"}
|
||||
}
|
||||
}
|
117
vendor/github.com/gophercloud/gophercloud/openstack/networking/v2/subnets/results.go
generated
vendored
Normal file
117
vendor/github.com/gophercloud/gophercloud/openstack/networking/v2/subnets/results.go
generated
vendored
Normal file
@ -0,0 +1,117 @@
|
||||
package subnets
|
||||
|
||||
import (
|
||||
"github.com/gophercloud/gophercloud"
|
||||
"github.com/gophercloud/gophercloud/pagination"
|
||||
)
|
||||
|
||||
type commonResult struct {
|
||||
gophercloud.Result
|
||||
}
|
||||
|
||||
// Extract is a function that accepts a result and extracts a subnet resource.
|
||||
func (r commonResult) Extract() (*Subnet, error) {
|
||||
var s struct {
|
||||
Subnet *Subnet `json:"subnet"`
|
||||
}
|
||||
err := r.ExtractInto(&s)
|
||||
return s.Subnet, err
|
||||
}
|
||||
|
||||
// CreateResult represents the result of a create operation.
|
||||
type CreateResult struct {
|
||||
commonResult
|
||||
}
|
||||
|
||||
// GetResult represents the result of a get operation.
|
||||
type GetResult struct {
|
||||
commonResult
|
||||
}
|
||||
|
||||
// UpdateResult represents the result of an update operation.
|
||||
type UpdateResult struct {
|
||||
commonResult
|
||||
}
|
||||
|
||||
// DeleteResult represents the result of a delete operation.
|
||||
type DeleteResult struct {
|
||||
gophercloud.ErrResult
|
||||
}
|
||||
|
||||
// AllocationPool represents a sub-range of cidr available for dynamic
|
||||
// allocation to ports, e.g. {Start: "10.0.0.2", End: "10.0.0.254"}
|
||||
type AllocationPool struct {
|
||||
Start string `json:"start"`
|
||||
End string `json:"end"`
|
||||
}
|
||||
|
||||
// HostRoute represents a route that should be used by devices with IPs from
|
||||
// a subnet (not including local subnet route).
|
||||
type HostRoute struct {
|
||||
DestinationCIDR string `json:"destination"`
|
||||
NextHop string `json:"nexthop"`
|
||||
}
|
||||
|
||||
// Subnet represents a subnet. See package documentation for a top-level
|
||||
// description of what this is.
|
||||
type Subnet struct {
|
||||
// UUID representing the subnet
|
||||
ID string `json:"id"`
|
||||
// UUID of the parent network
|
||||
NetworkID string `json:"network_id"`
|
||||
// Human-readable name for the subnet. Might not be unique.
|
||||
Name string `json:"name"`
|
||||
// IP version, either `4' or `6'
|
||||
IPVersion int `json:"ip_version"`
|
||||
// CIDR representing IP range for this subnet, based on IP version
|
||||
CIDR string `json:"cidr"`
|
||||
// Default gateway used by devices in this subnet
|
||||
GatewayIP string `json:"gateway_ip"`
|
||||
// DNS name servers used by hosts in this subnet.
|
||||
DNSNameservers []string `json:"dns_nameservers"`
|
||||
// Sub-ranges of CIDR available for dynamic allocation to ports. See AllocationPool.
|
||||
AllocationPools []AllocationPool `json:"allocation_pools"`
|
||||
// Routes that should be used by devices with IPs from this subnet (not including local subnet route).
|
||||
HostRoutes []HostRoute `json:"host_routes"`
|
||||
// Specifies whether DHCP is enabled for this subnet or not.
|
||||
EnableDHCP bool `json:"enable_dhcp"`
|
||||
// Owner of network. Only admin users can specify a tenant_id other than its own.
|
||||
TenantID string `json:"tenant_id"`
|
||||
}
|
||||
|
||||
// SubnetPage is the page returned by a pager when traversing over a collection
|
||||
// of subnets.
|
||||
type SubnetPage struct {
|
||||
pagination.LinkedPageBase
|
||||
}
|
||||
|
||||
// NextPageURL is invoked when a paginated collection of subnets has reached
|
||||
// the end of a page and the pager seeks to traverse over a new one. In order
|
||||
// to do this, it needs to construct the next page's URL.
|
||||
func (r SubnetPage) NextPageURL() (string, error) {
|
||||
var s struct {
|
||||
Links []gophercloud.Link `json:"subnets_links"`
|
||||
}
|
||||
err := r.ExtractInto(&s)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
return gophercloud.ExtractNextURL(s.Links)
|
||||
}
|
||||
|
||||
// IsEmpty checks whether a SubnetPage struct is empty.
|
||||
func (r SubnetPage) IsEmpty() (bool, error) {
|
||||
is, err := ExtractSubnets(r)
|
||||
return len(is) == 0, err
|
||||
}
|
||||
|
||||
// ExtractSubnets accepts a Page struct, specifically a SubnetPage struct,
|
||||
// and extracts the elements into a slice of Subnet structs. In other words,
|
||||
// a generic collection is mapped into a relevant slice.
|
||||
func ExtractSubnets(r pagination.Page) ([]Subnet, error) {
|
||||
var s struct {
|
||||
Subnets []Subnet `json:"subnets"`
|
||||
}
|
||||
err := (r.(SubnetPage)).ExtractInto(&s)
|
||||
return s.Subnets, err
|
||||
}
|
31
vendor/github.com/gophercloud/gophercloud/openstack/networking/v2/subnets/urls.go
generated
vendored
Normal file
31
vendor/github.com/gophercloud/gophercloud/openstack/networking/v2/subnets/urls.go
generated
vendored
Normal file
@ -0,0 +1,31 @@
|
||||
package subnets
|
||||
|
||||
import "github.com/gophercloud/gophercloud"
|
||||
|
||||
func resourceURL(c *gophercloud.ServiceClient, id string) string {
|
||||
return c.ServiceURL("subnets", id)
|
||||
}
|
||||
|
||||
func rootURL(c *gophercloud.ServiceClient) string {
|
||||
return c.ServiceURL("subnets")
|
||||
}
|
||||
|
||||
func listURL(c *gophercloud.ServiceClient) string {
|
||||
return rootURL(c)
|
||||
}
|
||||
|
||||
func getURL(c *gophercloud.ServiceClient, id string) string {
|
||||
return resourceURL(c, id)
|
||||
}
|
||||
|
||||
func createURL(c *gophercloud.ServiceClient) string {
|
||||
return rootURL(c)
|
||||
}
|
||||
|
||||
func updateURL(c *gophercloud.ServiceClient, id string) string {
|
||||
return resourceURL(c, id)
|
||||
}
|
||||
|
||||
func deleteURL(c *gophercloud.ServiceClient, id string) string {
|
||||
return resourceURL(c, id)
|
||||
}
|
1
vendor/github.com/pborman/uuid/CONTRIBUTORS
generated
vendored
Normal file
1
vendor/github.com/pborman/uuid/CONTRIBUTORS
generated
vendored
Normal file
@ -0,0 +1 @@
|
||||
Paul Borman <borman@google.com>
|
27
vendor/github.com/pborman/uuid/LICENSE
generated
vendored
Normal file
27
vendor/github.com/pborman/uuid/LICENSE
generated
vendored
Normal file
@ -0,0 +1,27 @@
|
||||
Copyright (c) 2009,2014 Google Inc. All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are
|
||||
met:
|
||||
|
||||
* Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
* Redistributions in binary form must reproduce the above
|
||||
copyright notice, this list of conditions and the following disclaimer
|
||||
in the documentation and/or other materials provided with the
|
||||
distribution.
|
||||
* Neither the name of Google Inc. nor the names of its
|
||||
contributors may be used to endorse or promote products derived from
|
||||
this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
84
vendor/github.com/pborman/uuid/dce.go
generated
vendored
Executable file
84
vendor/github.com/pborman/uuid/dce.go
generated
vendored
Executable file
@ -0,0 +1,84 @@
|
||||
// Copyright 2011 Google Inc. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package uuid
|
||||
|
||||
import (
|
||||
"encoding/binary"
|
||||
"fmt"
|
||||
"os"
|
||||
)
|
||||
|
||||
// A Domain represents a Version 2 domain
|
||||
type Domain byte
|
||||
|
||||
// Domain constants for DCE Security (Version 2) UUIDs.
|
||||
const (
|
||||
Person = Domain(0)
|
||||
Group = Domain(1)
|
||||
Org = Domain(2)
|
||||
)
|
||||
|
||||
// NewDCESecurity returns a DCE Security (Version 2) UUID.
|
||||
//
|
||||
// The domain should be one of Person, Group or Org.
|
||||
// On a POSIX system the id should be the users UID for the Person
|
||||
// domain and the users GID for the Group. The meaning of id for
|
||||
// the domain Org or on non-POSIX systems is site defined.
|
||||
//
|
||||
// For a given domain/id pair the same token may be returned for up to
|
||||
// 7 minutes and 10 seconds.
|
||||
func NewDCESecurity(domain Domain, id uint32) UUID {
|
||||
uuid := NewUUID()
|
||||
if uuid != nil {
|
||||
uuid[6] = (uuid[6] & 0x0f) | 0x20 // Version 2
|
||||
uuid[9] = byte(domain)
|
||||
binary.BigEndian.PutUint32(uuid[0:], id)
|
||||
}
|
||||
return uuid
|
||||
}
|
||||
|
||||
// NewDCEPerson returns a DCE Security (Version 2) UUID in the person
|
||||
// domain with the id returned by os.Getuid.
|
||||
//
|
||||
// NewDCEPerson(Person, uint32(os.Getuid()))
|
||||
func NewDCEPerson() UUID {
|
||||
return NewDCESecurity(Person, uint32(os.Getuid()))
|
||||
}
|
||||
|
||||
// NewDCEGroup returns a DCE Security (Version 2) UUID in the group
|
||||
// domain with the id returned by os.Getgid.
|
||||
//
|
||||
// NewDCEGroup(Group, uint32(os.Getgid()))
|
||||
func NewDCEGroup() UUID {
|
||||
return NewDCESecurity(Group, uint32(os.Getgid()))
|
||||
}
|
||||
|
||||
// Domain returns the domain for a Version 2 UUID or false.
|
||||
func (uuid UUID) Domain() (Domain, bool) {
|
||||
if v, _ := uuid.Version(); v != 2 {
|
||||
return 0, false
|
||||
}
|
||||
return Domain(uuid[9]), true
|
||||
}
|
||||
|
||||
// Id returns the id for a Version 2 UUID or false.
|
||||
func (uuid UUID) Id() (uint32, bool) {
|
||||
if v, _ := uuid.Version(); v != 2 {
|
||||
return 0, false
|
||||
}
|
||||
return binary.BigEndian.Uint32(uuid[0:4]), true
|
||||
}
|
||||
|
||||
func (d Domain) String() string {
|
||||
switch d {
|
||||
case Person:
|
||||
return "Person"
|
||||
case Group:
|
||||
return "Group"
|
||||
case Org:
|
||||
return "Org"
|
||||
}
|
||||
return fmt.Sprintf("Domain%d", int(d))
|
||||
}
|
8
vendor/github.com/pborman/uuid/doc.go
generated
vendored
Executable file
8
vendor/github.com/pborman/uuid/doc.go
generated
vendored
Executable file
@ -0,0 +1,8 @@
|
||||
// Copyright 2011 Google Inc. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
// The uuid package generates and inspects UUIDs.
|
||||
//
|
||||
// UUIDs are based on RFC 4122 and DCE 1.1: Authentication and Security Services.
|
||||
package uuid
|
53
vendor/github.com/pborman/uuid/hash.go
generated
vendored
Normal file
53
vendor/github.com/pborman/uuid/hash.go
generated
vendored
Normal file
@ -0,0 +1,53 @@
|
||||
// Copyright 2011 Google Inc. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package uuid
|
||||
|
||||
import (
|
||||
"crypto/md5"
|
||||
"crypto/sha1"
|
||||
"hash"
|
||||
)
|
||||
|
||||
// Well known Name Space IDs and UUIDs
|
||||
var (
|
||||
NameSpace_DNS = Parse("6ba7b810-9dad-11d1-80b4-00c04fd430c8")
|
||||
NameSpace_URL = Parse("6ba7b811-9dad-11d1-80b4-00c04fd430c8")
|
||||
NameSpace_OID = Parse("6ba7b812-9dad-11d1-80b4-00c04fd430c8")
|
||||
NameSpace_X500 = Parse("6ba7b814-9dad-11d1-80b4-00c04fd430c8")
|
||||
NIL = Parse("00000000-0000-0000-0000-000000000000")
|
||||
)
|
||||
|
||||
// NewHash returns a new UUID dervied from the hash of space concatenated with
|
||||
// data generated by h. The hash should be at least 16 byte in length. The
|
||||
// first 16 bytes of the hash are used to form the UUID. The version of the
|
||||
// UUID will be the lower 4 bits of version. NewHash is used to implement
|
||||
// NewMD5 and NewSHA1.
|
||||
func NewHash(h hash.Hash, space UUID, data []byte, version int) UUID {
|
||||
h.Reset()
|
||||
h.Write(space)
|
||||
h.Write([]byte(data))
|
||||
s := h.Sum(nil)
|
||||
uuid := make([]byte, 16)
|
||||
copy(uuid, s)
|
||||
uuid[6] = (uuid[6] & 0x0f) | uint8((version&0xf)<<4)
|
||||
uuid[8] = (uuid[8] & 0x3f) | 0x80 // RFC 4122 variant
|
||||
return uuid
|
||||
}
|
||||
|
||||
// NewMD5 returns a new MD5 (Version 3) UUID based on the
|
||||
// supplied name space and data.
|
||||
//
|
||||
// NewHash(md5.New(), space, data, 3)
|
||||
func NewMD5(space UUID, data []byte) UUID {
|
||||
return NewHash(md5.New(), space, data, 3)
|
||||
}
|
||||
|
||||
// NewSHA1 returns a new SHA1 (Version 5) UUID based on the
|
||||
// supplied name space and data.
|
||||
//
|
||||
// NewHash(sha1.New(), space, data, 5)
|
||||
func NewSHA1(space UUID, data []byte) UUID {
|
||||
return NewHash(sha1.New(), space, data, 5)
|
||||
}
|
30
vendor/github.com/pborman/uuid/json.go
generated
vendored
Normal file
30
vendor/github.com/pborman/uuid/json.go
generated
vendored
Normal file
@ -0,0 +1,30 @@
|
||||
// Copyright 2014 Google Inc. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package uuid
|
||||
|
||||
import "errors"
|
||||
|
||||
func (u UUID) MarshalJSON() ([]byte, error) {
|
||||
if len(u) == 0 {
|
||||
return []byte(`""`), nil
|
||||
}
|
||||
return []byte(`"` + u.String() + `"`), nil
|
||||
}
|
||||
|
||||
func (u *UUID) UnmarshalJSON(data []byte) error {
|
||||
if len(data) == 0 || string(data) == `""` {
|
||||
return nil
|
||||
}
|
||||
if len(data) < 2 || data[0] != '"' || data[len(data)-1] != '"' {
|
||||
return errors.New("invalid UUID format")
|
||||
}
|
||||
data = data[1 : len(data)-1]
|
||||
uu := Parse(string(data))
|
||||
if uu == nil {
|
||||
return errors.New("invalid UUID format")
|
||||
}
|
||||
*u = uu
|
||||
return nil
|
||||
}
|
101
vendor/github.com/pborman/uuid/node.go
generated
vendored
Executable file
101
vendor/github.com/pborman/uuid/node.go
generated
vendored
Executable file
@ -0,0 +1,101 @@
|
||||
// Copyright 2011 Google Inc. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package uuid
|
||||
|
||||
import "net"
|
||||
|
||||
var (
|
||||
interfaces []net.Interface // cached list of interfaces
|
||||
ifname string // name of interface being used
|
||||
nodeID []byte // hardware for version 1 UUIDs
|
||||
)
|
||||
|
||||
// NodeInterface returns the name of the interface from which the NodeID was
|
||||
// derived. The interface "user" is returned if the NodeID was set by
|
||||
// SetNodeID.
|
||||
func NodeInterface() string {
|
||||
return ifname
|
||||
}
|
||||
|
||||
// SetNodeInterface selects the hardware address to be used for Version 1 UUIDs.
|
||||
// If name is "" then the first usable interface found will be used or a random
|
||||
// Node ID will be generated. If a named interface cannot be found then false
|
||||
// is returned.
|
||||
//
|
||||
// SetNodeInterface never fails when name is "".
|
||||
func SetNodeInterface(name string) bool {
|
||||
if interfaces == nil {
|
||||
var err error
|
||||
interfaces, err = net.Interfaces()
|
||||
if err != nil && name != "" {
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
for _, ifs := range interfaces {
|
||||
if len(ifs.HardwareAddr) >= 6 && (name == "" || name == ifs.Name) {
|
||||
if setNodeID(ifs.HardwareAddr) {
|
||||
ifname = ifs.Name
|
||||
return true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// We found no interfaces with a valid hardware address. If name
|
||||
// does not specify a specific interface generate a random Node ID
|
||||
// (section 4.1.6)
|
||||
if name == "" {
|
||||
if nodeID == nil {
|
||||
nodeID = make([]byte, 6)
|
||||
}
|
||||
randomBits(nodeID)
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// NodeID returns a slice of a copy of the current Node ID, setting the Node ID
|
||||
// if not already set.
|
||||
func NodeID() []byte {
|
||||
if nodeID == nil {
|
||||
SetNodeInterface("")
|
||||
}
|
||||
nid := make([]byte, 6)
|
||||
copy(nid, nodeID)
|
||||
return nid
|
||||
}
|
||||
|
||||
// SetNodeID sets the Node ID to be used for Version 1 UUIDs. The first 6 bytes
|
||||
// of id are used. If id is less than 6 bytes then false is returned and the
|
||||
// Node ID is not set.
|
||||
func SetNodeID(id []byte) bool {
|
||||
if setNodeID(id) {
|
||||
ifname = "user"
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func setNodeID(id []byte) bool {
|
||||
if len(id) < 6 {
|
||||
return false
|
||||
}
|
||||
if nodeID == nil {
|
||||
nodeID = make([]byte, 6)
|
||||
}
|
||||
copy(nodeID, id)
|
||||
return true
|
||||
}
|
||||
|
||||
// NodeID returns the 6 byte node id encoded in uuid. It returns nil if uuid is
|
||||
// not valid. The NodeID is only well defined for version 1 and 2 UUIDs.
|
||||
func (uuid UUID) NodeID() []byte {
|
||||
if len(uuid) != 16 {
|
||||
return nil
|
||||
}
|
||||
node := make([]byte, 6)
|
||||
copy(node, uuid[10:])
|
||||
return node
|
||||
}
|
132
vendor/github.com/pborman/uuid/time.go
generated
vendored
Executable file
132
vendor/github.com/pborman/uuid/time.go
generated
vendored
Executable file
@ -0,0 +1,132 @@
|
||||
// Copyright 2014 Google Inc. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package uuid
|
||||
|
||||
import (
|
||||
"encoding/binary"
|
||||
"sync"
|
||||
"time"
|
||||
)
|
||||
|
||||
// A Time represents a time as the number of 100's of nanoseconds since 15 Oct
|
||||
// 1582.
|
||||
type Time int64
|
||||
|
||||
const (
|
||||
lillian = 2299160 // Julian day of 15 Oct 1582
|
||||
unix = 2440587 // Julian day of 1 Jan 1970
|
||||
epoch = unix - lillian // Days between epochs
|
||||
g1582 = epoch * 86400 // seconds between epochs
|
||||
g1582ns100 = g1582 * 10000000 // 100s of a nanoseconds between epochs
|
||||
)
|
||||
|
||||
var (
|
||||
mu sync.Mutex
|
||||
lasttime uint64 // last time we returned
|
||||
clock_seq uint16 // clock sequence for this run
|
||||
|
||||
timeNow = time.Now // for testing
|
||||
)
|
||||
|
||||
// UnixTime converts t the number of seconds and nanoseconds using the Unix
|
||||
// epoch of 1 Jan 1970.
|
||||
func (t Time) UnixTime() (sec, nsec int64) {
|
||||
sec = int64(t - g1582ns100)
|
||||
nsec = (sec % 10000000) * 100
|
||||
sec /= 10000000
|
||||
return sec, nsec
|
||||
}
|
||||
|
||||
// GetTime returns the current Time (100s of nanoseconds since 15 Oct 1582) and
|
||||
// clock sequence as well as adjusting the clock sequence as needed. An error
|
||||
// is returned if the current time cannot be determined.
|
||||
func GetTime() (Time, uint16, error) {
|
||||
defer mu.Unlock()
|
||||
mu.Lock()
|
||||
return getTime()
|
||||
}
|
||||
|
||||
func getTime() (Time, uint16, error) {
|
||||
t := timeNow()
|
||||
|
||||
// If we don't have a clock sequence already, set one.
|
||||
if clock_seq == 0 {
|
||||
setClockSequence(-1)
|
||||
}
|
||||
now := uint64(t.UnixNano()/100) + g1582ns100
|
||||
|
||||
// If time has gone backwards with this clock sequence then we
|
||||
// increment the clock sequence
|
||||
if now <= lasttime {
|
||||
clock_seq = ((clock_seq + 1) & 0x3fff) | 0x8000
|
||||
}
|
||||
lasttime = now
|
||||
return Time(now), clock_seq, nil
|
||||
}
|
||||
|
||||
// ClockSequence returns the current clock sequence, generating one if not
|
||||
// already set. The clock sequence is only used for Version 1 UUIDs.
|
||||
//
|
||||
// The uuid package does not use global static storage for the clock sequence or
|
||||
// the last time a UUID was generated. Unless SetClockSequence a new random
|
||||
// clock sequence is generated the first time a clock sequence is requested by
|
||||
// ClockSequence, GetTime, or NewUUID. (section 4.2.1.1) sequence is generated
|
||||
// for
|
||||
func ClockSequence() int {
|
||||
defer mu.Unlock()
|
||||
mu.Lock()
|
||||
return clockSequence()
|
||||
}
|
||||
|
||||
func clockSequence() int {
|
||||
if clock_seq == 0 {
|
||||
setClockSequence(-1)
|
||||
}
|
||||
return int(clock_seq & 0x3fff)
|
||||
}
|
||||
|
||||
// SetClockSeq sets the clock sequence to the lower 14 bits of seq. Setting to
|
||||
// -1 causes a new sequence to be generated.
|
||||
func SetClockSequence(seq int) {
|
||||
defer mu.Unlock()
|
||||
mu.Lock()
|
||||
setClockSequence(seq)
|
||||
}
|
||||
|
||||
func setClockSequence(seq int) {
|
||||
if seq == -1 {
|
||||
var b [2]byte
|
||||
randomBits(b[:]) // clock sequence
|
||||
seq = int(b[0])<<8 | int(b[1])
|
||||
}
|
||||
old_seq := clock_seq
|
||||
clock_seq = uint16(seq&0x3fff) | 0x8000 // Set our variant
|
||||
if old_seq != clock_seq {
|
||||
lasttime = 0
|
||||
}
|
||||
}
|
||||
|
||||
// Time returns the time in 100s of nanoseconds since 15 Oct 1582 encoded in
|
||||
// uuid. It returns false if uuid is not valid. The time is only well defined
|
||||
// for version 1 and 2 UUIDs.
|
||||
func (uuid UUID) Time() (Time, bool) {
|
||||
if len(uuid) != 16 {
|
||||
return 0, false
|
||||
}
|
||||
time := int64(binary.BigEndian.Uint32(uuid[0:4]))
|
||||
time |= int64(binary.BigEndian.Uint16(uuid[4:6])) << 32
|
||||
time |= int64(binary.BigEndian.Uint16(uuid[6:8])&0xfff) << 48
|
||||
return Time(time), true
|
||||
}
|
||||
|
||||
// ClockSequence returns the clock sequence encoded in uuid. It returns false
|
||||
// if uuid is not valid. The clock sequence is only well defined for version 1
|
||||
// and 2 UUIDs.
|
||||
func (uuid UUID) ClockSequence() (int, bool) {
|
||||
if len(uuid) != 16 {
|
||||
return 0, false
|
||||
}
|
||||
return int(binary.BigEndian.Uint16(uuid[8:10])) & 0x3fff, true
|
||||
}
|
43
vendor/github.com/pborman/uuid/util.go
generated
vendored
Normal file
43
vendor/github.com/pborman/uuid/util.go
generated
vendored
Normal file
@ -0,0 +1,43 @@
|
||||
// Copyright 2011 Google Inc. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package uuid
|
||||
|
||||
import (
|
||||
"io"
|
||||
)
|
||||
|
||||
// randomBits completely fills slice b with random data.
|
||||
func randomBits(b []byte) {
|
||||
if _, err := io.ReadFull(rander, b); err != nil {
|
||||
panic(err.Error()) // rand should never fail
|
||||
}
|
||||
}
|
||||
|
||||
// xvalues returns the value of a byte as a hexadecimal digit or 255.
|
||||
var xvalues = []byte{
|
||||
255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
|
||||
255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
|
||||
255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
|
||||
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 255, 255, 255, 255, 255, 255,
|
||||
255, 10, 11, 12, 13, 14, 15, 255, 255, 255, 255, 255, 255, 255, 255, 255,
|
||||
255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
|
||||
255, 10, 11, 12, 13, 14, 15, 255, 255, 255, 255, 255, 255, 255, 255, 255,
|
||||
255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
|
||||
255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
|
||||
255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
|
||||
255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
|
||||
255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
|
||||
255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
|
||||
255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
|
||||
255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
|
||||
255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
|
||||
}
|
||||
|
||||
// xtob converts the the first two hex bytes of x into a byte.
|
||||
func xtob(x string) (byte, bool) {
|
||||
b1 := xvalues[x[0]]
|
||||
b2 := xvalues[x[1]]
|
||||
return (b1 << 4) | b2, b1 != 255 && b2 != 255
|
||||
}
|
163
vendor/github.com/pborman/uuid/uuid.go
generated
vendored
Executable file
163
vendor/github.com/pborman/uuid/uuid.go
generated
vendored
Executable file
@ -0,0 +1,163 @@
|
||||
// Copyright 2011 Google Inc. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package uuid
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"crypto/rand"
|
||||
"fmt"
|
||||
"io"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// A UUID is a 128 bit (16 byte) Universal Unique IDentifier as defined in RFC
|
||||
// 4122.
|
||||
type UUID []byte
|
||||
|
||||
// A Version represents a UUIDs version.
|
||||
type Version byte
|
||||
|
||||
// A Variant represents a UUIDs variant.
|
||||
type Variant byte
|
||||
|
||||
// Constants returned by Variant.
|
||||
const (
|
||||
Invalid = Variant(iota) // Invalid UUID
|
||||
RFC4122 // The variant specified in RFC4122
|
||||
Reserved // Reserved, NCS backward compatibility.
|
||||
Microsoft // Reserved, Microsoft Corporation backward compatibility.
|
||||
Future // Reserved for future definition.
|
||||
)
|
||||
|
||||
var rander = rand.Reader // random function
|
||||
|
||||
// New returns a new random (version 4) UUID as a string. It is a convenience
|
||||
// function for NewRandom().String().
|
||||
func New() string {
|
||||
return NewRandom().String()
|
||||
}
|
||||
|
||||
// Parse decodes s into a UUID or returns nil. Both the UUID form of
|
||||
// xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx and
|
||||
// urn:uuid:xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx are decoded.
|
||||
func Parse(s string) UUID {
|
||||
if len(s) == 36+9 {
|
||||
if strings.ToLower(s[:9]) != "urn:uuid:" {
|
||||
return nil
|
||||
}
|
||||
s = s[9:]
|
||||
} else if len(s) != 36 {
|
||||
return nil
|
||||
}
|
||||
if s[8] != '-' || s[13] != '-' || s[18] != '-' || s[23] != '-' {
|
||||
return nil
|
||||
}
|
||||
uuid := make([]byte, 16)
|
||||
for i, x := range []int{
|
||||
0, 2, 4, 6,
|
||||
9, 11,
|
||||
14, 16,
|
||||
19, 21,
|
||||
24, 26, 28, 30, 32, 34} {
|
||||
if v, ok := xtob(s[x:]); !ok {
|
||||
return nil
|
||||
} else {
|
||||
uuid[i] = v
|
||||
}
|
||||
}
|
||||
return uuid
|
||||
}
|
||||
|
||||
// Equal returns true if uuid1 and uuid2 are equal.
|
||||
func Equal(uuid1, uuid2 UUID) bool {
|
||||
return bytes.Equal(uuid1, uuid2)
|
||||
}
|
||||
|
||||
// String returns the string form of uuid, xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
|
||||
// , or "" if uuid is invalid.
|
||||
func (uuid UUID) String() string {
|
||||
if uuid == nil || len(uuid) != 16 {
|
||||
return ""
|
||||
}
|
||||
b := []byte(uuid)
|
||||
return fmt.Sprintf("%08x-%04x-%04x-%04x-%012x",
|
||||
b[:4], b[4:6], b[6:8], b[8:10], b[10:])
|
||||
}
|
||||
|
||||
// URN returns the RFC 2141 URN form of uuid,
|
||||
// urn:uuid:xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx, or "" if uuid is invalid.
|
||||
func (uuid UUID) URN() string {
|
||||
if uuid == nil || len(uuid) != 16 {
|
||||
return ""
|
||||
}
|
||||
b := []byte(uuid)
|
||||
return fmt.Sprintf("urn:uuid:%08x-%04x-%04x-%04x-%012x",
|
||||
b[:4], b[4:6], b[6:8], b[8:10], b[10:])
|
||||
}
|
||||
|
||||
// Variant returns the variant encoded in uuid. It returns Invalid if
|
||||
// uuid is invalid.
|
||||
func (uuid UUID) Variant() Variant {
|
||||
if len(uuid) != 16 {
|
||||
return Invalid
|
||||
}
|
||||
switch {
|
||||
case (uuid[8] & 0xc0) == 0x80:
|
||||
return RFC4122
|
||||
case (uuid[8] & 0xe0) == 0xc0:
|
||||
return Microsoft
|
||||
case (uuid[8] & 0xe0) == 0xe0:
|
||||
return Future
|
||||
default:
|
||||
return Reserved
|
||||
}
|
||||
panic("unreachable")
|
||||
}
|
||||
|
||||
// Version returns the verison of uuid. It returns false if uuid is not
|
||||
// valid.
|
||||
func (uuid UUID) Version() (Version, bool) {
|
||||
if len(uuid) != 16 {
|
||||
return 0, false
|
||||
}
|
||||
return Version(uuid[6] >> 4), true
|
||||
}
|
||||
|
||||
func (v Version) String() string {
|
||||
if v > 15 {
|
||||
return fmt.Sprintf("BAD_VERSION_%d", v)
|
||||
}
|
||||
return fmt.Sprintf("VERSION_%d", v)
|
||||
}
|
||||
|
||||
func (v Variant) String() string {
|
||||
switch v {
|
||||
case RFC4122:
|
||||
return "RFC4122"
|
||||
case Reserved:
|
||||
return "Reserved"
|
||||
case Microsoft:
|
||||
return "Microsoft"
|
||||
case Future:
|
||||
return "Future"
|
||||
case Invalid:
|
||||
return "Invalid"
|
||||
}
|
||||
return fmt.Sprintf("BadVariant%d", int(v))
|
||||
}
|
||||
|
||||
// SetRand sets the random number generator to r, which implents io.Reader.
|
||||
// If r.Read returns an error when the package requests random data then
|
||||
// a panic will be issued.
|
||||
//
|
||||
// Calling SetRand with nil sets the random number generator to the default
|
||||
// generator.
|
||||
func SetRand(r io.Reader) {
|
||||
if r == nil {
|
||||
rander = rand.Reader
|
||||
return
|
||||
}
|
||||
rander = r
|
||||
}
|
41
vendor/github.com/pborman/uuid/version1.go
generated
vendored
Normal file
41
vendor/github.com/pborman/uuid/version1.go
generated
vendored
Normal file
@ -0,0 +1,41 @@
|
||||
// Copyright 2011 Google Inc. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package uuid
|
||||
|
||||
import (
|
||||
"encoding/binary"
|
||||
)
|
||||
|
||||
// NewUUID returns a Version 1 UUID based on the current NodeID and clock
|
||||
// sequence, and the current time. If the NodeID has not been set by SetNodeID
|
||||
// or SetNodeInterface then it will be set automatically. If the NodeID cannot
|
||||
// be set NewUUID returns nil. If clock sequence has not been set by
|
||||
// SetClockSequence then it will be set automatically. If GetTime fails to
|
||||
// return the current NewUUID returns nil.
|
||||
func NewUUID() UUID {
|
||||
if nodeID == nil {
|
||||
SetNodeInterface("")
|
||||
}
|
||||
|
||||
now, seq, err := GetTime()
|
||||
if err != nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
uuid := make([]byte, 16)
|
||||
|
||||
time_low := uint32(now & 0xffffffff)
|
||||
time_mid := uint16((now >> 32) & 0xffff)
|
||||
time_hi := uint16((now >> 48) & 0x0fff)
|
||||
time_hi |= 0x1000 // Version 1
|
||||
|
||||
binary.BigEndian.PutUint32(uuid[0:], time_low)
|
||||
binary.BigEndian.PutUint16(uuid[4:], time_mid)
|
||||
binary.BigEndian.PutUint16(uuid[6:], time_hi)
|
||||
binary.BigEndian.PutUint16(uuid[8:], seq)
|
||||
copy(uuid[10:], nodeID)
|
||||
|
||||
return uuid
|
||||
}
|
25
vendor/github.com/pborman/uuid/version4.go
generated
vendored
Normal file
25
vendor/github.com/pborman/uuid/version4.go
generated
vendored
Normal file
@ -0,0 +1,25 @@
|
||||
// Copyright 2011 Google Inc. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package uuid
|
||||
|
||||
// Random returns a Random (Version 4) UUID or panics.
|
||||
//
|
||||
// The strength of the UUIDs is based on the strength of the crypto/rand
|
||||
// package.
|
||||
//
|
||||
// A note about uniqueness derived from from the UUID Wikipedia entry:
|
||||
//
|
||||
// Randomly generated UUIDs have 122 random bits. One's annual risk of being
|
||||
// hit by a meteorite is estimated to be one chance in 17 billion, that
|
||||
// means the probability is about 0.00000000006 (6 × 10−11),
|
||||
// equivalent to the odds of creating a few tens of trillions of UUIDs in a
|
||||
// year and having one duplicate.
|
||||
func NewRandom() UUID {
|
||||
uuid := make([]byte, 16)
|
||||
randomBits([]byte(uuid))
|
||||
uuid[6] = (uuid[6] & 0x0f) | 0x40 // Version 4
|
||||
uuid[8] = (uuid[8] & 0x3f) | 0x80 // Variant is 10
|
||||
return uuid
|
||||
}
|
74
vendor/golang.org/x/net/context/ctxhttp/ctxhttp.go
generated
vendored
Normal file
74
vendor/golang.org/x/net/context/ctxhttp/ctxhttp.go
generated
vendored
Normal file
@ -0,0 +1,74 @@
|
||||
// Copyright 2016 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
// +build go1.7
|
||||
|
||||
// Package ctxhttp provides helper functions for performing context-aware HTTP requests.
|
||||
package ctxhttp
|
||||
|
||||
import (
|
||||
"io"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"strings"
|
||||
|
||||
"golang.org/x/net/context"
|
||||
)
|
||||
|
||||
// Do sends an HTTP request with the provided http.Client and returns
|
||||
// an HTTP response.
|
||||
//
|
||||
// If the client is nil, http.DefaultClient is used.
|
||||
//
|
||||
// The provided ctx must be non-nil. If it is canceled or times out,
|
||||
// ctx.Err() will be returned.
|
||||
func Do(ctx context.Context, client *http.Client, req *http.Request) (*http.Response, error) {
|
||||
if client == nil {
|
||||
client = http.DefaultClient
|
||||
}
|
||||
resp, err := client.Do(req.WithContext(ctx))
|
||||
// If we got an error, and the context has been canceled,
|
||||
// the context's error is probably more useful.
|
||||
if err != nil {
|
||||
select {
|
||||
case <-ctx.Done():
|
||||
err = ctx.Err()
|
||||
default:
|
||||
}
|
||||
}
|
||||
return resp, err
|
||||
}
|
||||
|
||||
// Get issues a GET request via the Do function.
|
||||
func Get(ctx context.Context, client *http.Client, url string) (*http.Response, error) {
|
||||
req, err := http.NewRequest("GET", url, nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return Do(ctx, client, req)
|
||||
}
|
||||
|
||||
// Head issues a HEAD request via the Do function.
|
||||
func Head(ctx context.Context, client *http.Client, url string) (*http.Response, error) {
|
||||
req, err := http.NewRequest("HEAD", url, nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return Do(ctx, client, req)
|
||||
}
|
||||
|
||||
// Post issues a POST request via the Do function.
|
||||
func Post(ctx context.Context, client *http.Client, url string, bodyType string, body io.Reader) (*http.Response, error) {
|
||||
req, err := http.NewRequest("POST", url, body)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
req.Header.Set("Content-Type", bodyType)
|
||||
return Do(ctx, client, req)
|
||||
}
|
||||
|
||||
// PostForm issues a POST request via the Do function.
|
||||
func PostForm(ctx context.Context, client *http.Client, url string, data url.Values) (*http.Response, error) {
|
||||
return Post(ctx, client, url, "application/x-www-form-urlencoded", strings.NewReader(data.Encode()))
|
||||
}
|
147
vendor/golang.org/x/net/context/ctxhttp/ctxhttp_pre17.go
generated
vendored
Normal file
147
vendor/golang.org/x/net/context/ctxhttp/ctxhttp_pre17.go
generated
vendored
Normal file
@ -0,0 +1,147 @@
|
||||
// Copyright 2015 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
// +build !go1.7
|
||||
|
||||
package ctxhttp
|
||||
|
||||
import (
|
||||
"io"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"strings"
|
||||
|
||||
"golang.org/x/net/context"
|
||||
)
|
||||
|
||||
func nop() {}
|
||||
|
||||
var (
|
||||
testHookContextDoneBeforeHeaders = nop
|
||||
testHookDoReturned = nop
|
||||
testHookDidBodyClose = nop
|
||||
)
|
||||
|
||||
// Do sends an HTTP request with the provided http.Client and returns an HTTP response.
|
||||
// If the client is nil, http.DefaultClient is used.
|
||||
// If the context is canceled or times out, ctx.Err() will be returned.
|
||||
func Do(ctx context.Context, client *http.Client, req *http.Request) (*http.Response, error) {
|
||||
if client == nil {
|
||||
client = http.DefaultClient
|
||||
}
|
||||
|
||||
// TODO(djd): Respect any existing value of req.Cancel.
|
||||
cancel := make(chan struct{})
|
||||
req.Cancel = cancel
|
||||
|
||||
type responseAndError struct {
|
||||
resp *http.Response
|
||||
err error
|
||||
}
|
||||
result := make(chan responseAndError, 1)
|
||||
|
||||
// Make local copies of test hooks closed over by goroutines below.
|
||||
// Prevents data races in tests.
|
||||
testHookDoReturned := testHookDoReturned
|
||||
testHookDidBodyClose := testHookDidBodyClose
|
||||
|
||||
go func() {
|
||||
resp, err := client.Do(req)
|
||||
testHookDoReturned()
|
||||
result <- responseAndError{resp, err}
|
||||
}()
|
||||
|
||||
var resp *http.Response
|
||||
|
||||
select {
|
||||
case <-ctx.Done():
|
||||
testHookContextDoneBeforeHeaders()
|
||||
close(cancel)
|
||||
// Clean up after the goroutine calling client.Do:
|
||||
go func() {
|
||||
if r := <-result; r.resp != nil {
|
||||
testHookDidBodyClose()
|
||||
r.resp.Body.Close()
|
||||
}
|
||||
}()
|
||||
return nil, ctx.Err()
|
||||
case r := <-result:
|
||||
var err error
|
||||
resp, err = r.resp, r.err
|
||||
if err != nil {
|
||||
return resp, err
|
||||
}
|
||||
}
|
||||
|
||||
c := make(chan struct{})
|
||||
go func() {
|
||||
select {
|
||||
case <-ctx.Done():
|
||||
close(cancel)
|
||||
case <-c:
|
||||
// The response's Body is closed.
|
||||
}
|
||||
}()
|
||||
resp.Body = ¬ifyingReader{resp.Body, c}
|
||||
|
||||
return resp, nil
|
||||
}
|
||||
|
||||
// Get issues a GET request via the Do function.
|
||||
func Get(ctx context.Context, client *http.Client, url string) (*http.Response, error) {
|
||||
req, err := http.NewRequest("GET", url, nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return Do(ctx, client, req)
|
||||
}
|
||||
|
||||
// Head issues a HEAD request via the Do function.
|
||||
func Head(ctx context.Context, client *http.Client, url string) (*http.Response, error) {
|
||||
req, err := http.NewRequest("HEAD", url, nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return Do(ctx, client, req)
|
||||
}
|
||||
|
||||
// Post issues a POST request via the Do function.
|
||||
func Post(ctx context.Context, client *http.Client, url string, bodyType string, body io.Reader) (*http.Response, error) {
|
||||
req, err := http.NewRequest("POST", url, body)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
req.Header.Set("Content-Type", bodyType)
|
||||
return Do(ctx, client, req)
|
||||
}
|
||||
|
||||
// PostForm issues a POST request via the Do function.
|
||||
func PostForm(ctx context.Context, client *http.Client, url string, data url.Values) (*http.Response, error) {
|
||||
return Post(ctx, client, url, "application/x-www-form-urlencoded", strings.NewReader(data.Encode()))
|
||||
}
|
||||
|
||||
// notifyingReader is an io.ReadCloser that closes the notify channel after
|
||||
// Close is called or a Read fails on the underlying ReadCloser.
|
||||
type notifyingReader struct {
|
||||
io.ReadCloser
|
||||
notify chan<- struct{}
|
||||
}
|
||||
|
||||
func (r *notifyingReader) Read(p []byte) (int, error) {
|
||||
n, err := r.ReadCloser.Read(p)
|
||||
if err != nil && r.notify != nil {
|
||||
close(r.notify)
|
||||
r.notify = nil
|
||||
}
|
||||
return n, err
|
||||
}
|
||||
|
||||
func (r *notifyingReader) Close() error {
|
||||
err := r.ReadCloser.Close()
|
||||
if r.notify != nil {
|
||||
close(r.notify)
|
||||
r.notify = nil
|
||||
}
|
||||
return err
|
||||
}
|
18
vendor/k8s.io/apimachinery/pkg/util/uuid/BUILD
generated
vendored
Normal file
18
vendor/k8s.io/apimachinery/pkg/util/uuid/BUILD
generated
vendored
Normal file
@ -0,0 +1,18 @@
|
||||
package(default_visibility = ["//visibility:public"])
|
||||
|
||||
licenses(["notice"])
|
||||
|
||||
load(
|
||||
"@io_bazel_rules_go//go:def.bzl",
|
||||
"go_library",
|
||||
)
|
||||
|
||||
go_library(
|
||||
name = "go_default_library",
|
||||
srcs = ["uuid.go"],
|
||||
tags = ["automanaged"],
|
||||
deps = [
|
||||
"//vendor/github.com/pborman/uuid:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/types:go_default_library",
|
||||
],
|
||||
)
|
43
vendor/k8s.io/apimachinery/pkg/util/uuid/uuid.go
generated
vendored
Normal file
43
vendor/k8s.io/apimachinery/pkg/util/uuid/uuid.go
generated
vendored
Normal file
@ -0,0 +1,43 @@
|
||||
/*
|
||||
Copyright 2014 The Kubernetes Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package uuid
|
||||
|
||||
import (
|
||||
"sync"
|
||||
|
||||
"github.com/pborman/uuid"
|
||||
|
||||
"k8s.io/apimachinery/pkg/types"
|
||||
)
|
||||
|
||||
var uuidLock sync.Mutex
|
||||
var lastUUID uuid.UUID
|
||||
|
||||
func NewUUID() types.UID {
|
||||
uuidLock.Lock()
|
||||
defer uuidLock.Unlock()
|
||||
result := uuid.NewUUID()
|
||||
// The UUID package is naive and can generate identical UUIDs if the
|
||||
// time interval is quick enough.
|
||||
// The UUID uses 100 ns increments so it's short enough to actively
|
||||
// wait for a new value.
|
||||
for uuid.Equal(lastUUID, result) == true {
|
||||
result = uuid.NewUUID()
|
||||
}
|
||||
lastUUID = result
|
||||
return types.UID(result.String())
|
||||
}
|
Loading…
Reference in New Issue
Block a user