Commit 1a15b3db authored by Kubernetes Submit Queue's avatar Kubernetes Submit Queue Committed by GitHub

Merge pull request #52132 from portworx/kubelet_weird_output_fix

Automatic merge from submit-queue (batch tested with PRs 51064, 52132). If you want to cherry-pick this change to another branch, please follow the instructions <a href="https://github.com/kubernetes/community/blob/master/contributors/devel/cherry-picks.md">here</a>.. Kubelet weird output fix **What this PR does / why we need it**: All kube binaries print the following message at the top when executed: ``` 2017/08/28 21:37:12 proto: duplicate proto type registered: google.protobuf.Any 2017/08/28 21:37:12 proto: duplicate proto type registered: google.protobuf.Duration 2017/08/28 21:37:12 proto: duplicate proto type registered: google.protobuf.Timestamp ``` This PR addresses the above issue It involves the following two changes: 1. Updating vendor packages - Removes everything under the repo ``go.pedge.io`` - Updates repo libopenstorage/openstorage (which was using the above package) 2. Updates the portworx volume native driver to adhere to the newly vendor'ed code. **Which issue this PR fixes** *(optional, in `fixes #<issue number>(, fixes #<issue_number>, ...)` format, will close that issue when PR gets merged)*: fixes #51452 **Special notes for your reviewer**: I have divided the changes into 2 commits 1. Vendor'ed changes 2. Changes in portworx volume driver. ```release-note Remove duplicate proto errors in kubelet. ```
parents a16a126f a967937a
......@@ -1930,27 +1930,31 @@
},
{
"ImportPath": "github.com/libopenstorage/openstorage/api",
"Rev": "6e787003b91ddba85f108b8aede075b1af0d3606"
"Rev": "093a0c3888753c2056e7373183693d670c6bba01"
},
{
"ImportPath": "github.com/libopenstorage/openstorage/api/client",
"Rev": "6e787003b91ddba85f108b8aede075b1af0d3606"
"Rev": "093a0c3888753c2056e7373183693d670c6bba01"
},
{
"ImportPath": "github.com/libopenstorage/openstorage/api/client/volume",
"Rev": "6e787003b91ddba85f108b8aede075b1af0d3606"
"Rev": "093a0c3888753c2056e7373183693d670c6bba01"
},
{
"ImportPath": "github.com/libopenstorage/openstorage/api/spec",
"Rev": "6e787003b91ddba85f108b8aede075b1af0d3606"
"Rev": "093a0c3888753c2056e7373183693d670c6bba01"
},
{
"ImportPath": "github.com/libopenstorage/openstorage/pkg/parser",
"Rev": "093a0c3888753c2056e7373183693d670c6bba01"
},
{
"ImportPath": "github.com/libopenstorage/openstorage/pkg/units",
"Rev": "6e787003b91ddba85f108b8aede075b1af0d3606"
"Rev": "093a0c3888753c2056e7373183693d670c6bba01"
},
{
"ImportPath": "github.com/libopenstorage/openstorage/volume",
"Rev": "6e787003b91ddba85f108b8aede075b1af0d3606"
"Rev": "093a0c3888753c2056e7373183693d670c6bba01"
},
{
"ImportPath": "github.com/lpabon/godbc",
......@@ -2001,6 +2005,10 @@
"Rev": "53818660ed4955e899c0bcafa97299a388bd7c8e"
},
{
"ImportPath": "github.com/mohae/deepcopy",
"Rev": "491d3605edfb866af34a48075bd4355ac1bf46ca"
},
{
"ImportPath": "github.com/mreiferson/go-httpclient",
"Rev": "31f0106b4474f14bc441575c19d3a5fa21aa1f6c"
},
......@@ -2750,10 +2758,6 @@
"Rev": "5292687f5379e01054407da44d7c4590a61fd3de"
},
{
"ImportPath": "go.pedge.io/pb/go/google/protobuf",
"Rev": "f3c84f58974dc53d460d0855337cad85843bf0df"
},
{
"ImportPath": "go4.org/errorutil",
"Rev": "03efcb870d84809319ea509714dd6d19a1498483"
},
......
......@@ -31,6 +31,11 @@ import (
"k8s.io/kubernetes/pkg/volume/util/volumehelper"
)
const (
attachContextKey = "context"
attachHostKey = "host"
)
// This is the primary entrypoint for volume plugins.
func ProbeVolumePlugins() []volume.VolumePlugin {
return []volume.VolumePlugin{&portworxVolumePlugin{nil, nil}}
......@@ -205,7 +210,7 @@ type portworxManager interface {
// Deletes a volume
DeleteVolume(deleter *portworxVolumeDeleter) error
// Attach a volume
AttachVolume(mounter *portworxVolumeMounter) (string, error)
AttachVolume(mounter *portworxVolumeMounter, attachOptions map[string]string) (string, error)
// Detach a volume
DetachVolume(unmounter *portworxVolumeUnmounter) error
// Mount a volume
......@@ -274,7 +279,10 @@ func (b *portworxVolumeMounter) SetUpAt(dir string, fsGroup *int64) error {
return nil
}
if _, err := b.manager.AttachVolume(b); err != nil {
attachOptions := make(map[string]string)
attachOptions[attachContextKey] = dir
attachOptions[attachHostKey] = b.plugin.host.GetHostName()
if _, err := b.manager.AttachVolume(b, attachOptions); err != nil {
return err
}
......
......@@ -97,7 +97,7 @@ type fakePortworxManager struct {
mountCalled bool
}
func (fake *fakePortworxManager) AttachVolume(b *portworxVolumeMounter) (string, error) {
func (fake *fakePortworxManager) AttachVolume(b *portworxVolumeMounter, attachOptions map[string]string) (string, error) {
fake.attachCalled = true
return "", nil
}
......
......@@ -35,6 +35,7 @@ const (
pxdDriverName = "pxd"
pvcClaimLabel = "pvc"
pxServiceName = "portworx-service"
pxDriverName = "pxd-sched"
)
type PortworxVolumeUtil struct {
......@@ -60,23 +61,26 @@ func (util *PortworxVolumeUtil) CreateVolume(p *portworxVolumeProvisioner) (stri
// doesn't support new parameters, the server-side processing will parse it correctly.
// We still need to call SpecFromOpts() here to handle cases where someone is running Portworx 1.2.8 and lower.
specHandler := osdspec.NewSpecHandler()
spec, _ := specHandler.SpecFromOpts(p.options.Parameters)
spec, locator, source, _ := specHandler.SpecFromOpts(p.options.Parameters)
if spec == nil {
spec = specHandler.DefaultSpec()
}
// Pass all parameters as volume labels for Portworx server-side processing.
spec.VolumeLabels = p.options.Parameters
// Update the requested size in the spec
spec.Size = uint64(requestGB * 1024 * 1024 * 1024)
source := osdapi.Source{}
locator := osdapi.VolumeLocator{
Name: p.options.PVName,
// Change the Portworx Volume name to PV name
if locator == nil {
locator = &osdapi.VolumeLocator{
VolumeLabels: make(map[string]string),
}
}
locator.Name = p.options.PVName
// Add claim Name as a part of Portworx Volume Labels
locator.VolumeLabels = make(map[string]string)
locator.VolumeLabels[pvcClaimLabel] = p.options.PVC.Name
volumeID, err := driver.Create(&locator, &source, spec)
volumeID, err := driver.Create(locator, source, spec)
if err != nil {
glog.Errorf("Error creating Portworx Volume : %v", err)
}
......@@ -102,14 +106,14 @@ func (util *PortworxVolumeUtil) DeleteVolume(d *portworxVolumeDeleter) error {
}
// AttachVolume attaches a Portworx Volume
func (util *PortworxVolumeUtil) AttachVolume(m *portworxVolumeMounter) (string, error) {
func (util *PortworxVolumeUtil) AttachVolume(m *portworxVolumeMounter, attachOptions map[string]string) (string, error) {
driver, err := util.getPortworxDriver(m.plugin.host, true /*localOnly*/)
if err != nil || driver == nil {
glog.Errorf("Failed to get portworx driver. Err: %v", err)
return "", err
}
devicePath, err := driver.Attach(m.volName)
devicePath, err := driver.Attach(m.volName, attachOptions)
if err != nil {
glog.Errorf("Error attaching Portworx Volume (%v): %v", m.volName, err)
return "", err
......@@ -125,7 +129,7 @@ func (util *PortworxVolumeUtil) DetachVolume(u *portworxVolumeUnmounter) error {
return err
}
err = driver.Detach(u.volName)
err = driver.Detach(u.volName, false /*doNotForceDetach*/)
if err != nil {
glog.Errorf("Error detaching Portworx Volume (%v): %v", u.volName, err)
return err
......@@ -181,7 +185,7 @@ func isClientValid(client *osdclient.Client) (bool, error) {
func createDriverClient(hostname string) (*osdclient.Client, error) {
client, err := volumeclient.NewDriverClient("http://"+hostname+":"+osdMgmtPort,
pxdDriverName, osdDriverVersion)
pxdDriverName, osdDriverVersion, pxDriverName)
if err != nil {
return nil, err
}
......
......@@ -260,6 +260,7 @@ filegroup(
"//vendor/github.com/kr/fs:all-srcs",
"//vendor/github.com/kr/pty:all-srcs",
"//vendor/github.com/libopenstorage/openstorage/api:all-srcs",
"//vendor/github.com/libopenstorage/openstorage/pkg/parser:all-srcs",
"//vendor/github.com/libopenstorage/openstorage/pkg/units:all-srcs",
"//vendor/github.com/libopenstorage/openstorage/volume:all-srcs",
"//vendor/github.com/lpabon/godbc:all-srcs",
......@@ -273,6 +274,7 @@ filegroup(
"//vendor/github.com/mistifyio/go-zfs:all-srcs",
"//vendor/github.com/mitchellh/go-wordwrap:all-srcs",
"//vendor/github.com/mitchellh/mapstructure:all-srcs",
"//vendor/github.com/mohae/deepcopy:all-srcs",
"//vendor/github.com/mreiferson/go-httpclient:all-srcs",
"//vendor/github.com/mrunalp/fileutils:all-srcs",
"//vendor/github.com/mvdan/xurls:all-srcs",
......@@ -330,7 +332,6 @@ filegroup(
"//vendor/github.com/xanzy/go-cloudstack/cloudstack:all-srcs",
"//vendor/github.com/xiang90/probing:all-srcs",
"//vendor/github.com/xyproto/simpleredis:all-srcs",
"//vendor/go.pedge.io/pb/go/google/protobuf:all-srcs",
"//vendor/go4.org/errorutil:all-srcs",
"//vendor/golang.org/x/crypto/bcrypt:all-srcs",
"//vendor/golang.org/x/crypto/blowfish:all-srcs",
......
......@@ -10,7 +10,8 @@ go_library(
visibility = ["//visibility:public"],
deps = [
"//vendor/github.com/golang/protobuf/proto:go_default_library",
"//vendor/go.pedge.io/pb/go/google/protobuf:go_default_library",
"//vendor/github.com/golang/protobuf/ptypes/timestamp:go_default_library",
"//vendor/github.com/mohae/deepcopy:go_default_library",
],
)
......
# OpenStorage API usage
Any storage product that uses the openstorage API can be managed via this API. Below are some examples of using this API.
### Enumerate nodes in a cluster
```go
import (
...
"github.com/libopenstorage/gossip/types"
"github.com/libopenstorage/openstorage/api"
"github.com/libopenstorage/openstorage/api/client/cluster"
)
type myapp struct {
manager cluster.Cluster
}
func (c *myapp) init() {
// Choose the default version.
// Leave the host blank to use the local UNIX socket, or pass in an IP and a port at which the server is listening on.
clnt, err := cluster.NewClusterClient("", cluster.APIVersion)
if err != nil {
fmt.Printf("Failed to initialize client library: %v\n", err)
os.Exit(1)
}
c.manager = cluster.ClusterManager(clnt)
}
func (c *myapp) listNodes() {
cluster, err := c.manager.Enumerate()
if err != nil {
cmdError(context, fn, err)
return
}
// cluster is now a hashmap of nodes... do something useful with it:
for _, n := range cluster.Nodes {
}
}
```
### Inspect a volume in a cluster
```go
import (
...
"github.com/libopenstorage/openstorage/api"
volumeclient "github.com/libopenstorage/openstorage/api/client/volume"
"github.com/libopenstorage/openstorage/volume"
)
type myapp struct {
volDriver volume.VolumeDriver
}
func (c *myapp) init() {
// Choose the default version.
// Leave the host blank to use the local UNIX socket, or pass in an IP and a port at which the server is listening on.
clnt, err := volumeclient.NewDriverClient("", v.name, volume.APIVersion)
if err != nil {
fmt.Printf("Failed to initialize client library: %v\n", err)
os.Exit(1)
}
v.volDriver = volumeclient.VolumeDriver(clnt)
}
func (c *myapp) inspect(id string) {
stats, err := v.volDriver.Stats(id, true)
if err != nil {
return
}
// stats is an object that has various volume properties and statistics.
}
```
......@@ -90,6 +90,13 @@ enum CosType {
HIGH = 3;
}
enum IoProfile {
IO_PROFILE_SEQUENTIAL = 0;
IO_PROFILE_RANDOM= 1;
IO_PROFILE_DB = 2;
IO_PROFILE_DB_REMOTE = 3;
}
// VolumeState represents the state of a volume.
enum VolumeState {
VOLUME_STATE_NONE = 0;
......@@ -108,6 +115,10 @@ enum VolumeState {
// Volume is deleted, it will remain in this state
// while resources are asynchronously reclaimed
VOLUME_STATE_DELETED = 7;
// Volume is trying to be detached
VOLUME_STATE_TRY_DETACHING = 8;
// Volume is undergoing restore
VOLUME_STATE_RESTORE = 9;
}
// VolumeStatus represents a health status for a volume.
......@@ -138,6 +149,15 @@ enum ClusterNotify {
CLUSTER_NOTIFY_DOWN = 0;
}
enum AttachState {
// Attached and available externally
ATTACH_STATE_EXTERNAL = 0;
// Attached but only available internally
ATTACH_STATE_INTERNAL = 1;
// Switching from External to Internal
ATTACH_STATE_INTERNAL_SWITCH = 2;
}
// StorageResource groups properties of a storage device.
message StorageResource {
// Id is the LUN identifier.
......@@ -166,6 +186,24 @@ message StorageResource {
google.protobuf.Timestamp last_scan = 12;
}
// StoragePool groups different storage devices based on their CosType
message StoragePool {
// ID pool ID
int32 ID = 1;
// Cos reflects the capabilities of this drive pool
CosType Cos = 2;
// Medium underlying storage type
StorageMedium Medium = 3;
// RaidLevel storage raid level
string RaidLevel = 4;
// TotalSize of the pool
uint64 TotalSize = 7;
// Used size of the pool
uint64 Used = 8;
// Labels is a list of user defined name-value pairs
map<string, string> labels = 9;
}
// VolumeLocator is a structure that is attached to a volume
// and is used to carry opaque metadata.
message VolumeLocator {
......@@ -183,89 +221,115 @@ message Source {
string seed = 2;
}
message Group {
// Id common identifier across volumes that have the same group.
string id = 1;
}
// VolumeSpec has the properties needed to create a volume.
message VolumeSpec {
// Ephemeral storage
bool ephemeral = 1;
// Thin provisioned volume size in bytes
// Size specifies the thin provisioned volume size.
uint64 size = 2;
// Format disk with this FSType
// Format specifies the filesystem for this volume.
FSType format = 3;
// Block size for filesystem
// BlockSize for the filesystem.
int64 block_size = 4;
// Specifies the number of nodes that are
// allowed to fail, and yet data is available
// A value of 0 implies that data is not erasure coded,
// a failure of a node will lead to data loss
// HaLevel specifies the number of copies of data.
int64 ha_level = 5;
// The COS, 1 to 9
// Cos specifies the relative class of service.
CosType cos = 6;
// Perform dedupe on this disk
bool dedupe = 7;
// IoProfile provides a hint about application using this volume.
IoProfile io_profile = 7;
// Dedupe specifies if the volume data is to be de-duplicated.
bool dedupe = 8;
// SnapshotInterval in minutes, set to 0 to disable snapshots
uint32 snapshot_interval = 8;
// Volume configuration labels
map<string, string> volume_labels = 9;
uint32 snapshot_interval = 9;
// VolumeLabels configuration labels
map<string, string> volume_labels = 10;
// Shared is true if this volume can be remotely accessed.
bool shared = 10;
// ReplicaSet is the desired replicaSet the volume want to be placed.
ReplicaSet replica_set = 11;
// Specifies the number of parts the volume can be aggregated from.
uint32 aggregation_level = 12;
bool shared = 11;
// ReplicaSet is the desired set of nodes for the volume data.
ReplicaSet replica_set = 12;
// Aggregatiokn level Specifies the number of parts the volume can be aggregated from.
uint32 aggregation_level = 13;
// Encrypted is true if this volume will be cryptographically secured.
bool encrypted = 13;
// User passphrase if this is an encrypted volume
string passphrase = 14;
// SnapshotSchedule
string snapshot_schedule = 15;
bool encrypted = 14;
// Passphrase for an encrypted volume
string passphrase = 15;
// SnapshotSchedule a well known string that specifies when snapshots should be taken.
string snapshot_schedule = 16;
// Scale allows autocreation of volumes.
uint32 scale = 16;
}
// Set of machine IDs (nodes) to which part of this volume is erasure coded - for clustered storage arrays
uint32 scale = 17;
// Sticky volumes cannot be deleted until the flag is removed.
bool sticky = 18;
// Group identifies a consistency group
Group group = 21;
// GroupEnforced is true if consistency group creation is enforced.
bool group_enforced = 22;
// Compressed is true if this volume is to be compressed.
bool compressed = 23;
}
// ReplicaSet set of machine IDs (nodes) to which part of this volume is erasure
// coded - for clustered storage arrays
message ReplicaSet {
repeated string nodes = 1;
}
// List of name value mapping of driver specific runtime information.
// RuntimeStateMap is a list of name value mapping of driver specific runtime
// information.
message RuntimeStateMap {
map<string, string> runtime_state = 1;
}
// Volume represents a live, created volume.
// Volume represents an abstract storage volume.
// Volume represents an abstract storage volume.
message Volume {
// Self referential volume ID
// Self referential volume ID.
string id = 1;
// Source specified seed data for the volume.
Source source = 2;
bool readonly = 3;
// Group volumes in the same group have the same group id.
Group group = 3;
// Readonly is true if this volume is to be mounted with readonly access.
bool readonly = 4;
// User specified locator
VolumeLocator locator = 4;
VolumeLocator locator = 5;
// Volume creation time
google.protobuf.Timestamp ctime = 5;
google.protobuf.Timestamp ctime = 6;
// User specified VolumeSpec
VolumeSpec spec = 6;
// Volume usage
uint64 usage = 7;
// Time when an integrity check for run
google.protobuf.Timestamp last_scan = 8;
// Format FSType type if any
FSType format = 9;
VolumeStatus status = 10;
VolumeState state = 11;
// Machine ID (node) on which this volume is attached
// Machine ID is a node instance identifier for clustered systems.
string attached_on = 12;
string device_path = 14;
repeated string attach_path = 15;
// List of ReplicaSets which provide storage for this volume, for clustered storage arrays
repeated ReplicaSet replica_sets = 16;
// Last recorded error
string error = 17;
// List of name value mapping of driver specific runtime information.
repeated RuntimeStateMap runtime_state = 18;
string secure_device_path = 19;
// BackgroundProcessing is true if volume is attached but not by the user
bool background_processing = 20;
VolumeSpec spec = 7;
// Usage is bytes consumed by vtheis volume.
uint64 usage = 8;
// LastScan is the time when an integrity check was run.
google.protobuf.Timestamp last_scan = 9;
// Format specifies the filesytem for this volume.
FSType format = 10;
// Status is the availability status of this volume.
VolumeStatus status = 11;
// State is the current runtime state of this volume.
VolumeState state = 12;
// AttachedOn is the node instance identifier for clustered systems.
string attached_on = 13;
// AttachedState shows whether the device is attached for internal or external use.
AttachState attached_state = 14;
// DevicePath is the device exported by block device implementations.
string device_path = 15;
// SecureDevicePath is the device path for an encrypted volume.
string secure_device_path = 16;
// AttachPath is the mounted path in the host namespace.
repeated string attach_path = 17;
// AttachInfo is a list of name value mappings that provides attach information.
map<string, string> attach_info = 18;
// ReplicatSets storage for this volumefor clustered storage arrays.
repeated ReplicaSet replica_sets = 19;
// RuntimeState is a lst of name value mapping of driver specific runtime
// information.
repeated RuntimeStateMap runtime_state = 20;
// Error is the Last recorded error.
string error = 21;
}
message Stats {
......@@ -308,6 +372,8 @@ message Alert {
bool cleared = 8;
// TTL in seconds for this Alert
uint64 ttl = 9;
// UniqueTag helps identify a unique alert for a given resouce
string unique_tag = 10;
}
message Alerts {
......@@ -339,9 +405,13 @@ message VolumeStateAction {
VolumeActionParam attach = 1;
// Mount or unmount volume
VolumeActionParam mount = 2;
// MountPath Path where the device is mounted
string mount_path = 3;
// Device path returned in attach
// DevicePath Path returned in attach
string device_path = 4;
// UnmountBeforeDetach is used to check whether unmount should be done before
// a detach
bool unmount_before_detach = 5;
}
message VolumeSetRequest {
......@@ -351,6 +421,9 @@ message VolumeSetRequest {
VolumeSpec spec = 2;
// State modification on this volume.
VolumeStateAction action = 3;
// additional options
// required for the Set operation.
map<string, string> options = 4;
}
message VolumeSetResponse {
......
......@@ -16,7 +16,7 @@ var (
)
// NewClient returns a new REST client for specified server.
func NewClient(host string, version string) (*Client, error) {
func NewClient(host, version, userAgent string) (*Client, error) {
baseURL, err := url.Parse(host)
if err != nil {
return nil, err
......@@ -25,14 +25,48 @@ func NewClient(host string, version string) (*Client, error) {
baseURL.Path = "/"
}
unix2HTTP(baseURL)
hClient := getHTTPClient(host)
if hClient == nil {
return nil, fmt.Errorf("Unable to parse provided url: %v", host)
}
c := &Client{
base: baseURL,
version: version,
httpClient: hClient,
authstring: "",
accesstoken: "",
userAgent: fmt.Sprintf("%v/%v", userAgent, version),
}
return c, nil
}
// NewAuthClient returns a new REST client for specified server.
func NewAuthClient(host, version, authstring, accesstoken, userAgent string) (*Client, error) {
baseURL, err := url.Parse(host)
if err != nil {
return nil, err
}
if baseURL.Path == "" {
baseURL.Path = "/"
}
unix2HTTP(baseURL)
hClient := getHTTPClient(host)
if hClient == nil {
return nil, fmt.Errorf("Unable to parse provided url: %v", host)
}
c := &Client{
base: baseURL,
version: version,
httpClient: getHttpClient(host),
base: baseURL,
version: version,
httpClient: hClient,
authstring: authstring,
accesstoken: accesstoken,
userAgent: fmt.Sprintf("%v/%v", userAgent, version),
}
return c, nil
}
// GetUnixServerPath returns a unix domain socket prepended with the
// provided path.
func GetUnixServerPath(socketName string, paths ...string) string {
serverPath := "unix://"
for _, path := range paths {
......@@ -42,13 +76,15 @@ func GetUnixServerPath(socketName string, paths ...string) string {
return serverPath
}
// Client is an HTTP REST wrapper. Use one of Get/Post/Put/Delete to get a request
// object.
type Client struct {
base *url.URL
version string
httpClient *http.Client
base *url.URL
version string
httpClient *http.Client
authstring string
accesstoken string
userAgent string
}
// Status sends a Status request at the /status REST endpoint.
......@@ -58,7 +94,7 @@ func (c *Client) Status() (*Status, error) {
return status, err
}
// Version send a request at the /versions REST endpoint.
// Versions send a request at the /versions REST endpoint.
func (c *Client) Versions(endpoint string) ([]string, error) {
versions := []string{}
err := c.Get().Resource(endpoint + "/versions").Do().Unmarshal(&versions)
......@@ -67,22 +103,22 @@ func (c *Client) Versions(endpoint string) ([]string, error) {
// Get returns a Request object setup for GET call.
func (c *Client) Get() *Request {
return NewRequest(c.httpClient, c.base, "GET", c.version)
return NewRequest(c.httpClient, c.base, "GET", c.version, c.authstring, c.userAgent)
}
// Post returns a Request object setup for POST call.
func (c *Client) Post() *Request {
return NewRequest(c.httpClient, c.base, "POST", c.version)
return NewRequest(c.httpClient, c.base, "POST", c.version, c.authstring, c.userAgent)
}
// Put returns a Request object setup for PUT call.
func (c *Client) Put() *Request {
return NewRequest(c.httpClient, c.base, "PUT", c.version)
return NewRequest(c.httpClient, c.base, "PUT", c.version, c.authstring, c.userAgent)
}
// Put returns a Request object setup for DELETE call.
// Delete returns a Request object setup for DELETE call.
func (c *Client) Delete() *Request {
return NewRequest(c.httpClient, c.base, "DELETE", c.version)
return NewRequest(c.httpClient, c.base, "DELETE", c.version, c.authstring, c.userAgent)
}
func unix2HTTP(u *url.URL) {
......@@ -94,7 +130,12 @@ func unix2HTTP(u *url.URL) {
}
}
func newHTTPClient(u *url.URL, tlsConfig *tls.Config, timeout time.Duration) *http.Client {
func newHTTPClient(
u *url.URL,
tlsConfig *tls.Config,
timeout time.Duration,
responseTimeout time.Duration,
) *http.Client {
httpTransport := &http.Transport{
TLSClientConfig: tlsConfig,
}
......@@ -114,28 +155,24 @@ func newHTTPClient(u *url.URL, tlsConfig *tls.Config, timeout time.Duration) *ht
}
}
return &http.Client{Transport: httpTransport}
return &http.Client{Transport: httpTransport, Timeout: responseTimeout}
}
func getHttpClient(host string) *http.Client {
func getHTTPClient(host string) *http.Client {
cacheLock.Lock()
defer cacheLock.Unlock()
c, ok := httpCache[host]
if !ok {
cacheLock.Lock()
defer cacheLock.Unlock()
c, ok = httpCache[host]
if !ok {
u, err := url.Parse(host)
if err != nil {
// TODO(pedge): clean up
fmt.Println("Failed to parse into url", host)
return nil
}
if u.Path == "" {
u.Path = "/"
}
c = newHTTPClient(u, nil, 10*time.Second)
httpCache[host] = c
u, err := url.Parse(host)
if err != nil {
return nil
}
if u.Path == "" {
u.Path = "/"
}
c = newHTTPClient(u, nil, 10*time.Second, 5*time.Minute)
httpCache[host] = c
}
return c
}
......@@ -11,6 +11,7 @@ import (
"strconv"
"strings"
"time"
"math/rand"
)
// Request is contructed iteratively by the client and finally dispatched.
......@@ -31,6 +32,8 @@ type Request struct {
req *http.Request
resp *http.Response
timeout time.Duration
authstring string
accesstoken string
}
// Response is a representation of HTTP response received from the server.
......@@ -48,14 +51,17 @@ type Status struct {
}
// NewRequest instance
func NewRequest(client *http.Client, base *url.URL, verb string, version string) *Request {
return &Request{
func NewRequest(client *http.Client, base *url.URL, verb string, version string, authstring, userAgent string) *Request {
r := &Request{
client: client,
verb: verb,
base: base,
path: base.Path,
version: version,
authstring: authstring,
}
r.SetHeader("User-Agent", userAgent)
return r
}
func checkExists(mustExist string, before string) error {
......@@ -251,8 +257,19 @@ func (r *Request) Do() *Response {
if r.headers == nil {
r.headers = http.Header{}
}
req.Header = r.headers
req.Header.Set("Content-Type", "application/json")
req.Header.Set("Date", time.Now().String())
if len(r.authstring) > 0 {
req.Header.Set("Authorization", "Basic "+ r.authstring)
}
if len(r.accesstoken) > 0 {
req.Header.Set("Access-Token", r.accesstoken)
}
resp, err = r.client.Do(req)
if err != nil {
return &Response{err: err}
......@@ -295,10 +312,21 @@ func (r Response) Error() error {
return r.err
}
// FormatError formats the error
func (r Response) FormatError() error {
if len(r.body) == 0 {
return fmt.Errorf("Error: %v", r.err)
} else {
return fmt.Errorf("HTTP-%d: %s", r.statusCode, string(r.body))
}
return fmt.Errorf("HTTP-%d: %s", r.statusCode, string(r.body))
}
func digest(method string, path string) string {
now := time.Now().String()
s1 := rand.NewSource(time.Now().UnixNano())
r1 := rand.New(s1)
nonce := r1.Intn(10)
return method + "+" + path + "+" + now + "+" + strconv.Itoa(nonce)
}
......@@ -195,6 +195,21 @@ func (v *volumeClient) Snapshot(volumeID string, readonly bool,
return "", nil
}
// Restore specified volume to given snapshot state
func (v *volumeClient) Restore(volumeID string, snapID string) error {
response := &api.VolumeResponse{}
req := v.c.Post().Resource(snapPath + "/restore").Instance(volumeID)
req.QueryOption(api.OptSnapID, snapID)
if err := req.Do().Unmarshal(response); err != nil {
return err
}
if response.Error != "" {
return errors.New(response.Error)
}
return nil
}
// Stats for specified volume.
// Errors ErrEnoEnt may be returned
func (v *volumeClient) Stats(
......@@ -205,21 +220,20 @@ func (v *volumeClient) Stats(
req := v.c.Get().Resource(volumePath + "/stats").Instance(volumeID)
req.QueryOption(api.OptCumulative, strconv.FormatBool(cumulative))
if err := req.Do().Unmarshal(stats); err != nil {
return nil, err
}
err := req.Do().Unmarshal(stats)
return stats, err
return stats, nil
}
// Alerts on this volume.
// UsedSize returns allocated volume size.
// Errors ErrEnoEnt may be returned
func (v *volumeClient) Alerts(volumeID string) (*api.Alerts, error) {
alerts := &api.Alerts{}
if err := v.c.Get().Resource(volumePath + "/alerts").Instance(volumeID).Do().Unmarshal(alerts); err != nil {
return nil, err
}
return alerts, nil
func (v *volumeClient) UsedSize(
volumeID string,
) (uint64, error) {
var usedSize uint64
req := v.c.Get().Resource(volumePath + "/usedsize").Instance(volumeID)
err := req.Do().Unmarshal(&usedSize)
return usedSize, err
}
// Active Requests on all volume.
......@@ -289,13 +303,14 @@ func (v *volumeClient) SnapEnumerate(ids []string,
// Attach map device to the host.
// On success the devicePath specifies location where the device is exported
// Errors ErrEnoEnt, ErrVolAttached may be returned.
func (v *volumeClient) Attach(volumeID string) (string, error) {
func (v *volumeClient) Attach(volumeID string, attachOptions map[string]string) (string, error) {
response, err := v.doVolumeSetGetResponse(
volumeID,
&api.VolumeSetRequest{
Action: &api.VolumeStateAction{
Attach: api.VolumeActionParam_VOLUME_ACTION_PARAM_ON,
},
Options: attachOptions,
},
)
if err != nil {
......@@ -313,12 +328,13 @@ func (v *volumeClient) Attach(volumeID string) (string, error) {
// Detach device from the host.
// Errors ErrEnoEnt, ErrVolDetached may be returned.
func (v *volumeClient) Detach(volumeID string) error {
func (v *volumeClient) Detach(volumeID string, unmountBeforeDetach bool) error {
return v.doVolumeSet(
volumeID,
&api.VolumeSetRequest{
Action: &api.VolumeStateAction{
Attach: api.VolumeActionParam_VOLUME_ACTION_PARAM_OFF,
Attach: api.VolumeActionParam_VOLUME_ACTION_PARAM_OFF,
UnmountBeforeDetach: unmountBeforeDetach,
},
},
)
......
......@@ -2,9 +2,9 @@ package volume
import (
"fmt"
"github.com/libopenstorage/openstorage/api"
"github.com/libopenstorage/openstorage/api/client"
"github.com/libopenstorage/openstorage/volume"
"github.com/libopenstorage/openstorage/api"
)
// VolumeDriver returns a REST wrapper for the VolumeDriver interface.
......@@ -12,10 +12,27 @@ func VolumeDriver(c *client.Client) volume.VolumeDriver {
return newVolumeClient(c)
}
// NewDriver returns a new REST client of the supplied version for specified driver.
// NewAuthDriverClient returns a new REST client of the supplied version for specified driver.
// host: REST endpoint [http://<ip>:<port> OR unix://<path-to-unix-socket>]. default: [unix:///var/lib/osd/<driverName>.sock]
// version: Volume API version
func NewAuthDriverClient(host, driverName, version, authstring, accesstoken, userAgent string) (*client.Client, error) {
if driverName == "" {
return nil, fmt.Errorf("Driver Name cannot be empty")
}
if host == "" {
host = client.GetUnixServerPath(driverName, volume.DriverAPIBase)
}
if version == "" {
// Set the default version
version = volume.APIVersion
}
return client.NewAuthClient(host, version, authstring, accesstoken, userAgent)
}
// NewDriverClient returns a new REST client of the supplied version for specified driver.
// host: REST endpoint [http://<ip>:<port> OR unix://<path-to-unix-socket>]. default: [unix:///var/lib/osd/<driverName>.sock]
// version: Volume API version
func NewDriverClient(host, driverName, version string) (*client.Client, error) {
func NewDriverClient(host, driverName, version, userAgent string) (*client.Client, error) {
if driverName == "" {
return nil, fmt.Errorf("Driver Name cannot be empty")
}
......@@ -26,7 +43,7 @@ func NewDriverClient(host, driverName, version string) (*client.Client, error) {
// Set the default version
version = volume.APIVersion
}
return client.NewClient(host, version)
return client.NewClient(host, version, userAgent)
}
// GetSupportedDriverVersions returns a list of supported versions
......@@ -38,7 +55,7 @@ func GetSupportedDriverVersions(driverName, host string) ([]string, error) {
host = client.GetUnixServerPath(driverName, volume.DriverAPIBase)
}
client, err := client.NewClient(host, "")
client, err := client.NewClient(host, "", "")
if err != nil {
return []string{}, err
}
......
......@@ -6,6 +6,7 @@ go_library(
visibility = ["//visibility:public"],
deps = [
"//vendor/github.com/libopenstorage/openstorage/api:go_default_library",
"//vendor/github.com/libopenstorage/openstorage/pkg/parser:go_default_library",
"//vendor/github.com/libopenstorage/openstorage/pkg/units:go_default_library",
],
)
......
package api
// StatusKind indicates the severity of a status
type StatusKind int32
const (
......@@ -12,32 +13,35 @@ const (
)
var statusToStatusKind = map[Status]StatusKind{
Status_STATUS_NONE: StatusSeverityHigh,
Status_STATUS_INIT: StatusSeverityMedium,
Status_STATUS_OK: StatusSeverityLow,
Status_STATUS_OFFLINE: StatusSeverityHigh,
Status_STATUS_ERROR: StatusSeverityHigh,
Status_STATUS_NOT_IN_QUORUM: StatusSeverityHigh,
Status_STATUS_DECOMMISSION: StatusSeverityHigh,
Status_STATUS_MAINTENANCE: StatusSeverityHigh,
Status_STATUS_STORAGE_DOWN: StatusSeverityHigh,
Status_STATUS_STORAGE_DEGRADED: StatusSeverityHigh,
Status_STATUS_NEEDS_REBOOT: StatusSeverityHigh,
Status_STATUS_STORAGE_REBALANCE: StatusSeverityMedium,
Status_STATUS_STORAGE_DRIVE_REPLACE: StatusSeverityMedium,
Status_STATUS_NONE: StatusSeverityHigh,
Status_STATUS_INIT: StatusSeverityMedium,
Status_STATUS_OK: StatusSeverityLow,
Status_STATUS_OFFLINE: StatusSeverityHigh,
Status_STATUS_ERROR: StatusSeverityHigh,
Status_STATUS_NOT_IN_QUORUM: StatusSeverityHigh,
Status_STATUS_DECOMMISSION: StatusSeverityHigh,
Status_STATUS_MAINTENANCE: StatusSeverityHigh,
Status_STATUS_STORAGE_DOWN: StatusSeverityHigh,
Status_STATUS_STORAGE_DEGRADED: StatusSeverityHigh,
Status_STATUS_NEEDS_REBOOT: StatusSeverityHigh,
Status_STATUS_STORAGE_REBALANCE: StatusSeverityMedium,
Status_STATUS_STORAGE_DRIVE_REPLACE: StatusSeverityMedium,
// Add statuses before MAX
Status_STATUS_MAX: StatusSeverityHigh,
}
// StatusSimpleValueOf returns the string format of Status
func StatusSimpleValueOf(s string) (Status, error) {
obj, err := simpleValueOf("status", Status_value, s)
return Status(obj), err
}
// SimpleString returns the string format of Status
func (x Status) SimpleString() string {
return simpleString("status", Status_name, int32(x))
}
// StatusKind returns the king of status
func (x Status) StatusKind() StatusKind {
statusType, _ := statusToStatusKind[x]
return statusType
......
......@@ -2,21 +2,8 @@ load("@io_bazel_rules_go//go:def.bzl", "go_library")
go_library(
name = "go_default_library",
srcs = [
"any.pb.go",
"api.pb.go",
"duration.pb.go",
"empty.pb.go",
"field_mask.pb.go",
"protobuf.gen.go",
"source_context.pb.go",
"struct.pb.go",
"timestamp.pb.go",
"type.pb.go",
"wrappers.pb.go",
],
srcs = ["labels.go"],
visibility = ["//visibility:public"],
deps = ["//vendor/github.com/golang/protobuf/proto:go_default_library"],
)
filegroup(
......
package parser
import (
"fmt"
"strings"
)
const (
NoLabel = "NoLabel"
)
func LabelsFromString(str string) (map[string]string, error) {
if len(str) == 0 {
return nil, nil
}
labels := strings.Split(str, ",")
m := make(map[string]string, len(labels))
for _, v := range labels {
if strings.Contains(v, "=") {
label := strings.SplitN(v, "=", 2)
if len(label) != 2 {
return m, fmt.Errorf("Malformed label: %s", v)
}
if _, ok := m[label[0]]; ok {
return m, fmt.Errorf("Duplicate label: %s", v)
}
m[label[0]] = label[1]
} else if len(v) != 0 {
m[v] = ""
}
}
return m, nil
}
func LabelsToString(labels map[string]string) string {
l := ""
for k, v := range labels {
if len(l) != 0 {
l += ","
}
if len(v) != 0 {
l += k + "=" + v
} else if len(k) != 0 {
l += k
}
}
return l
}
func MergeLabels(old map[string]string, new map[string]string) map[string]string {
if old == nil {
return new
}
if new == nil {
return old
}
m := make(map[string]string, len(old)+len(new))
for k, v := range old {
m[k] = v
}
for k, v := range new {
m[k] = v
}
return m
}
func HasLabels(set map[string]string, subset map[string]string) bool {
for k, v1 := range subset {
if v2, ok := set[k]; !ok || v1 != v2 {
return false
}
}
return true
}
......@@ -40,16 +40,16 @@ var (
"B": 1,
"b": 1,
"KB": KB,
"kb": KB,
"MB": MB,
"mb": MB,
"GB": GB,
"gb": GB,
"TB": TB,
"tb": TB,
"PB": PB,
"pb": PB,
"KB": KiB,
"kb": KiB,
"MB": MiB,
"mb": MiB,
"GB": GiB,
"gb": GiB,
"TB": TiB,
"tb": TiB,
"PB": PiB,
"pb": PiB,
"K": KiB,
"k": KiB,
......
......@@ -7,30 +7,67 @@ import (
)
var (
ErrAlreadyShutdown = errors.New("VolumeDriverProvider already shutdown")
ErrExist = errors.New("Driver already exists")
ErrDriverNotFound = errors.New("Driver implementation not found")
ErrDriverInitializing = errors.New("Driver is initializing")
ErrEnoEnt = errors.New("Volume does not exist.")
ErrEnomem = errors.New("Out of memory.")
ErrEinval = errors.New("Invalid argument")
ErrVolDetached = errors.New("Volume is detached")
ErrVolAttached = errors.New("Volume is attached")
// ErrAlreadyShutdown returned when driver is shutdown
ErrAlreadyShutdown = errors.New("VolumeDriverProvider already shutdown")
// ErrExit returned when driver already registered
ErrExist = errors.New("Already exists")
// ErrDriverNotFound returned when a driver is not registered
ErrDriverNotFound = errors.New("Driver implementation not found")
// ErrDriverInitializing returned when a driver is initializing
ErrDriverInitializing = errors.New("Driver is initializing")
// ErrEnoEnt returned when volume does not exist
ErrEnoEnt = errors.New("Volume does not exist.")
// ErrEnomem returned when we are out of memory
ErrEnomem = errors.New("Out of memory.")
// ErrEinval returned when an invalid input is provided
ErrEinval = errors.New("Invalid argument")
// ErrVolDetached returned when volume is in detached state
ErrVolDetached = errors.New("Volume is detached")
// ErrVolAttached returned when volume is in attached state
ErrVolAttached = errors.New("Volume is attached")
// ErrVolAttachedOnRemoteNode returned when volume is in attached on different node
ErrVolAttachedOnRemoteNode = errors.New("Volume is attached on another node")
ErrVolAttachedScale = errors.New("Volume is attached but can be scaled")
ErrVolHasSnaps = errors.New("Volume has snapshots associated")
ErrNotSupported = errors.New("Operation not supported")
// ErrVolAttachedScale returned when volume is attached and can be scaled
ErrVolAttachedScale = errors.New("Volume is attached on another node." +
" Increase scale factor to create more instances")
// ErrVolHasSnaps returned when volume has previous snapshots
ErrVolHasSnaps = errors.New("Volume has snapshots associated")
// ErrNotSupported returned when the operation is not supported
ErrNotSupported = errors.New("Operation not supported")
// ErrVolBusy returned when volume is in busy state
ErrVolBusy = errors.New("Volume is busy")
)
// Constants used by the VolumeDriver
const (
APIVersion = "v1"
// APIVersion for the volume management apis
APIVersion = "v1"
// PluginAPIBase where the docker unix socket resides
PluginAPIBase = "/run/docker/plugins/"
// DriverAPIBase where the osd unix socket resides
DriverAPIBase = "/var/lib/osd/driver/"
MountBase = "/var/lib/osd/mounts/"
VolumeBase = "/var/lib/osd/"
// MountBase for osd mountpoints
MountBase = "/var/lib/osd/mounts/"
// VolumeBase for osd volumes
VolumeBase = "/var/lib/osd/"
)
const (
// LocationConstaint is a label that specifies data location constraint.
LocationConstraint = "LocationConstraint"
// LocalNode is an alias for this node - similar to localhost.
LocalNode = "LocalNode"
)
// AttachOptionsKey specifies a key type from a key-value pair
// that will be passed in to the Attach api
type AttachOptionsKey string
const (
AttachOptionsSecret = AttachOptionsKey("SECRET_KEY")
)
// Store defines the interface for basic volume store operations
type Store interface {
// Lock volume specified by volumeID.
Lock(volumeID string) (interface{}, error)
......@@ -68,16 +105,34 @@ type IODriver interface {
Flush(volumeID string) error
}
// SnapshotDriver interfaces provides snapshot capability
type SnapshotDriver interface {
// Snapshot create volume snapshot.
// Errors ErrEnoEnt may be returned
Snapshot(volumeID string, readonly bool, locator *api.VolumeLocator) (string, error)
// Restore restores volume to specified snapshot.
Restore(volumeID string, snapshotID string) error
}
// StatsDriver interface provides stats features
type StatsDriver interface {
// Stats for specified volume.
// cumulative stats are /proc/diskstats style stats.
// nonCumulative stats are stats for specific duration.
// Errors ErrEnoEnt may be returned
Stats(volumeID string, cumulative bool) (*api.Stats, error)
// UsedSize returns currently used volume size.
// Errors ErrEnoEnt may be returned.
UsedSize(volumeID string) (uint64, error)
// GetActiveRequests get active requests
GetActiveRequests() (*api.ActiveRequests, error)
}
// ProtoDriver must be implemented by all volume drivers. It specifies the
// most basic functionality, such as creating and deleting volumes.
type ProtoDriver interface {
SnapshotDriver
StatsDriver
// Name returns the name of the driver.
Name() string
// Type of this driver
......@@ -99,16 +154,6 @@ type ProtoDriver interface {
// Update not all fields of the spec are supported, ErrNotSupported will be thrown for unsupported
// updates.
Set(volumeID string, locator *api.VolumeLocator, spec *api.VolumeSpec) error
// Stats for specified volume.
// cumulative stats are /proc/diskstats style stats.
// nonCumulative stats are stats for specific duration.
// Errors ErrEnoEnt may be returned
Stats(volumeID string, cumulative bool) (*api.Stats, error)
// Alerts on this volume.
// Errors ErrEnoEnt may be returned
Alerts(volumeID string) (*api.Alerts, error)
// GetActiveRequests get active requests
GetActiveRequests() (*api.ActiveRequests, error)
// Status returns a set of key-value pairs which give low
// level diagnostic status about this driver.
Status() [][2]string
......@@ -128,6 +173,7 @@ type Enumerator interface {
SnapEnumerate(volID []string, snapLabels map[string]string) ([]*api.Volume, error)
}
// StoreEnumerator combines Store and Enumerator capabilities
type StoreEnumerator interface {
Store
Enumerator
......@@ -139,10 +185,10 @@ type BlockDriver interface {
// Attach map device to the host.
// On success the devicePath specifies location where the device is exported
// Errors ErrEnoEnt, ErrVolAttached may be returned.
Attach(volumeID string) (string, error)
Attach(volumeID string, attachOptions map[string]string) (string, error)
// Detach device from the host.
// Errors ErrEnoEnt, ErrVolDetached may be returned.
Detach(volumeID string) error
Detach(volumeID string, unmountBeforeDetach bool) error
}
// VolumeDriverProvider provides VolumeDrivers.
......@@ -165,7 +211,7 @@ type VolumeDriverRegistry interface {
Add(name string, init func(map[string]string) (VolumeDriver, error)) error
}
// VolumeDriverRegistry constructs a new VolumeDriverRegistry.
// NewVolumeDriverRegistry constructs a new VolumeDriverRegistry.
func NewVolumeDriverRegistry(nameToInitFunc map[string]func(map[string]string) (VolumeDriver, error)) VolumeDriverRegistry {
return newVolumeDriverRegistry(nameToInitFunc)
}
......@@ -8,19 +8,24 @@ var (
// BlockNotSupported is a default (null) block driver implementation. This can be
// used by drivers that do not want to (or care about) implementing the attach,
// format and detach interfaces.
BlockNotSupported = &blockNotSupported{}
BlockNotSupported = &blockNotSupported{}
// SnapshotNotSupported is a null snapshot driver implementation. This can be used
// by drivers that do not want to implement the snapshot interface
SnapshotNotSupported = &snapshotNotSupported{}
IONotSupported = &ioNotSupported{}
// IONotSupported is a null IODriver interface
IONotSupported = &ioNotSupported{}
// StatsNotSupported is a null stats driver implementation. This can be used
// by drivers that do not want to implement the stats interface.
StatsNotSupported = &statsNotSupported{}
)
type blockNotSupported struct{}
func (b *blockNotSupported) Attach(volumeID string) (string, error) {
func (b *blockNotSupported) Attach(volumeID string, attachOptions map[string]string) (string, error) {
return "", ErrNotSupported
}
func (b *blockNotSupported) Detach(volumeID string) error {
func (b *blockNotSupported) Detach(volumeID string, unmountBeforeDetach bool) error {
return ErrNotSupported
}
......@@ -30,6 +35,10 @@ func (s *snapshotNotSupported) Snapshot(volumeID string, readonly bool, locator
return "", ErrNotSupported
}
func (s *snapshotNotSupported) Restore(volumeID, snapshotID string) error {
return ErrNotSupported
}
type ioNotSupported struct{}
func (i *ioNotSupported) Read(volumeID string, buffer []byte, size uint64, offset int64) (int64, error) {
......@@ -43,3 +52,23 @@ func (i *ioNotSupported) Write(volumeID string, buffer []byte, size uint64, offs
func (i *ioNotSupported) Flush(volumeID string) error {
return ErrNotSupported
}
type statsNotSupported struct{}
// Stats returns stats
func (s *statsNotSupported) Stats(
volumeID string,
cumulative bool,
) (*api.Stats, error) {
return nil, ErrNotSupported
}
// UsedSize returns allocated size
func (s *statsNotSupported) UsedSize(volumeID string) (uint64, error) {
return 0, ErrNotSupported
}
// GetActiveRequests gets active requests
func (s *statsNotSupported) GetActiveRequests() (*api.ActiveRequests, error) {
return nil, nil
}
# Compiled Object files, Static and Dynamic libs (Shared Objects)
*.o
*.a
*.so
# Folders
_obj
_test
# Architecture specific extensions/prefixes
*.[568vq]
[568vq].out
*.cgo1.go
*.cgo2.c
_cgo_defun.c
_cgo_gotypes.go
_cgo_export.*
_testmain.go
*.exe
*.test
*~
*.out
*.log
language: go
go:
- tip
matrix:
allow_failures:
- go: tip
script:
- go test ./...
load("@io_bazel_rules_go//go:def.bzl", "go_library")
go_library(
name = "go_default_library",
srcs = ["deepcopy.go"],
visibility = ["//visibility:public"],
)
filegroup(
name = "package-srcs",
srcs = glob(["**"]),
tags = ["automanaged"],
visibility = ["//visibility:private"],
)
filegroup(
name = "all-srcs",
srcs = [":package-srcs"],
tags = ["automanaged"],
visibility = ["//visibility:public"],
)
The MIT License (MIT)
Copyright (c) 2015 Peter Edge
Copyright (c) 2014 Joel
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
......@@ -19,4 +19,3 @@ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
deepCopy
========
[![GoDoc](https://godoc.org/github.com/mohae/deepcopy?status.svg)](https://godoc.org/github.com/mohae/deepcopy)[![Build Status](https://travis-ci.org/mohae/deepcopy.png)](https://travis-ci.org/mohae/deepcopy)
DeepCopy makes deep copies of things: unexported field values are not copied.
## Usage
cpy := deepcopy.Copy(orig)
// deepcopy makes deep copies of things. A standard copy will copy the
// pointers: deep copy copies the values pointed to. Unexported field
// values are not copied.
//
// Copyright (c)2014-2016, Joel Scoble (github.com/mohae), all rights reserved.
// License: MIT, for more details check the included LICENSE file.
package deepcopy
import (
"reflect"
"time"
)
// Iface is an alias to Copy; this exists for backwards compatibility reasons.
func Iface(iface interface{}) interface{} {
return Copy(iface)
}
// Copy creates a deep copy of whatever is passed to it and returns the copy
// in an interface{}. The returned value will need to be asserted to the
// correct type.
func Copy(src interface{}) interface{} {
if src == nil {
return nil
}
// Make the interface a reflect.Value
original := reflect.ValueOf(src)
// Make a copy of the same type as the original.
cpy := reflect.New(original.Type()).Elem()
// Recursively copy the original.
copyRecursive(original, cpy)
// Return the copy as an interface.
return cpy.Interface()
}
// copyRecursive does the actual copying of the interface. It currently has
// limited support for what it can handle. Add as needed.
func copyRecursive(original, cpy reflect.Value) {
// handle according to original's Kind
switch original.Kind() {
case reflect.Ptr:
// Get the actual value being pointed to.
originalValue := original.Elem()
// if it isn't valid, return.
if !originalValue.IsValid() {
return
}
cpy.Set(reflect.New(originalValue.Type()))
copyRecursive(originalValue, cpy.Elem())
case reflect.Interface:
// If this is a nil, don't do anything
if original.IsNil() {
return
}
// Get the value for the interface, not the pointer.
originalValue := original.Elem()
// Get the value by calling Elem().
copyValue := reflect.New(originalValue.Type()).Elem()
copyRecursive(originalValue, copyValue)
cpy.Set(copyValue)
case reflect.Struct:
t, ok := original.Interface().(time.Time)
if ok {
cpy.Set(reflect.ValueOf(t))
return
}
// Go through each field of the struct and copy it.
for i := 0; i < original.NumField(); i++ {
// The Type's StructField for a given field is checked to see if StructField.PkgPath
// is set to determine if the field is exported or not because CanSet() returns false
// for settable fields. I'm not sure why. -mohae
if original.Type().Field(i).PkgPath != "" {
continue
}
copyRecursive(original.Field(i), cpy.Field(i))
}
case reflect.Slice:
if original.IsNil() {
return
}
// Make a new slice and copy each element.
cpy.Set(reflect.MakeSlice(original.Type(), original.Len(), original.Cap()))
for i := 0; i < original.Len(); i++ {
copyRecursive(original.Index(i), cpy.Index(i))
}
case reflect.Map:
if original.IsNil() {
return
}
cpy.Set(reflect.MakeMap(original.Type()))
for _, key := range original.MapKeys() {
originalValue := original.MapIndex(key)
copyValue := reflect.New(originalValue.Type()).Elem()
copyRecursive(originalValue, copyValue)
copyKey := Copy(key.Interface())
cpy.SetMapIndex(reflect.ValueOf(copyKey), copyValue)
}
default:
cpy.Set(original)
}
}
// Code generated by protoc-gen-go.
// source: google/protobuf/any.proto
// DO NOT EDIT!
package google_protobuf
import proto "github.com/golang/protobuf/proto"
import fmt "fmt"
import math "math"
// Reference imports to suppress errors if they are not otherwise used.
var _ = proto.Marshal
var _ = fmt.Errorf
var _ = math.Inf
// This is a compile-time assertion to ensure that this generated file
// is compatible with the proto package it is being compiled against.
// A compilation error at this line likely means your copy of the
// proto package needs to be updated.
const _ = proto.ProtoPackageIsVersion2 // please upgrade the proto package
// `Any` contains an arbitrary serialized message along with a URL
// that describes the type of the serialized message.
//
//
// JSON
// ====
// The JSON representation of an `Any` value uses the regular
// representation of the deserialized, embedded message, with an
// additional field `@type` which contains the type URL. Example:
//
// package google.profile;
// message Person {
// string first_name = 1;
// string last_name = 2;
// }
//
// {
// "@type": "type.googleapis.com/google.profile.Person",
// "firstName": <string>,
// "lastName": <string>
// }
//
// If the embedded message type is well-known and has a custom JSON
// representation, that representation will be embedded adding a field
// `value` which holds the custom JSON in addition to the `@type`
// field. Example (for message [google.protobuf.Duration][]):
//
// {
// "@type": "type.googleapis.com/google.protobuf.Duration",
// "value": "1.212s"
// }
//
type Any struct {
// A URL/resource name whose content describes the type of the
// serialized message.
//
// For URLs which use the schema `http`, `https`, or no schema, the
// following restrictions and interpretations apply:
//
// * If no schema is provided, `https` is assumed.
// * The last segment of the URL's path must represent the fully
// qualified name of the type (as in `path/google.protobuf.Duration`).
// * An HTTP GET on the URL must yield a [google.protobuf.Type][]
// value in binary format, or produce an error.
// * Applications are allowed to cache lookup results based on the
// URL, or have them precompiled into a binary to avoid any
// lookup. Therefore, binary compatibility needs to be preserved
// on changes to types. (Use versioned type names to manage
// breaking changes.)
//
// Schemas other than `http`, `https` (or the empty schema) might be
// used with implementation specific semantics.
//
TypeUrl string `protobuf:"bytes,1,opt,name=type_url,json=typeUrl" json:"type_url,omitempty"`
// Must be valid serialized data of the above specified type.
Value []byte `protobuf:"bytes,2,opt,name=value,proto3" json:"value,omitempty"`
}
func (m *Any) Reset() { *m = Any{} }
func (m *Any) String() string { return proto.CompactTextString(m) }
func (*Any) ProtoMessage() {}
func (*Any) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{0} }
func (*Any) XXX_WellKnownType() string { return "Any" }
func init() {
proto.RegisterType((*Any)(nil), "google.protobuf.Any")
}
func init() { proto.RegisterFile("google/protobuf/any.proto", fileDescriptor0) }
var fileDescriptor0 = []byte{
// 160 bytes of a gzipped FileDescriptorProto
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x09, 0x6e, 0x88, 0x02, 0xff, 0xe2, 0x92, 0x4c, 0xcf, 0xcf, 0x4f,
0xcf, 0x49, 0xd5, 0x2f, 0x28, 0xca, 0x2f, 0xc9, 0x4f, 0x2a, 0x4d, 0xd3, 0x4f, 0xcc, 0xab, 0xd4,
0x03, 0x73, 0x84, 0xf8, 0x21, 0x52, 0x7a, 0x30, 0x29, 0x25, 0x33, 0x2e, 0x66, 0xc7, 0xbc, 0x4a,
0x21, 0x49, 0x2e, 0x8e, 0x92, 0xca, 0x82, 0xd4, 0xf8, 0xd2, 0xa2, 0x1c, 0x09, 0x46, 0x05, 0x46,
0x0d, 0xce, 0x20, 0x76, 0x10, 0x3f, 0xb4, 0x28, 0x47, 0x48, 0x84, 0x8b, 0xb5, 0x2c, 0x31, 0xa7,
0x34, 0x55, 0x82, 0x09, 0x28, 0xce, 0x13, 0x04, 0xe1, 0x38, 0x79, 0x73, 0x09, 0x27, 0xe7, 0xe7,
0xea, 0xa1, 0x19, 0xe7, 0xc4, 0x01, 0x34, 0x2c, 0x00, 0xc4, 0x09, 0x60, 0x5c, 0xc0, 0xc8, 0xb8,
0x88, 0x89, 0xd9, 0x3d, 0xc0, 0x69, 0x15, 0x93, 0x9c, 0x3b, 0x44, 0x59, 0x00, 0x54, 0x99, 0x5e,
0x78, 0x6a, 0x4e, 0x8e, 0x77, 0x5e, 0x7e, 0x79, 0x5e, 0x08, 0xd0, 0x92, 0xe2, 0x24, 0x36, 0xb0,
0x7e, 0x63, 0x40, 0x00, 0x00, 0x00, 0xff, 0xff, 0x83, 0x49, 0xa8, 0x53, 0xb9, 0x00, 0x00, 0x00,
}
// Code generated by protoc-gen-go.
// source: google/protobuf/duration.proto
// DO NOT EDIT!
package google_protobuf
import proto "github.com/golang/protobuf/proto"
import fmt "fmt"
import math "math"
// Reference imports to suppress errors if they are not otherwise used.
var _ = proto.Marshal
var _ = fmt.Errorf
var _ = math.Inf
// A Duration represents a signed, fixed-length span of time represented
// as a count of seconds and fractions of seconds at nanosecond
// resolution. It is independent of any calendar and concepts like "day"
// or "month". It is related to Timestamp in that the difference between
// two Timestamp values is a Duration and it can be added or subtracted
// from a Timestamp. Range is approximately +-10,000 years.
//
// Example 1: Compute Duration from two Timestamps in pseudo code.
//
// Timestamp start = ...;
// Timestamp end = ...;
// Duration duration = ...;
//
// duration.seconds = end.seconds - start.seconds;
// duration.nanos = end.nanos - start.nanos;
//
// if (duration.seconds < 0 && duration.nanos > 0) {
// duration.seconds += 1;
// duration.nanos -= 1000000000;
// } else if (durations.seconds > 0 && duration.nanos < 0) {
// duration.seconds -= 1;
// duration.nanos += 1000000000;
// }
//
// Example 2: Compute Timestamp from Timestamp + Duration in pseudo code.
//
// Timestamp start = ...;
// Duration duration = ...;
// Timestamp end = ...;
//
// end.seconds = start.seconds + duration.seconds;
// end.nanos = start.nanos + duration.nanos;
//
// if (end.nanos < 0) {
// end.seconds -= 1;
// end.nanos += 1000000000;
// } else if (end.nanos >= 1000000000) {
// end.seconds += 1;
// end.nanos -= 1000000000;
// }
//
type Duration struct {
// Signed seconds of the span of time. Must be from -315,576,000,000
// to +315,576,000,000 inclusive.
Seconds int64 `protobuf:"varint,1,opt,name=seconds" json:"seconds,omitempty"`
// Signed fractions of a second at nanosecond resolution of the span
// of time. Durations less than one second are represented with a 0
// `seconds` field and a positive or negative `nanos` field. For durations
// of one second or more, a non-zero value for the `nanos` field must be
// of the same sign as the `seconds` field. Must be from -999,999,999
// to +999,999,999 inclusive.
Nanos int32 `protobuf:"varint,2,opt,name=nanos" json:"nanos,omitempty"`
}
func (m *Duration) Reset() { *m = Duration{} }
func (m *Duration) String() string { return proto.CompactTextString(m) }
func (*Duration) ProtoMessage() {}
func (*Duration) Descriptor() ([]byte, []int) { return fileDescriptor2, []int{0} }
func (*Duration) XXX_WellKnownType() string { return "Duration" }
func init() {
proto.RegisterType((*Duration)(nil), "google.protobuf.Duration")
}
func init() { proto.RegisterFile("google/protobuf/duration.proto", fileDescriptor2) }
var fileDescriptor2 = []byte{
// 161 bytes of a gzipped FileDescriptorProto
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x09, 0x6e, 0x88, 0x02, 0xff, 0xe2, 0x92, 0x4b, 0xcf, 0xcf, 0x4f,
0xcf, 0x49, 0xd5, 0x2f, 0x28, 0xca, 0x2f, 0xc9, 0x4f, 0x2a, 0x4d, 0xd3, 0x4f, 0x29, 0x2d, 0x4a,
0x2c, 0xc9, 0xcc, 0xcf, 0xd3, 0x03, 0x8b, 0x08, 0xf1, 0x43, 0xe4, 0xf5, 0x60, 0xf2, 0x4a, 0x56,
0x5c, 0x1c, 0x2e, 0x50, 0x25, 0x42, 0x12, 0x5c, 0xec, 0xc5, 0xa9, 0xc9, 0xf9, 0x79, 0x29, 0xc5,
0x12, 0x8c, 0x0a, 0x8c, 0x1a, 0xcc, 0x41, 0x30, 0xae, 0x90, 0x08, 0x17, 0x6b, 0x5e, 0x62, 0x5e,
0x7e, 0xb1, 0x04, 0x13, 0x50, 0x9c, 0x35, 0x08, 0xc2, 0x71, 0x0a, 0xe0, 0x12, 0x4e, 0xce, 0xcf,
0xd5, 0x43, 0x33, 0xd2, 0x89, 0x17, 0x66, 0x60, 0x00, 0x48, 0x24, 0x80, 0x71, 0x01, 0x23, 0xe3,
0x22, 0x26, 0x66, 0xf7, 0x00, 0xa7, 0x55, 0x4c, 0x72, 0xee, 0x10, 0xb5, 0x01, 0x50, 0xb5, 0x7a,
0xe1, 0xa9, 0x39, 0x39, 0xde, 0x79, 0xf9, 0xe5, 0x79, 0x21, 0x95, 0x05, 0xa9, 0xc5, 0x49, 0x6c,
0x60, 0x43, 0x8c, 0x01, 0x01, 0x00, 0x00, 0xff, 0xff, 0x5b, 0xa9, 0x05, 0xfd, 0xc7, 0x00, 0x00,
0x00,
}
// Code generated by protoc-gen-go.
// source: google/protobuf/empty.proto
// DO NOT EDIT!
package google_protobuf
import proto "github.com/golang/protobuf/proto"
import fmt "fmt"
import math "math"
// Reference imports to suppress errors if they are not otherwise used.
var _ = proto.Marshal
var _ = fmt.Errorf
var _ = math.Inf
// A generic empty message that you can re-use to avoid defining duplicated
// empty messages in your APIs. A typical example is to use it as the request
// or the response type of an API method. For instance:
//
// service Foo {
// rpc Bar(google.protobuf.Empty) returns (google.protobuf.Empty);
// }
//
// The JSON representation for `Empty` is empty JSON object `{}`.
type Empty struct {
}
func (m *Empty) Reset() { *m = Empty{} }
func (m *Empty) String() string { return proto.CompactTextString(m) }
func (*Empty) ProtoMessage() {}
func (*Empty) Descriptor() ([]byte, []int) { return fileDescriptor3, []int{0} }
func (*Empty) XXX_WellKnownType() string { return "Empty" }
func init() {
proto.RegisterType((*Empty)(nil), "google.protobuf.Empty")
}
func init() { proto.RegisterFile("google/protobuf/empty.proto", fileDescriptor3) }
var fileDescriptor3 = []byte{
// 124 bytes of a gzipped FileDescriptorProto
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x09, 0x6e, 0x88, 0x02, 0xff, 0xe2, 0x92, 0x4e, 0xcf, 0xcf, 0x4f,
0xcf, 0x49, 0xd5, 0x2f, 0x28, 0xca, 0x2f, 0xc9, 0x4f, 0x2a, 0x4d, 0xd3, 0x4f, 0xcd, 0x2d, 0x28,
0xa9, 0xd4, 0x03, 0x73, 0x85, 0xf8, 0x21, 0x92, 0x7a, 0x30, 0x49, 0x25, 0x76, 0x2e, 0x56, 0x57,
0x90, 0xbc, 0x53, 0x00, 0x97, 0x70, 0x72, 0x7e, 0xae, 0x1e, 0x9a, 0xbc, 0x13, 0x17, 0x58, 0x36,
0x00, 0xc4, 0x0d, 0x60, 0x5c, 0xc0, 0xc8, 0xf8, 0x83, 0x91, 0x71, 0x11, 0x13, 0xb3, 0x7b, 0x80,
0xd3, 0x2a, 0x26, 0x39, 0x77, 0x88, 0xda, 0x00, 0xa8, 0x5a, 0xbd, 0xf0, 0xd4, 0x9c, 0x1c, 0xef,
0xbc, 0xfc, 0xf2, 0xbc, 0x90, 0xca, 0x82, 0xd4, 0xe2, 0x24, 0x36, 0xb0, 0x21, 0xc6, 0x80, 0x00,
0x00, 0x00, 0xff, 0xff, 0xac, 0xca, 0x5b, 0xd0, 0x91, 0x00, 0x00, 0x00,
}
// Code generated by protoc-gen-go.
// source: google/protobuf/field_mask.proto
// DO NOT EDIT!
package google_protobuf
import proto "github.com/golang/protobuf/proto"
import fmt "fmt"
import math "math"
// Reference imports to suppress errors if they are not otherwise used.
var _ = proto.Marshal
var _ = fmt.Errorf
var _ = math.Inf
// `FieldMask` represents a set of symbolic field paths, for example:
//
// paths: "f.a"
// paths: "f.b.d"
//
// Here `f` represents a field in some root message, `a` and `b`
// fields in the message found in `f`, and `d` a field found in the
// message in `f.b`.
//
// Field masks are used to specify a subset of fields that should be
// returned by a get operation or modified by an update operation.
// Field masks also have a custom JSON encoding (see below).
//
// # Field Masks in Projections
//
// When used in the context of a projection, a response message or
// sub-message is filtered by the API to only contain those fields as
// specified in the mask. For example, if the mask in the previous
// example is applied to a response message as follows:
//
// f {
// a : 22
// b {
// d : 1
// x : 2
// }
// y : 13
// }
// z: 8
//
// The result will not contain specific values for fields x,y and z
// (their value will be set to the default, and omitted in proto text
// output):
//
//
// f {
// a : 22
// b {
// d : 1
// }
// }
//
// A repeated field is not allowed except at the last position of a
// field mask.
//
// If a FieldMask object is not present in a get operation, the
// operation applies to all fields (as if a FieldMask of all fields
// had been specified).
//
// Note that a field mask does not necessarily applies to the
// top-level response message. In case of a REST get operation, the
// field mask applies directly to the response, but in case of a REST
// list operation, the mask instead applies to each individual message
// in the returned resource list. In case of a REST custom method,
// other definitions may be used. Where the mask applies will be
// clearly documented together with its declaration in the API. In
// any case, the effect on the returned resource/resources is required
// behavior for APIs.
//
// # Field Masks in Update Operations
//
// A field mask in update operations specifies which fields of the
// targeted resource are going to be updated. The API is required
// to only change the values of the fields as specified in the mask
// and leave the others untouched. If a resource is passed in to
// describe the updated values, the API ignores the values of all
// fields not covered by the mask.
//
// In order to reset a field's value to the default, the field must
// be in the mask and set to the default value in the provided resource.
// Hence, in order to reset all fields of a resource, provide a default
// instance of the resource and set all fields in the mask, or do
// not provide a mask as described below.
//
// If a field mask is not present on update, the operation applies to
// all fields (as if a field mask of all fields has been specified).
// Note that in the presence of schema evolution, this may mean that
// fields the client does not know and has therefore not filled into
// the request will be reset to their default. If this is unwanted
// behavior, a specific service may require a client to always specify
// a field mask, producing an error if not.
//
// As with get operations, the location of the resource which
// describes the updated values in the request message depends on the
// operation kind. In any case, the effect of the field mask is
// required to be honored by the API.
//
// ## Considerations for HTTP REST
//
// The HTTP kind of an update operation which uses a field mask must
// be set to PATCH instead of PUT in order to satisfy HTTP semantics
// (PUT must only be used for full updates).
//
// # JSON Encoding of Field Masks
//
// In JSON, a field mask is encoded as a single string where paths are
// separated by a comma. Fields name in each path are converted
// to/from lower-camel naming conventions.
//
// As an example, consider the following message declarations:
//
// message Profile {
// User user = 1;
// Photo photo = 2;
// }
// message User {
// string display_name = 1;
// string address = 2;
// }
//
// In proto a field mask for `Profile` may look as such:
//
// mask {
// paths: "user.display_name"
// paths: "photo"
// }
//
// In JSON, the same mask is represented as below:
//
// {
// mask: "user.displayName,photo"
// }
//
type FieldMask struct {
// The set of field mask paths.
Paths []string `protobuf:"bytes,1,rep,name=paths" json:"paths,omitempty"`
}
func (m *FieldMask) Reset() { *m = FieldMask{} }
func (m *FieldMask) String() string { return proto.CompactTextString(m) }
func (*FieldMask) ProtoMessage() {}
func (*FieldMask) Descriptor() ([]byte, []int) { return fileDescriptor4, []int{0} }
func init() {
proto.RegisterType((*FieldMask)(nil), "google.protobuf.FieldMask")
}
func init() { proto.RegisterFile("google/protobuf/field_mask.proto", fileDescriptor4) }
var fileDescriptor4 = []byte{
// 147 bytes of a gzipped FileDescriptorProto
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x09, 0x6e, 0x88, 0x02, 0xff, 0xe2, 0x52, 0x48, 0xcf, 0xcf, 0x4f,
0xcf, 0x49, 0xd5, 0x2f, 0x28, 0xca, 0x2f, 0xc9, 0x4f, 0x2a, 0x4d, 0xd3, 0x4f, 0xcb, 0x4c, 0xcd,
0x49, 0x89, 0xcf, 0x4d, 0x2c, 0xce, 0xd6, 0x03, 0x8b, 0x09, 0xf1, 0x43, 0x54, 0xe8, 0xc1, 0x54,
0x28, 0x29, 0x72, 0x71, 0xba, 0x81, 0x14, 0xf9, 0x02, 0xd5, 0x08, 0x89, 0x70, 0xb1, 0x16, 0x24,
0x96, 0x64, 0x14, 0x4b, 0x30, 0x2a, 0x30, 0x6b, 0x70, 0x06, 0x41, 0x38, 0x4e, 0x81, 0x5c, 0xc2,
0xc9, 0xf9, 0xb9, 0x7a, 0x68, 0x3a, 0x9d, 0xf8, 0xe0, 0xfa, 0x02, 0x40, 0x42, 0x01, 0x8c, 0x0b,
0x18, 0x19, 0x17, 0x31, 0x31, 0xbb, 0x07, 0x38, 0xad, 0x62, 0x92, 0x73, 0x87, 0x28, 0x0e, 0x80,
0x2a, 0xd6, 0x0b, 0x4f, 0xcd, 0xc9, 0xf1, 0xce, 0xcb, 0x2f, 0xcf, 0x0b, 0xa9, 0x2c, 0x48, 0x2d,
0x4e, 0x62, 0x03, 0x9b, 0x62, 0x0c, 0x08, 0x00, 0x00, 0xff, 0xff, 0x21, 0xb1, 0xe8, 0x01, 0xb1,
0x00, 0x00, 0x00,
}
package google_protobuf
import (
"time"
)
var (
// EmptyInstance is an instance of Empty.
EmptyInstance = &Empty{}
)
// Now returns the current time as a protobuf Timestamp.
func Now() *Timestamp {
return TimeToProto(time.Now().UTC())
}
// TimeToProto converts a go Time to a protobuf Timestamp.
func TimeToProto(t time.Time) *Timestamp {
return &Timestamp{
Seconds: t.UnixNano() / int64(time.Second),
Nanos: int32(t.UnixNano() % int64(time.Second)),
}
}
// GoTime converts a protobuf Timestamp to a go Time.
func (t *Timestamp) GoTime() time.Time {
if t == nil {
return time.Unix(0, 0).UTC()
}
return time.Unix(
t.Seconds,
int64(t.Nanos),
).UTC()
}
// Before returns true if t is before j.
func (t *Timestamp) Before(j *Timestamp) bool {
if j == nil {
return false
}
if t == nil {
return true
}
if t.Seconds < j.Seconds {
return true
}
if t.Seconds > j.Seconds {
return false
}
return t.Nanos < j.Nanos
}
// DurationToProto converts a go Duration to a protobuf Duration.
func DurationToProto(d time.Duration) *Duration {
return &Duration{
Seconds: int64(d) / int64(time.Second),
Nanos: int32(int64(d) % int64(time.Second)),
}
}
// GoDuration converts a protobuf Duration to a go Duration.
func (d *Duration) GoDuration() time.Duration {
if d == nil {
return 0
}
return time.Duration((d.Seconds * int64(time.Second)) + int64(d.Nanos))
}
// Code generated by protoc-gen-go.
// source: google/protobuf/source_context.proto
// DO NOT EDIT!
package google_protobuf
import proto "github.com/golang/protobuf/proto"
import fmt "fmt"
import math "math"
// Reference imports to suppress errors if they are not otherwise used.
var _ = proto.Marshal
var _ = fmt.Errorf
var _ = math.Inf
// `SourceContext` represents information about the source of a
// protobuf element, like the file in which it is defined.
type SourceContext struct {
// The path-qualified name of the .proto file that contained the associated
// protobuf element. For example: `"google/protobuf/source.proto"`.
FileName string `protobuf:"bytes,1,opt,name=file_name,json=fileName" json:"file_name,omitempty"`
}
func (m *SourceContext) Reset() { *m = SourceContext{} }
func (m *SourceContext) String() string { return proto.CompactTextString(m) }
func (*SourceContext) ProtoMessage() {}
func (*SourceContext) Descriptor() ([]byte, []int) { return fileDescriptor5, []int{0} }
func init() {
proto.RegisterType((*SourceContext)(nil), "google.protobuf.SourceContext")
}
func init() { proto.RegisterFile("google/protobuf/source_context.proto", fileDescriptor5) }
var fileDescriptor5 = []byte{
// 159 bytes of a gzipped FileDescriptorProto
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x09, 0x6e, 0x88, 0x02, 0xff, 0xe2, 0x52, 0x49, 0xcf, 0xcf, 0x4f,
0xcf, 0x49, 0xd5, 0x2f, 0x28, 0xca, 0x2f, 0xc9, 0x4f, 0x2a, 0x4d, 0xd3, 0x2f, 0xce, 0x2f, 0x2d,
0x4a, 0x4e, 0x8d, 0x4f, 0xce, 0xcf, 0x2b, 0x49, 0xad, 0x28, 0xd1, 0x03, 0x8b, 0x0b, 0xf1, 0x43,
0x54, 0xe9, 0xc1, 0x54, 0x29, 0xe9, 0x70, 0xf1, 0x06, 0x83, 0x15, 0x3a, 0x43, 0xd4, 0x09, 0x49,
0x73, 0x71, 0xa6, 0x65, 0xe6, 0xa4, 0xc6, 0xe7, 0x25, 0xe6, 0xa6, 0x4a, 0x30, 0x2a, 0x30, 0x6a,
0x70, 0x06, 0x71, 0x80, 0x04, 0xfc, 0x80, 0x7c, 0xa7, 0x50, 0x2e, 0xe1, 0xe4, 0xfc, 0x5c, 0x3d,
0x34, 0x43, 0x9c, 0x84, 0x50, 0x8c, 0x08, 0x00, 0x09, 0x07, 0x30, 0x2e, 0x60, 0x64, 0x5c, 0xc4,
0xc4, 0xec, 0x1e, 0xe0, 0xb4, 0x8a, 0x49, 0xce, 0x1d, 0xa2, 0x21, 0x00, 0xaa, 0x41, 0x2f, 0x3c,
0x35, 0x27, 0xc7, 0x3b, 0x2f, 0xbf, 0x3c, 0x2f, 0xa4, 0xb2, 0x20, 0xb5, 0x38, 0x89, 0x0d, 0x6c,
0x92, 0x31, 0x20, 0x00, 0x00, 0xff, 0xff, 0xb6, 0x80, 0x1f, 0xc2, 0xc4, 0x00, 0x00, 0x00,
}
// Code generated by protoc-gen-go.
// source: google/protobuf/timestamp.proto
// DO NOT EDIT!
package google_protobuf
import proto "github.com/golang/protobuf/proto"
import fmt "fmt"
import math "math"
// Reference imports to suppress errors if they are not otherwise used.
var _ = proto.Marshal
var _ = fmt.Errorf
var _ = math.Inf
// A Timestamp represents a point in time independent of any time zone
// or calendar, represented as seconds and fractions of seconds at
// nanosecond resolution in UTC Epoch time. It is encoded using the
// Proleptic Gregorian Calendar which extends the Gregorian calendar
// backwards to year one. It is encoded assuming all minutes are 60
// seconds long, i.e. leap seconds are "smeared" so that no leap second
// table is needed for interpretation. Range is from
// 0001-01-01T00:00:00Z to 9999-12-31T23:59:59.999999999Z.
// By restricting to that range, we ensure that we can convert to
// and from RFC 3339 date strings.
// See [https://www.ietf.org/rfc/rfc3339.txt](https://www.ietf.org/rfc/rfc3339.txt).
//
// Example 1: Compute Timestamp from POSIX `time()`.
//
// Timestamp timestamp;
// timestamp.set_seconds(time(NULL));
// timestamp.set_nanos(0);
//
// Example 2: Compute Timestamp from POSIX `gettimeofday()`.
//
// struct timeval tv;
// gettimeofday(&tv, NULL);
//
// Timestamp timestamp;
// timestamp.set_seconds(tv.tv_sec);
// timestamp.set_nanos(tv.tv_usec * 1000);
//
// Example 3: Compute Timestamp from Win32 `GetSystemTimeAsFileTime()`.
//
// FILETIME ft;
// GetSystemTimeAsFileTime(&ft);
// UINT64 ticks = (((UINT64)ft.dwHighDateTime) << 32) | ft.dwLowDateTime;
//
// // A Windows tick is 100 nanoseconds. Windows epoch 1601-01-01T00:00:00Z
// // is 11644473600 seconds before Unix epoch 1970-01-01T00:00:00Z.
// Timestamp timestamp;
// timestamp.set_seconds((INT64) ((ticks / 10000000) - 11644473600LL));
// timestamp.set_nanos((INT32) ((ticks % 10000000) * 100));
//
// Example 4: Compute Timestamp from Java `System.currentTimeMillis()`.
//
// long millis = System.currentTimeMillis();
//
// Timestamp timestamp = Timestamp.newBuilder().setSeconds(millis / 1000)
// .setNanos((int) ((millis % 1000) * 1000000)).build();
//
//
// Example 5: Compute Timestamp from current time in Python.
//
// now = time.time()
// seconds = int(now)
// nanos = int((now - seconds) * 10**9)
// timestamp = Timestamp(seconds=seconds, nanos=nanos)
//
//
type Timestamp struct {
// Represents seconds of UTC time since Unix epoch
// 1970-01-01T00:00:00Z. Must be from from 0001-01-01T00:00:00Z to
// 9999-12-31T23:59:59Z inclusive.
Seconds int64 `protobuf:"varint,1,opt,name=seconds" json:"seconds,omitempty"`
// Non-negative fractions of a second at nanosecond resolution. Negative
// second values with fractions must still have non-negative nanos values
// that count forward in time. Must be from 0 to 999,999,999
// inclusive.
Nanos int32 `protobuf:"varint,2,opt,name=nanos" json:"nanos,omitempty"`
}
func (m *Timestamp) Reset() { *m = Timestamp{} }
func (m *Timestamp) String() string { return proto.CompactTextString(m) }
func (*Timestamp) ProtoMessage() {}
func (*Timestamp) Descriptor() ([]byte, []int) { return fileDescriptor7, []int{0} }
func (*Timestamp) XXX_WellKnownType() string { return "Timestamp" }
func init() {
proto.RegisterType((*Timestamp)(nil), "google.protobuf.Timestamp")
}
func init() { proto.RegisterFile("google/protobuf/timestamp.proto", fileDescriptor7) }
var fileDescriptor7 = []byte{
// 165 bytes of a gzipped FileDescriptorProto
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x09, 0x6e, 0x88, 0x02, 0xff, 0xe2, 0x92, 0x4f, 0xcf, 0xcf, 0x4f,
0xcf, 0x49, 0xd5, 0x2f, 0x28, 0xca, 0x2f, 0xc9, 0x4f, 0x2a, 0x4d, 0xd3, 0x2f, 0xc9, 0xcc, 0x4d,
0x2d, 0x2e, 0x49, 0xcc, 0x2d, 0xd0, 0x03, 0x0b, 0x09, 0xf1, 0x43, 0x14, 0xe8, 0xc1, 0x14, 0x28,
0x59, 0x73, 0x71, 0x86, 0xc0, 0xd4, 0x08, 0x49, 0x70, 0xb1, 0x17, 0xa7, 0x26, 0xe7, 0xe7, 0xa5,
0x14, 0x4b, 0x30, 0x2a, 0x30, 0x6a, 0x30, 0x07, 0xc1, 0xb8, 0x42, 0x22, 0x5c, 0xac, 0x79, 0x89,
0x79, 0xf9, 0xc5, 0x12, 0x4c, 0x40, 0x71, 0xd6, 0x20, 0x08, 0xc7, 0x29, 0x84, 0x4b, 0x38, 0x39,
0x3f, 0x57, 0x0f, 0xcd, 0x4c, 0x27, 0x3e, 0xb8, 0x89, 0x01, 0x20, 0xa1, 0x00, 0xc6, 0x05, 0x8c,
0x8c, 0x3f, 0x18, 0x19, 0x17, 0x31, 0x31, 0xbb, 0x07, 0x38, 0xad, 0x62, 0x92, 0x73, 0x87, 0xa8,
0x0f, 0x80, 0xaa, 0xd7, 0x0b, 0x4f, 0xcd, 0xc9, 0xf1, 0xce, 0xcb, 0x2f, 0xcf, 0x0b, 0xa9, 0x2c,
0x48, 0x2d, 0x4e, 0x62, 0x03, 0x1b, 0x64, 0x0c, 0x08, 0x00, 0x00, 0xff, 0xff, 0x10, 0x2f, 0xb9,
0x47, 0xcd, 0x00, 0x00, 0x00,
}
// Code generated by protoc-gen-go.
// source: google/protobuf/wrappers.proto
// DO NOT EDIT!
package google_protobuf
import proto "github.com/golang/protobuf/proto"
import fmt "fmt"
import math "math"
// Reference imports to suppress errors if they are not otherwise used.
var _ = proto.Marshal
var _ = fmt.Errorf
var _ = math.Inf
// Wrapper message for `double`.
//
// The JSON representation for `DoubleValue` is JSON number.
type DoubleValue struct {
// The double value.
Value float64 `protobuf:"fixed64,1,opt,name=value" json:"value,omitempty"`
}
func (m *DoubleValue) Reset() { *m = DoubleValue{} }
func (m *DoubleValue) String() string { return proto.CompactTextString(m) }
func (*DoubleValue) ProtoMessage() {}
func (*DoubleValue) Descriptor() ([]byte, []int) { return fileDescriptor9, []int{0} }
func (*DoubleValue) XXX_WellKnownType() string { return "DoubleValue" }
// Wrapper message for `float`.
//
// The JSON representation for `FloatValue` is JSON number.
type FloatValue struct {
// The float value.
Value float32 `protobuf:"fixed32,1,opt,name=value" json:"value,omitempty"`
}
func (m *FloatValue) Reset() { *m = FloatValue{} }
func (m *FloatValue) String() string { return proto.CompactTextString(m) }
func (*FloatValue) ProtoMessage() {}
func (*FloatValue) Descriptor() ([]byte, []int) { return fileDescriptor9, []int{1} }
func (*FloatValue) XXX_WellKnownType() string { return "FloatValue" }
// Wrapper message for `int64`.
//
// The JSON representation for `Int64Value` is JSON string.
type Int64Value struct {
// The int64 value.
Value int64 `protobuf:"varint,1,opt,name=value" json:"value,omitempty"`
}
func (m *Int64Value) Reset() { *m = Int64Value{} }
func (m *Int64Value) String() string { return proto.CompactTextString(m) }
func (*Int64Value) ProtoMessage() {}
func (*Int64Value) Descriptor() ([]byte, []int) { return fileDescriptor9, []int{2} }
func (*Int64Value) XXX_WellKnownType() string { return "Int64Value" }
// Wrapper message for `uint64`.
//
// The JSON representation for `UInt64Value` is JSON string.
type UInt64Value struct {
// The uint64 value.
Value uint64 `protobuf:"varint,1,opt,name=value" json:"value,omitempty"`
}
func (m *UInt64Value) Reset() { *m = UInt64Value{} }
func (m *UInt64Value) String() string { return proto.CompactTextString(m) }
func (*UInt64Value) ProtoMessage() {}
func (*UInt64Value) Descriptor() ([]byte, []int) { return fileDescriptor9, []int{3} }
func (*UInt64Value) XXX_WellKnownType() string { return "UInt64Value" }
// Wrapper message for `int32`.
//
// The JSON representation for `Int32Value` is JSON number.
type Int32Value struct {
// The int32 value.
Value int32 `protobuf:"varint,1,opt,name=value" json:"value,omitempty"`
}
func (m *Int32Value) Reset() { *m = Int32Value{} }
func (m *Int32Value) String() string { return proto.CompactTextString(m) }
func (*Int32Value) ProtoMessage() {}
func (*Int32Value) Descriptor() ([]byte, []int) { return fileDescriptor9, []int{4} }
func (*Int32Value) XXX_WellKnownType() string { return "Int32Value" }
// Wrapper message for `uint32`.
//
// The JSON representation for `UInt32Value` is JSON number.
type UInt32Value struct {
// The uint32 value.
Value uint32 `protobuf:"varint,1,opt,name=value" json:"value,omitempty"`
}
func (m *UInt32Value) Reset() { *m = UInt32Value{} }
func (m *UInt32Value) String() string { return proto.CompactTextString(m) }
func (*UInt32Value) ProtoMessage() {}
func (*UInt32Value) Descriptor() ([]byte, []int) { return fileDescriptor9, []int{5} }
func (*UInt32Value) XXX_WellKnownType() string { return "UInt32Value" }
// Wrapper message for `bool`.
//
// The JSON representation for `BoolValue` is JSON `true` and `false`.
type BoolValue struct {
// The bool value.
Value bool `protobuf:"varint,1,opt,name=value" json:"value,omitempty"`
}
func (m *BoolValue) Reset() { *m = BoolValue{} }
func (m *BoolValue) String() string { return proto.CompactTextString(m) }
func (*BoolValue) ProtoMessage() {}
func (*BoolValue) Descriptor() ([]byte, []int) { return fileDescriptor9, []int{6} }
func (*BoolValue) XXX_WellKnownType() string { return "BoolValue" }
// Wrapper message for `string`.
//
// The JSON representation for `StringValue` is JSON string.
type StringValue struct {
// The string value.
Value string `protobuf:"bytes,1,opt,name=value" json:"value,omitempty"`
}
func (m *StringValue) Reset() { *m = StringValue{} }
func (m *StringValue) String() string { return proto.CompactTextString(m) }
func (*StringValue) ProtoMessage() {}
func (*StringValue) Descriptor() ([]byte, []int) { return fileDescriptor9, []int{7} }
func (*StringValue) XXX_WellKnownType() string { return "StringValue" }
// Wrapper message for `bytes`.
//
// The JSON representation for `BytesValue` is JSON string.
type BytesValue struct {
// The bytes value.
Value []byte `protobuf:"bytes,1,opt,name=value,proto3" json:"value,omitempty"`
}
func (m *BytesValue) Reset() { *m = BytesValue{} }
func (m *BytesValue) String() string { return proto.CompactTextString(m) }
func (*BytesValue) ProtoMessage() {}
func (*BytesValue) Descriptor() ([]byte, []int) { return fileDescriptor9, []int{8} }
func (*BytesValue) XXX_WellKnownType() string { return "BytesValue" }
func init() {
proto.RegisterType((*DoubleValue)(nil), "google.protobuf.DoubleValue")
proto.RegisterType((*FloatValue)(nil), "google.protobuf.FloatValue")
proto.RegisterType((*Int64Value)(nil), "google.protobuf.Int64Value")
proto.RegisterType((*UInt64Value)(nil), "google.protobuf.UInt64Value")
proto.RegisterType((*Int32Value)(nil), "google.protobuf.Int32Value")
proto.RegisterType((*UInt32Value)(nil), "google.protobuf.UInt32Value")
proto.RegisterType((*BoolValue)(nil), "google.protobuf.BoolValue")
proto.RegisterType((*StringValue)(nil), "google.protobuf.StringValue")
proto.RegisterType((*BytesValue)(nil), "google.protobuf.BytesValue")
}
func init() { proto.RegisterFile("google/protobuf/wrappers.proto", fileDescriptor9) }
var fileDescriptor9 = []byte{
// 233 bytes of a gzipped FileDescriptorProto
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x09, 0x6e, 0x88, 0x02, 0xff, 0xe2, 0x92, 0x4b, 0xcf, 0xcf, 0x4f,
0xcf, 0x49, 0xd5, 0x2f, 0x28, 0xca, 0x2f, 0xc9, 0x4f, 0x2a, 0x4d, 0xd3, 0x2f, 0x2f, 0x4a, 0x2c,
0x28, 0x48, 0x2d, 0x2a, 0xd6, 0x03, 0x8b, 0x08, 0xf1, 0x43, 0xe4, 0xf5, 0x60, 0xf2, 0x4a, 0xca,
0x5c, 0xdc, 0x2e, 0xf9, 0xa5, 0x49, 0x39, 0xa9, 0x61, 0x89, 0x39, 0xa5, 0xa9, 0x42, 0x22, 0x5c,
0xac, 0x65, 0x20, 0x86, 0x04, 0xa3, 0x02, 0xa3, 0x06, 0x63, 0x10, 0x84, 0xa3, 0xa4, 0xc4, 0xc5,
0xe5, 0x96, 0x93, 0x9f, 0x58, 0x82, 0x45, 0x0d, 0x13, 0x92, 0x1a, 0xcf, 0xbc, 0x12, 0x33, 0x13,
0x2c, 0x6a, 0x98, 0x61, 0x6a, 0x80, 0x96, 0x85, 0xe2, 0x52, 0xc4, 0x82, 0x6a, 0x90, 0xb1, 0x11,
0x16, 0x35, 0xac, 0x68, 0x06, 0x61, 0x55, 0xc4, 0x0b, 0x53, 0xa4, 0xc8, 0xc5, 0xe9, 0x94, 0x9f,
0x9f, 0x83, 0x45, 0x09, 0x07, 0x92, 0x39, 0xc1, 0x25, 0x45, 0x99, 0x79, 0xe9, 0x58, 0x14, 0x71,
0x22, 0x39, 0xc8, 0xa9, 0xb2, 0x24, 0xb5, 0x18, 0x8b, 0x1a, 0x1e, 0xa8, 0x1a, 0xa7, 0x60, 0x2e,
0xe1, 0xe4, 0xfc, 0x5c, 0x3d, 0xb4, 0xd0, 0x75, 0xe2, 0x0d, 0x87, 0x06, 0x7f, 0x00, 0x48, 0x24,
0x80, 0x71, 0x01, 0x23, 0xe3, 0x0f, 0x46, 0xc6, 0x45, 0x4c, 0xcc, 0xee, 0x01, 0x4e, 0xab, 0x98,
0xe4, 0xdc, 0x21, 0xca, 0x03, 0xa0, 0xca, 0xf5, 0xc2, 0x53, 0x73, 0x72, 0xbc, 0xf3, 0xf2, 0xcb,
0xf3, 0x42, 0x2a, 0x0b, 0x52, 0x8b, 0x93, 0xd8, 0xc0, 0xe6, 0x18, 0x03, 0x02, 0x00, 0x00, 0xff,
0xff, 0xd8, 0xa5, 0x6f, 0xc9, 0xd5, 0x01, 0x00, 0x00,
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment