mirror of https://github.com/k3s-io/k3s
commit
159ba48932
|
@ -14,26 +14,6 @@
|
|||
"ImportPath": "code.google.com/p/gcfg",
|
||||
"Rev": "c2d3050044d05357eaf6c3547249ba57c5e235cb"
|
||||
},
|
||||
{
|
||||
"ImportPath": "code.google.com/p/go-uuid/uuid",
|
||||
"Comment": "null-12",
|
||||
"Rev": "7dda39b2e7d5e265014674c5af696ba4186679e9"
|
||||
},
|
||||
{
|
||||
"ImportPath": "code.google.com/p/google-api-go-client/compute/v1",
|
||||
"Comment": "release-105",
|
||||
"Rev": "98c78185197025f935947caac56a7b6d022f89d2"
|
||||
},
|
||||
{
|
||||
"ImportPath": "code.google.com/p/google-api-go-client/container/v1beta1",
|
||||
"Comment": "release-105",
|
||||
"Rev": "98c78185197025f935947caac56a7b6d022f89d2"
|
||||
},
|
||||
{
|
||||
"ImportPath": "code.google.com/p/google-api-go-client/googleapi",
|
||||
"Comment": "release-105",
|
||||
"Rev": "98c78185197025f935947caac56a7b6d022f89d2"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/GoogleCloudPlatform/gcloud-golang/compute/metadata",
|
||||
"Rev": "e34a32f9b0ecbc0784865fb2d47f3818c09521d4"
|
||||
|
@ -390,35 +370,35 @@
|
|||
},
|
||||
{
|
||||
"ImportPath": "github.com/mesos/mesos-go/auth",
|
||||
"Rev": "6440c09c9d8a1b365f3c3e9b2297dd856abd017c"
|
||||
"Rev": "65cb9ffec50a76f4ed9fe4808405b66b3bb7010d"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/mesos/mesos-go/detector",
|
||||
"Rev": "6440c09c9d8a1b365f3c3e9b2297dd856abd017c"
|
||||
"Rev": "65cb9ffec50a76f4ed9fe4808405b66b3bb7010d"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/mesos/mesos-go/executor",
|
||||
"Rev": "6440c09c9d8a1b365f3c3e9b2297dd856abd017c"
|
||||
"Rev": "65cb9ffec50a76f4ed9fe4808405b66b3bb7010d"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/mesos/mesos-go/mesosproto",
|
||||
"Rev": "6440c09c9d8a1b365f3c3e9b2297dd856abd017c"
|
||||
"Rev": "65cb9ffec50a76f4ed9fe4808405b66b3bb7010d"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/mesos/mesos-go/mesosutil",
|
||||
"Rev": "6440c09c9d8a1b365f3c3e9b2297dd856abd017c"
|
||||
"Rev": "65cb9ffec50a76f4ed9fe4808405b66b3bb7010d"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/mesos/mesos-go/messenger",
|
||||
"Rev": "6440c09c9d8a1b365f3c3e9b2297dd856abd017c"
|
||||
"Rev": "65cb9ffec50a76f4ed9fe4808405b66b3bb7010d"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/mesos/mesos-go/scheduler",
|
||||
"Rev": "6440c09c9d8a1b365f3c3e9b2297dd856abd017c"
|
||||
"Rev": "65cb9ffec50a76f4ed9fe4808405b66b3bb7010d"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/mesos/mesos-go/upid",
|
||||
"Rev": "6440c09c9d8a1b365f3c3e9b2297dd856abd017c"
|
||||
"Rev": "65cb9ffec50a76f4ed9fe4808405b66b3bb7010d"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/miekg/dns",
|
||||
|
@ -442,6 +422,10 @@
|
|||
"Comment": "v1.0-28-g8adf9e1",
|
||||
"Rev": "8adf9e1730c55cdc590de7d49766cb2acc88d8f2"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/pborman/uuid",
|
||||
"Rev": "ca53cad383cad2479bbba7f7a1a05797ec1386e4"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/prometheus/client_golang/extraction",
|
||||
"Comment": "0.4.0-1-g692492e",
|
||||
|
@ -563,6 +547,18 @@
|
|||
"ImportPath": "golang.org/x/oauth2",
|
||||
"Rev": "b5adcc2dcdf009d0391547edc6ecbaff889f5bb9"
|
||||
},
|
||||
{
|
||||
"ImportPath": "google.golang.org/api/compute/v1",
|
||||
"Rev": "0c2979aeaa5b573e60d3ddffe5ce8dca8df309bd"
|
||||
},
|
||||
{
|
||||
"ImportPath": "google.golang.org/api/container/v1beta1",
|
||||
"Rev": "0c2979aeaa5b573e60d3ddffe5ce8dca8df309bd"
|
||||
},
|
||||
{
|
||||
"ImportPath": "google.golang.org/api/googleapi",
|
||||
"Rev": "0c2979aeaa5b573e60d3ddffe5ce8dca8df309bd"
|
||||
},
|
||||
{
|
||||
"ImportPath": "google.golang.org/cloud/compute/metadata",
|
||||
"Rev": "2e43671e4ad874a7bca65746ff3edb38e6e93762"
|
||||
|
|
9526
Godeps/_workspace/src/code.google.com/p/google-api-go-client/compute/v1/compute-api.json
generated
vendored
9526
Godeps/_workspace/src/code.google.com/p/google-api-go-client/compute/v1/compute-api.json
generated
vendored
File diff suppressed because it is too large
Load Diff
|
@ -270,9 +270,6 @@ func (zkc *Client) monitorSession(sessionEvents <-chan zk.Event, connected chan
|
|||
default: // message buf full, this becomes a non-blocking noop
|
||||
}
|
||||
|
||||
case zk.StateSyncConnected:
|
||||
log.Infoln("syncConnected to zookper server")
|
||||
|
||||
case zk.StateDisconnected:
|
||||
log.Infoln("zookeeper client disconnected")
|
||||
|
||||
|
|
|
@ -25,7 +25,6 @@ import (
|
|||
"sync"
|
||||
"time"
|
||||
|
||||
"code.google.com/p/go-uuid/uuid"
|
||||
"github.com/gogo/protobuf/proto"
|
||||
log "github.com/golang/glog"
|
||||
"github.com/mesos/mesos-go/mesosproto"
|
||||
|
@ -33,6 +32,7 @@ import (
|
|||
"github.com/mesos/mesos-go/mesosutil/process"
|
||||
"github.com/mesos/mesos-go/messenger"
|
||||
"github.com/mesos/mesos-go/upid"
|
||||
"github.com/pborman/uuid"
|
||||
"golang.org/x/net/context"
|
||||
)
|
||||
|
||||
|
|
2
Godeps/_workspace/src/github.com/mesos/mesos-go/executor/executor_intgr_test.go
generated
vendored
2
Godeps/_workspace/src/github.com/mesos/mesos-go/executor/executor_intgr_test.go
generated
vendored
|
@ -28,12 +28,12 @@ import (
|
|||
"testing"
|
||||
"time"
|
||||
|
||||
"code.google.com/p/go-uuid/uuid"
|
||||
"github.com/gogo/protobuf/proto"
|
||||
log "github.com/golang/glog"
|
||||
mesos "github.com/mesos/mesos-go/mesosproto"
|
||||
util "github.com/mesos/mesos-go/mesosutil"
|
||||
"github.com/mesos/mesos-go/testutil"
|
||||
"github.com/pborman/uuid"
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
|
|
|
@ -28,7 +28,6 @@ import (
|
|||
"sync"
|
||||
"time"
|
||||
|
||||
"code.google.com/p/go-uuid/uuid"
|
||||
"github.com/gogo/protobuf/proto"
|
||||
log "github.com/golang/glog"
|
||||
"github.com/mesos/mesos-go/auth"
|
||||
|
@ -38,6 +37,7 @@ import (
|
|||
"github.com/mesos/mesos-go/mesosutil/process"
|
||||
"github.com/mesos/mesos-go/messenger"
|
||||
"github.com/mesos/mesos-go/upid"
|
||||
"github.com/pborman/uuid"
|
||||
"golang.org/x/net/context"
|
||||
)
|
||||
|
||||
|
|
|
@ -0,0 +1 @@
|
|||
Paul Borman <borman@google.com>
|
|
@ -1,4 +1,4 @@
|
|||
Copyright (c) 2009 Google Inc. All rights reserved.
|
||||
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
|
|
@ -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
|
||||
}
|
|
@ -0,0 +1,32 @@
|
|||
// 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/json"
|
||||
"reflect"
|
||||
"testing"
|
||||
)
|
||||
|
||||
var testUUID = Parse("f47ac10b-58cc-0372-8567-0e02b2c3d479")
|
||||
|
||||
func TestJSON(t *testing.T) {
|
||||
type S struct {
|
||||
ID1 UUID
|
||||
ID2 UUID
|
||||
}
|
||||
s1 := S{ID1: testUUID}
|
||||
data, err := json.Marshal(&s1)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
var s2 S
|
||||
if err := json.Unmarshal(data, &s2); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if !reflect.DeepEqual(&s1, &s2) {
|
||||
t.Errorf("got %#v, want %#v", s2, s1)
|
||||
}
|
||||
}
|
|
@ -0,0 +1,66 @@
|
|||
// 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 (
|
||||
"flag"
|
||||
"runtime"
|
||||
"testing"
|
||||
"time"
|
||||
)
|
||||
|
||||
// This test is only run when --regressions is passed on the go test line.
|
||||
var regressions = flag.Bool("regressions", false, "run uuid regression tests")
|
||||
|
||||
// TestClockSeqRace tests for a particular race condition of returning two
|
||||
// identical Version1 UUIDs. The duration of 1 minute was chosen as the race
|
||||
// condition, before being fixed, nearly always occured in under 30 seconds.
|
||||
func TestClockSeqRace(t *testing.T) {
|
||||
if !*regressions {
|
||||
t.Skip("skipping regression tests")
|
||||
}
|
||||
duration := time.Minute
|
||||
|
||||
done := make(chan struct{})
|
||||
defer close(done)
|
||||
|
||||
ch := make(chan UUID, 10000)
|
||||
ncpu := runtime.NumCPU()
|
||||
switch ncpu {
|
||||
case 0, 1:
|
||||
// We can't run the test effectively.
|
||||
t.Skip("skipping race test, only one CPU detected")
|
||||
return
|
||||
default:
|
||||
runtime.GOMAXPROCS(ncpu)
|
||||
}
|
||||
for i := 0; i < ncpu; i++ {
|
||||
go func() {
|
||||
for {
|
||||
select {
|
||||
case <-done:
|
||||
return
|
||||
case ch <- NewUUID():
|
||||
}
|
||||
}
|
||||
}()
|
||||
}
|
||||
|
||||
uuids := make(map[string]bool)
|
||||
cnt := 0
|
||||
start := time.Now()
|
||||
for u := range ch {
|
||||
s := u.String()
|
||||
if uuids[s] {
|
||||
t.Errorf("duplicate uuid after %d in %v: %s", cnt, time.Since(start), s)
|
||||
return
|
||||
}
|
||||
uuids[s] = true
|
||||
if time.Since(start) > duration {
|
||||
return
|
||||
}
|
||||
cnt++
|
||||
}
|
||||
}
|
|
@ -40,15 +40,15 @@ func (t Time) UnixTime() (sec, nsec int64) {
|
|||
}
|
||||
|
||||
// GetTime returns the current Time (100s of nanoseconds since 15 Oct 1582) and
|
||||
// adjusts the clock sequence as needed. An error is returned if the current
|
||||
// time cannot be determined.
|
||||
func GetTime() (Time, error) {
|
||||
// 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, error) {
|
||||
func getTime() (Time, uint16, error) {
|
||||
t := timeNow()
|
||||
|
||||
// If we don't have a clock sequence already, set one.
|
||||
|
@ -63,7 +63,7 @@ func getTime() (Time, error) {
|
|||
clock_seq = ((clock_seq + 1) & 0x3fff) | 0x8000
|
||||
}
|
||||
lasttime = now
|
||||
return Time(now), nil
|
||||
return Time(now), clock_seq, nil
|
||||
}
|
||||
|
||||
// ClockSequence returns the current clock sequence, generating one if not
|
|
@ -19,7 +19,7 @@ func NewUUID() UUID {
|
|||
SetNodeInterface("")
|
||||
}
|
||||
|
||||
now, err := GetTime()
|
||||
now, seq, err := GetTime()
|
||||
if err != nil {
|
||||
return nil
|
||||
}
|
||||
|
@ -34,7 +34,7 @@ func NewUUID() UUID {
|
|||
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:], clock_seq)
|
||||
binary.BigEndian.PutUint16(uuid[8:], seq)
|
||||
copy(uuid[10:], nodeID)
|
||||
|
||||
return uuid
|
13142
Godeps/_workspace/src/google.golang.org/api/compute/v1/compute-api.json
generated
vendored
Normal file
13142
Godeps/_workspace/src/google.golang.org/api/compute/v1/compute-api.json
generated
vendored
Normal file
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
|
@ -1,11 +1,11 @@
|
|||
{
|
||||
"kind": "discovery#restDescription",
|
||||
"etag": "\"l66ggWbucbkBw9Lpos72oziyefE/ZrZBeDfQYPqAxFURJt0IhCOLUHQ\"",
|
||||
"etag": "\"ye6orv2F-1npMW3u9suM3a7C5Bo/H5vlYxYcjMuH0uPSZu-WXGARHps\"",
|
||||
"discoveryVersion": "v1",
|
||||
"id": "container:v1beta1",
|
||||
"name": "container",
|
||||
"version": "v1beta1",
|
||||
"revision": "20141103",
|
||||
"revision": "20150326",
|
||||
"title": "Google Container Engine API",
|
||||
"description": "The Google Container Engine API is used for building and managing container based applications, powered by the open source Kubernetes technology.",
|
||||
"ownerDomain": "google.com",
|
||||
|
@ -14,6 +14,7 @@
|
|||
"x16": "http://www.google.com/images/icons/product/search-16.gif",
|
||||
"x32": "http://www.google.com/images/icons/product/search-32.gif"
|
||||
},
|
||||
"documentationLink": "https://cloud.google.com/container-engine/docs/v1beta1/",
|
||||
"protocol": "rest",
|
||||
"baseUrl": "https://www.googleapis.com/container/v1beta1/projects/",
|
||||
"basePath": "/container/v1beta1/projects/",
|
||||
|
@ -78,15 +79,14 @@
|
|||
"Cluster": {
|
||||
"id": "Cluster",
|
||||
"type": "object",
|
||||
"externalTypeName": "container.v1beta1.Cluster",
|
||||
"properties": {
|
||||
"clusterApiVersion": {
|
||||
"type": "string",
|
||||
"description": "The API version of the Kubernetes master and kubelets running in this cluster. Allowed value is 0.4.2, or leave blank to pick up the latest stable release."
|
||||
"description": "The API version of the Kubernetes master and kubelets running in this cluster. Leave blank to pick up the latest stable release, or specify a version of the form \"x.y.z\". The Google Container Engine release notes lists the currently supported versions. If an incorrect version is specified, the server returns an error listing the currently supported versions."
|
||||
},
|
||||
"containerIpv4Cidr": {
|
||||
"type": "string",
|
||||
"description": "[Output only] The IP addresses of the container pods in this cluster, in CIDR notation (e.g. 1.2.3.4/29)."
|
||||
"description": "The IP address range of the container pods in this cluster, in CIDR notation (e.g. 10.96.0.0/14). Leave blank to have one automatically chosen or specify a /14 block in 10.0.0.0/8 or 172.16.0.0/12."
|
||||
},
|
||||
"creationTimestamp": {
|
||||
"type": "string",
|
||||
|
@ -96,18 +96,37 @@
|
|||
"type": "string",
|
||||
"description": "An optional description of this cluster."
|
||||
},
|
||||
"enableCloudLogging": {
|
||||
"type": "boolean",
|
||||
"description": "Whether logs from the cluster should be made available via the Google Cloud Logging service. This includes both logs from your applications running in the cluster as well as logs from the Kubernetes components themselves."
|
||||
},
|
||||
"enableCloudMonitoring": {
|
||||
"type": "boolean",
|
||||
"description": "Whether metrics from the cluster should be made available via the Google Cloud Monitoring service."
|
||||
},
|
||||
"endpoint": {
|
||||
"type": "string",
|
||||
"description": "[Output only] The IP address of this cluster's Kubernetes master. The endpoint can be accessed from the internet at https://username:password@endpoint/.\n\nSee the masterAuth property of this resource for username and password information."
|
||||
},
|
||||
"instanceGroupUrls": {
|
||||
"type": "array",
|
||||
"description": "[Output only] The resource URLs of [instance groups](/compute/docs/instance-groups/) associated with this cluster.",
|
||||
"items": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"masterAuth": {
|
||||
"$ref": "MasterAuth",
|
||||
"description": "The HTTP basic authentication information for accessing the master. Because the master endpoint is open to the internet, you should create a strong password."
|
||||
"description": "The authentication information for accessing the master."
|
||||
},
|
||||
"name": {
|
||||
"type": "string",
|
||||
"description": "The name of this cluster. The name must be unique within this project and zone, and can be up to 40 characters with the following restrictions: \n- Lowercase letters, numbers, and hyphens only.\n- Must start with a letter.\n- Must end with a number or a letter."
|
||||
},
|
||||
"network": {
|
||||
"type": "string",
|
||||
"description": "The name of the Google Compute Engine network to which the cluster is connected."
|
||||
},
|
||||
"nodeConfig": {
|
||||
"$ref": "NodeConfig",
|
||||
"description": "The machine type and image to use for all nodes in this cluster. See the descriptions of the child properties of nodeConfig."
|
||||
|
@ -122,9 +141,13 @@
|
|||
"description": "The number of nodes to create in this cluster. You must ensure that your Compute Engine resource quota is sufficient for this number of instances plus one (to include the master). You must also have available firewall and routes quota.",
|
||||
"format": "int32"
|
||||
},
|
||||
"selfLink": {
|
||||
"type": "string",
|
||||
"description": "[Output only] Server-defined URL for the resource."
|
||||
},
|
||||
"servicesIpv4Cidr": {
|
||||
"type": "string",
|
||||
"description": "[Output only] The IP addresses of the Kubernetes services in this cluster, in CIDR notation (e.g. 1.2.3.4/29). Service addresses are always in the 10.0.0.0/16 range."
|
||||
"description": "[Output only] The IP address range of the Kubernetes services in this cluster, in CIDR notation (e.g. 1.2.3.4/29). Service addresses are typically put in the last /16 from the container CIDR."
|
||||
},
|
||||
"status": {
|
||||
"type": "string",
|
||||
|
@ -155,7 +178,6 @@
|
|||
"CreateClusterRequest": {
|
||||
"id": "CreateClusterRequest",
|
||||
"type": "object",
|
||||
"externalTypeName": "container.v1beta1.CreateClusterRequest",
|
||||
"properties": {
|
||||
"cluster": {
|
||||
"$ref": "Cluster",
|
||||
|
@ -166,7 +188,6 @@
|
|||
"ListAggregatedClustersResponse": {
|
||||
"id": "ListAggregatedClustersResponse",
|
||||
"type": "object",
|
||||
"externalTypeName": "container.v1beta1.ListAggregatedClustersResponse",
|
||||
"properties": {
|
||||
"clusters": {
|
||||
"type": "array",
|
||||
|
@ -180,7 +201,6 @@
|
|||
"ListAggregatedOperationsResponse": {
|
||||
"id": "ListAggregatedOperationsResponse",
|
||||
"type": "object",
|
||||
"externalTypeName": "container.v1beta1.ListAggregatedOperationsResponse",
|
||||
"properties": {
|
||||
"operations": {
|
||||
"type": "array",
|
||||
|
@ -194,7 +214,6 @@
|
|||
"ListClustersResponse": {
|
||||
"id": "ListClustersResponse",
|
||||
"type": "object",
|
||||
"externalTypeName": "container.v1beta1.ListClustersResponse",
|
||||
"properties": {
|
||||
"clusters": {
|
||||
"type": "array",
|
||||
|
@ -208,7 +227,6 @@
|
|||
"ListOperationsResponse": {
|
||||
"id": "ListOperationsResponse",
|
||||
"type": "object",
|
||||
"externalTypeName": "container.v1beta1.ListOperationsResponse",
|
||||
"properties": {
|
||||
"operations": {
|
||||
"type": "array",
|
||||
|
@ -222,27 +240,49 @@
|
|||
"MasterAuth": {
|
||||
"id": "MasterAuth",
|
||||
"type": "object",
|
||||
"externalTypeName": "container.v1beta1.MasterAuth",
|
||||
"description": "The authentication information for accessing the master. Authentication is either done using HTTP basic authentication or using a bearer token.",
|
||||
"properties": {
|
||||
"bearerToken": {
|
||||
"type": "string",
|
||||
"description": "The token used to authenticate API requests to the master. The token is to be included in an HTTP Authorization Header in all requests to the master endpoint. The format of the header is: \"Authorization: Bearer \"."
|
||||
},
|
||||
"clientCertificate": {
|
||||
"type": "string",
|
||||
"description": "[Output only] Base64 encoded public certificate used by clients to authenticate to the cluster endpoint."
|
||||
},
|
||||
"clientKey": {
|
||||
"type": "string",
|
||||
"description": "[Output only] Base64 encoded private key used by clients to authenticate to the cluster endpoint."
|
||||
},
|
||||
"clusterCaCertificate": {
|
||||
"type": "string",
|
||||
"description": "[Output only] Base64 encoded public certificate that is the root of trust for the cluster."
|
||||
},
|
||||
"password": {
|
||||
"type": "string",
|
||||
"description": "The password to use when accessing the Kubernetes master endpoint."
|
||||
"description": "The password to use for HTTP basic authentication when accessing the Kubernetes master endpoint. Because the master endpoint is open to the internet, you should create a strong password."
|
||||
},
|
||||
"user": {
|
||||
"type": "string",
|
||||
"description": "The username to use when accessing the Kubernetes master endpoint."
|
||||
"description": "The username to use for HTTP basic authentication when accessing the Kubernetes master endpoint."
|
||||
}
|
||||
}
|
||||
},
|
||||
"NodeConfig": {
|
||||
"id": "NodeConfig",
|
||||
"type": "object",
|
||||
"externalTypeName": "container.v1beta1.NodeConfig",
|
||||
"properties": {
|
||||
"machineType": {
|
||||
"type": "string",
|
||||
"description": "The name of a Google Compute Engine machine type (e.g. n1-standard-1).\n\nIf unspecified, the default machine type is n1-standard-1."
|
||||
},
|
||||
"serviceAccounts": {
|
||||
"type": "array",
|
||||
"description": "The optional list of ServiceAccounts, each with their specified scopes, to be made available on all of the node VMs. In addition to the service accounts and scopes specified, the \"default\" account will always be created with the following scopes to ensure the correct functioning of the cluster: \n- https://www.googleapis.com/auth/compute,\n- https://www.googleapis.com/auth/devstorage.read_only",
|
||||
"items": {
|
||||
"$ref": "ServiceAccount"
|
||||
}
|
||||
},
|
||||
"sourceImage": {
|
||||
"type": "string",
|
||||
"description": "The fully-specified name of a Google Compute Engine image. For example: https://www.googleapis.com/compute/v1/projects/debian-cloud/global/images/backports-debian-7-wheezy-vYYYYMMDD (where YYYMMDD is the version date).\n\nIf specifying an image, you are responsible for ensuring its compatibility with the Debian 7 backports image. We recommend leaving this field blank to accept the default backports-debian-7-wheezy value."
|
||||
|
@ -253,7 +293,6 @@
|
|||
"id": "Operation",
|
||||
"type": "object",
|
||||
"description": "Defines the operation resource. All fields are output only.",
|
||||
"externalTypeName": "container.v1beta1.Operation",
|
||||
"properties": {
|
||||
"errorMessage": {
|
||||
"type": "string",
|
||||
|
@ -261,7 +300,7 @@
|
|||
},
|
||||
"name": {
|
||||
"type": "string",
|
||||
"description": "The server-assigned ID for this operation. If the operation is fulfilled upfront, it may not have a resource name."
|
||||
"description": "The server-assigned ID for the operation."
|
||||
},
|
||||
"operationType": {
|
||||
"type": "string",
|
||||
|
@ -275,6 +314,10 @@
|
|||
""
|
||||
]
|
||||
},
|
||||
"selfLink": {
|
||||
"type": "string",
|
||||
"description": "Server-defined URL for the resource."
|
||||
},
|
||||
"status": {
|
||||
"type": "string",
|
||||
"description": "The current status of the operation.",
|
||||
|
@ -293,11 +336,33 @@
|
|||
"type": "string",
|
||||
"description": "[Optional] The URL of the cluster resource that this operation is associated with."
|
||||
},
|
||||
"targetLink": {
|
||||
"type": "string",
|
||||
"description": "Server-defined URL for the target of the operation."
|
||||
},
|
||||
"zone": {
|
||||
"type": "string",
|
||||
"description": "The name of the Google Compute Engine zone in which the operation is taking place."
|
||||
}
|
||||
}
|
||||
},
|
||||
"ServiceAccount": {
|
||||
"id": "ServiceAccount",
|
||||
"type": "object",
|
||||
"description": "A Compute Engine service account.",
|
||||
"properties": {
|
||||
"email": {
|
||||
"type": "string",
|
||||
"description": "Email address of the service account."
|
||||
},
|
||||
"scopes": {
|
||||
"type": "array",
|
||||
"description": "The list of scopes to be made available for this service account.",
|
||||
"items": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"resources": {
|
||||
|
@ -365,7 +430,7 @@
|
|||
"id": "container.projects.zones.clusters.create",
|
||||
"path": "{projectId}/zones/{zoneId}/clusters",
|
||||
"httpMethod": "POST",
|
||||
"description": "Creates a cluster, consisting of the specified number and type of Google Compute Engine instances, plus a Kubernetes master instance.\n\nThe cluster is created in the project's default network.\n\nA firewall is added that allows traffic into port 443 on the master, which enables HTTPS. A firewall and a route is added for each node to allow the containers on that node to communicate with all other instances in the cluster.\n\nFinally, a route named k8s-iproute-10-xx-0-0 is created to track that the cluster's 10.xx.0.0/16 CIDR has been assigned.",
|
||||
"description": "Creates a cluster, consisting of the specified number and type of Google Compute Engine instances, plus a Kubernetes master instance.\n\nThe cluster is created in the project's default network.\n\nA firewall is added that allows traffic into port 443 on the master, which enables HTTPS. A firewall and a route is added for each node to allow the containers on that node to communicate with all other instances in the cluster.\n\nFinally, an entry is added to the project's global metadata indicating which CIDR range is being used by the cluster.",
|
||||
"parameters": {
|
||||
"projectId": {
|
||||
"type": "string",
|
|
@ -1,18 +1,21 @@
|
|||
// Package container provides access to the Google Container Engine API.
|
||||
//
|
||||
// See https://cloud.google.com/container-engine/docs/v1beta1/
|
||||
//
|
||||
// Usage example:
|
||||
//
|
||||
// import "code.google.com/p/google-api-go-client/container/v1beta1"
|
||||
// import "google.golang.org/api/container/v1beta1"
|
||||
// ...
|
||||
// containerService, err := container.New(oauthHttpClient)
|
||||
package container
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"code.google.com/p/google-api-go-client/googleapi"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"golang.org/x/net/context"
|
||||
"google.golang.org/api/googleapi"
|
||||
"io"
|
||||
"net/http"
|
||||
"net/url"
|
||||
|
@ -31,6 +34,7 @@ var _ = url.Parse
|
|||
var _ = googleapi.Version
|
||||
var _ = errors.New
|
||||
var _ = strings.Replace
|
||||
var _ = context.Background
|
||||
|
||||
const apiId = "container:v1beta1"
|
||||
const apiName = "container"
|
||||
|
@ -53,12 +57,20 @@ func New(client *http.Client) (*Service, error) {
|
|||
}
|
||||
|
||||
type Service struct {
|
||||
client *http.Client
|
||||
BasePath string // API endpoint base URL
|
||||
client *http.Client
|
||||
BasePath string // API endpoint base URL
|
||||
UserAgent string // optional additional User-Agent fragment
|
||||
|
||||
Projects *ProjectsService
|
||||
}
|
||||
|
||||
func (s *Service) userAgent() string {
|
||||
if s.UserAgent == "" {
|
||||
return googleapi.UserAgent
|
||||
}
|
||||
return googleapi.UserAgent + " " + s.UserAgent
|
||||
}
|
||||
|
||||
func NewProjectsService(s *Service) *ProjectsService {
|
||||
rs := &ProjectsService{s: s}
|
||||
rs.Clusters = NewProjectsClustersService(s)
|
||||
|
@ -130,12 +142,17 @@ type ProjectsZonesOperationsService struct {
|
|||
|
||||
type Cluster struct {
|
||||
// ClusterApiVersion: The API version of the Kubernetes master and
|
||||
// kubelets running in this cluster. Allowed value is 0.4.2, or leave
|
||||
// blank to pick up the latest stable release.
|
||||
// kubelets running in this cluster. Leave blank to pick up the latest
|
||||
// stable release, or specify a version of the form "x.y.z". The Google
|
||||
// Container Engine release notes lists the currently supported
|
||||
// versions. If an incorrect version is specified, the server returns an
|
||||
// error listing the currently supported versions.
|
||||
ClusterApiVersion string `json:"clusterApiVersion,omitempty"`
|
||||
|
||||
// ContainerIpv4Cidr: [Output only] The IP addresses of the container
|
||||
// pods in this cluster, in CIDR notation (e.g. 1.2.3.4/29).
|
||||
// ContainerIpv4Cidr: The IP address range of the container pods in this
|
||||
// cluster, in CIDR notation (e.g. 10.96.0.0/14). Leave blank to have
|
||||
// one automatically chosen or specify a /14 block in 10.0.0.0/8 or
|
||||
// 172.16.0.0/12.
|
||||
ContainerIpv4Cidr string `json:"containerIpv4Cidr,omitempty"`
|
||||
|
||||
// CreationTimestamp: [Output only] The time the cluster was created, in
|
||||
|
@ -145,28 +162,43 @@ type Cluster struct {
|
|||
// Description: An optional description of this cluster.
|
||||
Description string `json:"description,omitempty"`
|
||||
|
||||
// EnableCloudLogging: Whether logs from the cluster should be made
|
||||
// available via the Google Cloud Logging service. This includes both
|
||||
// logs from your applications running in the cluster as well as logs
|
||||
// from the Kubernetes components themselves.
|
||||
EnableCloudLogging bool `json:"enableCloudLogging,omitempty"`
|
||||
|
||||
// EnableCloudMonitoring: Whether metrics from the cluster should be
|
||||
// made available via the Google Cloud Monitoring service.
|
||||
EnableCloudMonitoring bool `json:"enableCloudMonitoring,omitempty"`
|
||||
|
||||
// Endpoint: [Output only] The IP address of this cluster's Kubernetes
|
||||
// master. The endpoint can be accessed from the internet at
|
||||
// https://username:password@endpoint/.
|
||||
//
|
||||
// See the masterAuth property of
|
||||
// this resource for username and password information.
|
||||
// See the masterAuth property of this resource for username and
|
||||
// password information.
|
||||
Endpoint string `json:"endpoint,omitempty"`
|
||||
|
||||
// MasterAuth: The HTTP basic authentication information for accessing
|
||||
// the master. Because the master endpoint is open to the internet, you
|
||||
// should create a strong password.
|
||||
// InstanceGroupUrls: [Output only] The resource URLs of [instance
|
||||
// groups](/compute/docs/instance-groups/) associated with this cluster.
|
||||
InstanceGroupUrls []string `json:"instanceGroupUrls,omitempty"`
|
||||
|
||||
// MasterAuth: The authentication information for accessing the master.
|
||||
MasterAuth *MasterAuth `json:"masterAuth,omitempty"`
|
||||
|
||||
// Name: The name of this cluster. The name must be unique within this
|
||||
// project and zone, and can be up to 40 characters with the following
|
||||
// restrictions:
|
||||
// - Lowercase letters, numbers, and hyphens only.
|
||||
// -
|
||||
// Must start with a letter.
|
||||
// - Must start with a letter.
|
||||
// - Must end with a number or a letter.
|
||||
Name string `json:"name,omitempty"`
|
||||
|
||||
// Network: The name of the Google Compute Engine network to which the
|
||||
// cluster is connected.
|
||||
Network string `json:"network,omitempty"`
|
||||
|
||||
// NodeConfig: The machine type and image to use for all nodes in this
|
||||
// cluster. See the descriptions of the child properties of nodeConfig.
|
||||
NodeConfig *NodeConfig `json:"nodeConfig,omitempty"`
|
||||
|
@ -181,12 +213,22 @@ type Cluster struct {
|
|||
// have available firewall and routes quota.
|
||||
NumNodes int64 `json:"numNodes,omitempty"`
|
||||
|
||||
// ServicesIpv4Cidr: [Output only] The IP addresses of the Kubernetes
|
||||
// services in this cluster, in CIDR notation (e.g. 1.2.3.4/29).
|
||||
// Service addresses are always in the 10.0.0.0/16 range.
|
||||
// SelfLink: [Output only] Server-defined URL for the resource.
|
||||
SelfLink string `json:"selfLink,omitempty"`
|
||||
|
||||
// ServicesIpv4Cidr: [Output only] The IP address range of the
|
||||
// Kubernetes services in this cluster, in CIDR notation (e.g.
|
||||
// 1.2.3.4/29). Service addresses are typically put in the last /16 from
|
||||
// the container CIDR.
|
||||
ServicesIpv4Cidr string `json:"servicesIpv4Cidr,omitempty"`
|
||||
|
||||
// Status: [Output only] The current status of this cluster.
|
||||
//
|
||||
// Possible values:
|
||||
// "error"
|
||||
// "provisioning"
|
||||
// "running"
|
||||
// "stopping"
|
||||
Status string `json:"status,omitempty"`
|
||||
|
||||
// StatusMessage: [Output only] Additional information about the current
|
||||
|
@ -224,13 +266,35 @@ type ListOperationsResponse struct {
|
|||
Operations []*Operation `json:"operations,omitempty"`
|
||||
}
|
||||
|
||||
// MasterAuth: The authentication information for accessing the master.
|
||||
// Authentication is either done using HTTP basic authentication or
|
||||
// using a bearer token.
|
||||
type MasterAuth struct {
|
||||
// Password: The password to use when accessing the Kubernetes master
|
||||
// endpoint.
|
||||
// BearerToken: The token used to authenticate API requests to the
|
||||
// master. The token is to be included in an HTTP Authorization Header
|
||||
// in all requests to the master endpoint. The format of the header is:
|
||||
// "Authorization: Bearer ".
|
||||
BearerToken string `json:"bearerToken,omitempty"`
|
||||
|
||||
// ClientCertificate: [Output only] Base64 encoded public certificate
|
||||
// used by clients to authenticate to the cluster endpoint.
|
||||
ClientCertificate string `json:"clientCertificate,omitempty"`
|
||||
|
||||
// ClientKey: [Output only] Base64 encoded private key used by clients
|
||||
// to authenticate to the cluster endpoint.
|
||||
ClientKey string `json:"clientKey,omitempty"`
|
||||
|
||||
// ClusterCaCertificate: [Output only] Base64 encoded public certificate
|
||||
// that is the root of trust for the cluster.
|
||||
ClusterCaCertificate string `json:"clusterCaCertificate,omitempty"`
|
||||
|
||||
// Password: The password to use for HTTP basic authentication when
|
||||
// accessing the Kubernetes master endpoint. Because the master endpoint
|
||||
// is open to the internet, you should create a strong password.
|
||||
Password string `json:"password,omitempty"`
|
||||
|
||||
// User: The username to use when accessing the Kubernetes master
|
||||
// endpoint.
|
||||
// User: The username to use for HTTP basic authentication when
|
||||
// accessing the Kubernetes master endpoint.
|
||||
User string `json:"user,omitempty"`
|
||||
}
|
||||
|
||||
|
@ -238,15 +302,21 @@ type NodeConfig struct {
|
|||
// MachineType: The name of a Google Compute Engine machine type (e.g.
|
||||
// n1-standard-1).
|
||||
//
|
||||
// If unspecified, the default machine type is
|
||||
// n1-standard-1.
|
||||
// If unspecified, the default machine type is n1-standard-1.
|
||||
MachineType string `json:"machineType,omitempty"`
|
||||
|
||||
// ServiceAccounts: The optional list of ServiceAccounts, each with
|
||||
// their specified scopes, to be made available on all of the node VMs.
|
||||
// In addition to the service accounts and scopes specified, the
|
||||
// "default" account will always be created with the following scopes to
|
||||
// ensure the correct functioning of the cluster:
|
||||
// - https://www.googleapis.com/auth/compute,
|
||||
// - https://www.googleapis.com/auth/devstorage.read_only
|
||||
ServiceAccounts []*ServiceAccount `json:"serviceAccounts,omitempty"`
|
||||
|
||||
// SourceImage: The fully-specified name of a Google Compute Engine
|
||||
// image. For example:
|
||||
// https://www.googleapis.com/compute/v1/projects/debian-cloud/global/ima
|
||||
// ges/backports-debian-7-wheezy-vYYYYMMDD (where YYYMMDD is the version
|
||||
// date).
|
||||
// https://www.googleapis.com/compute/v1/projects/debian-cloud/global/images/backports-debian-7-wheezy-vYYYYMMDD (where YYYMMDD is the version date).
|
||||
//
|
||||
// If specifying an image, you are responsible for ensuring its
|
||||
// compatibility with the Debian 7 backports image. We recommend leaving
|
||||
|
@ -255,30 +325,56 @@ type NodeConfig struct {
|
|||
SourceImage string `json:"sourceImage,omitempty"`
|
||||
}
|
||||
|
||||
// Operation: Defines the operation resource. All fields are output
|
||||
// only.
|
||||
type Operation struct {
|
||||
// ErrorMessage: If an error has occurred, a textual description of the
|
||||
// error.
|
||||
ErrorMessage string `json:"errorMessage,omitempty"`
|
||||
|
||||
// Name: The server-assigned ID for this operation. If the operation is
|
||||
// fulfilled upfront, it may not have a resource name.
|
||||
// Name: The server-assigned ID for the operation.
|
||||
Name string `json:"name,omitempty"`
|
||||
|
||||
// OperationType: The operation type.
|
||||
//
|
||||
// Possible values:
|
||||
// "createCluster"
|
||||
// "deleteCluster"
|
||||
OperationType string `json:"operationType,omitempty"`
|
||||
|
||||
// SelfLink: Server-defined URL for the resource.
|
||||
SelfLink string `json:"selfLink,omitempty"`
|
||||
|
||||
// Status: The current status of the operation.
|
||||
//
|
||||
// Possible values:
|
||||
// "done"
|
||||
// "pending"
|
||||
// "running"
|
||||
Status string `json:"status,omitempty"`
|
||||
|
||||
// Target: [Optional] The URL of the cluster resource that this
|
||||
// operation is associated with.
|
||||
Target string `json:"target,omitempty"`
|
||||
|
||||
// TargetLink: Server-defined URL for the target of the operation.
|
||||
TargetLink string `json:"targetLink,omitempty"`
|
||||
|
||||
// Zone: The name of the Google Compute Engine zone in which the
|
||||
// operation is taking place.
|
||||
Zone string `json:"zone,omitempty"`
|
||||
}
|
||||
|
||||
// ServiceAccount: A Compute Engine service account.
|
||||
type ServiceAccount struct {
|
||||
// Email: Email address of the service account.
|
||||
Email string `json:"email,omitempty"`
|
||||
|
||||
// Scopes: The list of scopes to be made available for this service
|
||||
// account.
|
||||
Scopes []string `json:"scopes,omitempty"`
|
||||
}
|
||||
|
||||
// method id "container.projects.clusters.list":
|
||||
|
||||
type ProjectsClustersListCall struct {
|
||||
|
@ -315,7 +411,7 @@ func (c *ProjectsClustersListCall) Do() (*ListAggregatedClustersResponse, error)
|
|||
googleapi.Expand(req.URL, map[string]string{
|
||||
"projectId": c.projectId,
|
||||
})
|
||||
req.Header.Set("User-Agent", "google-api-go-client/0.5")
|
||||
req.Header.Set("User-Agent", c.s.userAgent())
|
||||
res, err := c.s.client.Do(req)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
@ -391,7 +487,7 @@ func (c *ProjectsOperationsListCall) Do() (*ListAggregatedOperationsResponse, er
|
|||
googleapi.Expand(req.URL, map[string]string{
|
||||
"projectId": c.projectId,
|
||||
})
|
||||
req.Header.Set("User-Agent", "google-api-go-client/0.5")
|
||||
req.Header.Set("User-Agent", c.s.userAgent())
|
||||
res, err := c.s.client.Do(req)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
@ -445,17 +541,15 @@ type ProjectsZonesClustersCreateCall struct {
|
|||
// type of Google Compute Engine instances, plus a Kubernetes master
|
||||
// instance.
|
||||
//
|
||||
// The cluster is created in the project's default
|
||||
// network.
|
||||
// The cluster is created in the project's default network.
|
||||
//
|
||||
// A firewall is added that allows traffic into port 443 on
|
||||
// the master, which enables HTTPS. A firewall and a route is added for
|
||||
// each node to allow the containers on that node to communicate with
|
||||
// all other instances in the cluster.
|
||||
// A firewall is added that allows traffic into port 443 on the master,
|
||||
// which enables HTTPS. A firewall and a route is added for each node to
|
||||
// allow the containers on that node to communicate with all other
|
||||
// instances in the cluster.
|
||||
//
|
||||
// Finally, a route named
|
||||
// k8s-iproute-10-xx-0-0 is created to track that the cluster's
|
||||
// 10.xx.0.0/16 CIDR has been assigned.
|
||||
// Finally, an entry is added to the project's global metadata
|
||||
// indicating which CIDR range is being used by the cluster.
|
||||
func (r *ProjectsZonesClustersService) Create(projectId string, zoneId string, createclusterrequest *CreateClusterRequest) *ProjectsZonesClustersCreateCall {
|
||||
c := &ProjectsZonesClustersCreateCall{s: r.s, opt_: make(map[string]interface{})}
|
||||
c.projectId = projectId
|
||||
|
@ -492,7 +586,7 @@ func (c *ProjectsZonesClustersCreateCall) Do() (*Operation, error) {
|
|||
"zoneId": c.zoneId,
|
||||
})
|
||||
req.Header.Set("Content-Type", ctype)
|
||||
req.Header.Set("User-Agent", "google-api-go-client/0.5")
|
||||
req.Header.Set("User-Agent", c.s.userAgent())
|
||||
res, err := c.s.client.Do(req)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
@ -507,7 +601,7 @@ func (c *ProjectsZonesClustersCreateCall) Do() (*Operation, error) {
|
|||
}
|
||||
return ret, nil
|
||||
// {
|
||||
// "description": "Creates a cluster, consisting of the specified number and type of Google Compute Engine instances, plus a Kubernetes master instance.\n\nThe cluster is created in the project's default network.\n\nA firewall is added that allows traffic into port 443 on the master, which enables HTTPS. A firewall and a route is added for each node to allow the containers on that node to communicate with all other instances in the cluster.\n\nFinally, a route named k8s-iproute-10-xx-0-0 is created to track that the cluster's 10.xx.0.0/16 CIDR has been assigned.",
|
||||
// "description": "Creates a cluster, consisting of the specified number and type of Google Compute Engine instances, plus a Kubernetes master instance.\n\nThe cluster is created in the project's default network.\n\nA firewall is added that allows traffic into port 443 on the master, which enables HTTPS. A firewall and a route is added for each node to allow the containers on that node to communicate with all other instances in the cluster.\n\nFinally, an entry is added to the project's global metadata indicating which CIDR range is being used by the cluster.",
|
||||
// "httpMethod": "POST",
|
||||
// "id": "container.projects.zones.clusters.create",
|
||||
// "parameterOrder": [
|
||||
|
@ -555,8 +649,8 @@ type ProjectsZonesClustersDeleteCall struct {
|
|||
// Delete: Deletes the cluster, including the Kubernetes master and all
|
||||
// worker nodes.
|
||||
//
|
||||
// Firewalls and routes that were configured at cluster
|
||||
// creation are also deleted.
|
||||
// Firewalls and routes that were configured at cluster creation are
|
||||
// also deleted.
|
||||
func (r *ProjectsZonesClustersService) Delete(projectId string, zoneId string, clusterId string) *ProjectsZonesClustersDeleteCall {
|
||||
c := &ProjectsZonesClustersDeleteCall{s: r.s, opt_: make(map[string]interface{})}
|
||||
c.projectId = projectId
|
||||
|
@ -588,7 +682,7 @@ func (c *ProjectsZonesClustersDeleteCall) Do() (*Operation, error) {
|
|||
"zoneId": c.zoneId,
|
||||
"clusterId": c.clusterId,
|
||||
})
|
||||
req.Header.Set("User-Agent", "google-api-go-client/0.5")
|
||||
req.Header.Set("User-Agent", c.s.userAgent())
|
||||
res, err := c.s.client.Do(req)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
@ -684,7 +778,7 @@ func (c *ProjectsZonesClustersGetCall) Do() (*Cluster, error) {
|
|||
"zoneId": c.zoneId,
|
||||
"clusterId": c.clusterId,
|
||||
})
|
||||
req.Header.Set("User-Agent", "google-api-go-client/0.5")
|
||||
req.Header.Set("User-Agent", c.s.userAgent())
|
||||
res, err := c.s.client.Do(req)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
@ -777,7 +871,7 @@ func (c *ProjectsZonesClustersListCall) Do() (*ListClustersResponse, error) {
|
|||
"projectId": c.projectId,
|
||||
"zoneId": c.zoneId,
|
||||
})
|
||||
req.Header.Set("User-Agent", "google-api-go-client/0.5")
|
||||
req.Header.Set("User-Agent", c.s.userAgent())
|
||||
res, err := c.s.client.Do(req)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
@ -866,7 +960,7 @@ func (c *ProjectsZonesOperationsGetCall) Do() (*Operation, error) {
|
|||
"zoneId": c.zoneId,
|
||||
"operationId": c.operationId,
|
||||
})
|
||||
req.Header.Set("User-Agent", "google-api-go-client/0.5")
|
||||
req.Header.Set("User-Agent", c.s.userAgent())
|
||||
res, err := c.s.client.Do(req)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
@ -959,7 +1053,7 @@ func (c *ProjectsZonesOperationsListCall) Do() (*ListOperationsResponse, error)
|
|||
"projectId": c.projectId,
|
||||
"zoneId": c.zoneId,
|
||||
})
|
||||
req.Header.Set("User-Agent", "google-api-go-client/0.5")
|
||||
req.Header.Set("User-Agent", c.s.userAgent())
|
||||
res, err := c.s.client.Do(req)
|
||||
if err != nil {
|
||||
return nil, err
|
|
@ -9,6 +9,7 @@ package googleapi
|
|||
import (
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
|
@ -16,10 +17,14 @@ import (
|
|||
"net/http"
|
||||
"net/textproto"
|
||||
"net/url"
|
||||
"os"
|
||||
"regexp"
|
||||
"strconv"
|
||||
"strings"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"code.google.com/p/google-api-go-client/googleapi/internal/uritemplates"
|
||||
"golang.org/x/net/context"
|
||||
"google.golang.org/api/googleapi/internal/uritemplates"
|
||||
)
|
||||
|
||||
// ContentTyper is an interface for Readers which know (or would like
|
||||
|
@ -30,7 +35,25 @@ type ContentTyper interface {
|
|||
ContentType() string
|
||||
}
|
||||
|
||||
const Version = "0.5"
|
||||
// A SizeReaderAt is a ReaderAt with a Size method.
|
||||
// An io.SectionReader implements SizeReaderAt.
|
||||
type SizeReaderAt interface {
|
||||
io.ReaderAt
|
||||
Size() int64
|
||||
}
|
||||
|
||||
const (
|
||||
Version = "0.5"
|
||||
|
||||
// statusResumeIncomplete is the code returned by the Google uploader when the transfer is not yet complete.
|
||||
statusResumeIncomplete = 308
|
||||
|
||||
// UserAgent is the header string used to identify this package.
|
||||
UserAgent = "google-api-go-client/" + Version
|
||||
|
||||
// uploadPause determines the delay between failed upload attempts
|
||||
uploadPause = 1 * time.Second
|
||||
)
|
||||
|
||||
// Error contains an error response from the server.
|
||||
type Error struct {
|
||||
|
@ -130,14 +153,41 @@ func getMediaType(media io.Reader) (io.Reader, string) {
|
|||
return media, typer.ContentType()
|
||||
}
|
||||
|
||||
pr, pw := io.Pipe()
|
||||
typ := "application/octet-stream"
|
||||
buf, err := ioutil.ReadAll(io.LimitReader(media, 512))
|
||||
if err != nil {
|
||||
pw.CloseWithError(fmt.Errorf("error reading media: %v", err))
|
||||
return pr, typ
|
||||
}
|
||||
typ = http.DetectContentType(buf)
|
||||
mr := io.MultiReader(bytes.NewReader(buf), media)
|
||||
go func() {
|
||||
_, err = io.Copy(pw, mr)
|
||||
if err != nil {
|
||||
pw.CloseWithError(fmt.Errorf("error reading media: %v", err))
|
||||
return
|
||||
}
|
||||
pw.Close()
|
||||
}()
|
||||
return pr, typ
|
||||
}
|
||||
|
||||
// DetectMediaType detects and returns the content type of the provided media.
|
||||
// If the type can not be determined, "application/octet-stream" is returned.
|
||||
func DetectMediaType(media io.ReaderAt) string {
|
||||
if typer, ok := media.(ContentTyper); ok {
|
||||
return typer.ContentType()
|
||||
}
|
||||
|
||||
typ := "application/octet-stream"
|
||||
buf := make([]byte, 1024)
|
||||
n, err := media.Read(buf)
|
||||
n, err := media.ReadAt(buf, 0)
|
||||
buf = buf[:n]
|
||||
if err == nil {
|
||||
if err == nil || err == io.EOF {
|
||||
typ = http.DetectContentType(buf)
|
||||
}
|
||||
return io.MultiReader(bytes.NewBuffer(buf), media), typ
|
||||
return typ
|
||||
}
|
||||
|
||||
type Lengther interface {
|
||||
|
@ -145,7 +195,7 @@ type Lengther interface {
|
|||
}
|
||||
|
||||
// endingWithErrorReader from r until it returns an error. If the
|
||||
// final error from r is os.EOF and e is non-nil, e is used instead.
|
||||
// final error from r is io.EOF and e is non-nil, e is used instead.
|
||||
type endingWithErrorReader struct {
|
||||
r io.Reader
|
||||
e error
|
||||
|
@ -159,38 +209,6 @@ func (er endingWithErrorReader) Read(p []byte) (n int, err error) {
|
|||
return
|
||||
}
|
||||
|
||||
func getReaderSize(r io.Reader) (io.Reader, int64) {
|
||||
// Ideal case, the reader knows its own size.
|
||||
if lr, ok := r.(Lengther); ok {
|
||||
return r, int64(lr.Len())
|
||||
}
|
||||
|
||||
// But maybe it's a seeker and we can seek to the end to find its size.
|
||||
if s, ok := r.(io.Seeker); ok {
|
||||
pos0, err := s.Seek(0, os.SEEK_CUR)
|
||||
if err == nil {
|
||||
posend, err := s.Seek(0, os.SEEK_END)
|
||||
if err == nil {
|
||||
_, err = s.Seek(pos0, os.SEEK_SET)
|
||||
if err == nil {
|
||||
return r, posend - pos0
|
||||
} else {
|
||||
// We moved it forward but can't restore it.
|
||||
// Seems unlikely, but can't really restore now.
|
||||
return endingWithErrorReader{strings.NewReader(""), err}, posend - pos0
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Otherwise we have to make a copy to calculate how big the reader is.
|
||||
buf := new(bytes.Buffer)
|
||||
// TODO(bradfitz): put a cap on this copy? spill to disk after
|
||||
// a certain point?
|
||||
_, err := io.Copy(buf, r)
|
||||
return endingWithErrorReader{buf, err}, int64(buf.Len())
|
||||
}
|
||||
|
||||
func typeHeader(contentType string) textproto.MIMEHeader {
|
||||
h := make(textproto.MIMEHeader)
|
||||
h.Set("Content-Type", contentType)
|
||||
|
@ -219,60 +237,192 @@ func (w countingWriter) Write(p []byte) (int, error) {
|
|||
// to the "multipart/related" content type, with random boundary.
|
||||
//
|
||||
// The return value is the content-length of the entire multpart body.
|
||||
func ConditionallyIncludeMedia(media io.Reader, bodyp *io.Reader, ctypep *string) (totalContentLength int64, ok bool) {
|
||||
func ConditionallyIncludeMedia(media io.Reader, bodyp *io.Reader, ctypep *string) (cancel func(), ok bool) {
|
||||
if media == nil {
|
||||
return
|
||||
}
|
||||
// Get the media type and size. The type check might return a
|
||||
// different reader instance, so do the size check first,
|
||||
// which looks at the specific type of the io.Reader.
|
||||
// Get the media type, which might return a different reader instance.
|
||||
var mediaType string
|
||||
if typer, ok := media.(ContentTyper); ok {
|
||||
mediaType = typer.ContentType()
|
||||
}
|
||||
media, mediaSize := getReaderSize(media)
|
||||
if mediaType == "" {
|
||||
media, mediaType = getMediaType(media)
|
||||
}
|
||||
body, bodyType := *bodyp, *ctypep
|
||||
body, bodySize := getReaderSize(body)
|
||||
media, mediaType = getMediaType(media)
|
||||
|
||||
// Calculate how big the the multipart will be.
|
||||
{
|
||||
totalContentLength = bodySize + mediaSize
|
||||
mpw := multipart.NewWriter(countingWriter{&totalContentLength})
|
||||
mpw.CreatePart(typeHeader(bodyType))
|
||||
mpw.CreatePart(typeHeader(mediaType))
|
||||
mpw.Close()
|
||||
}
|
||||
body, bodyType := *bodyp, *ctypep
|
||||
|
||||
pr, pw := io.Pipe()
|
||||
mpw := multipart.NewWriter(pw)
|
||||
*bodyp = pr
|
||||
*ctypep = "multipart/related; boundary=" + mpw.Boundary()
|
||||
go func() {
|
||||
defer pw.Close()
|
||||
defer mpw.Close()
|
||||
|
||||
w, err := mpw.CreatePart(typeHeader(bodyType))
|
||||
if err != nil {
|
||||
mpw.Close()
|
||||
pw.CloseWithError(fmt.Errorf("googleapi: body CreatePart failed: %v", err))
|
||||
return
|
||||
}
|
||||
_, err = io.Copy(w, body)
|
||||
if err != nil {
|
||||
mpw.Close()
|
||||
pw.CloseWithError(fmt.Errorf("googleapi: body Copy failed: %v", err))
|
||||
return
|
||||
}
|
||||
|
||||
w, err = mpw.CreatePart(typeHeader(mediaType))
|
||||
if err != nil {
|
||||
mpw.Close()
|
||||
pw.CloseWithError(fmt.Errorf("googleapi: media CreatePart failed: %v", err))
|
||||
return
|
||||
}
|
||||
_, err = io.Copy(w, media)
|
||||
if err != nil {
|
||||
mpw.Close()
|
||||
pw.CloseWithError(fmt.Errorf("googleapi: media Copy failed: %v", err))
|
||||
return
|
||||
}
|
||||
mpw.Close()
|
||||
pw.Close()
|
||||
}()
|
||||
return totalContentLength, true
|
||||
cancel = func() { pw.CloseWithError(errAborted) }
|
||||
return cancel, true
|
||||
}
|
||||
|
||||
var errAborted = errors.New("googleapi: upload aborted")
|
||||
|
||||
// ProgressUpdater is a function that is called upon every progress update of a resumable upload.
|
||||
// This is the only part of a resumable upload (from googleapi) that is usable by the developer.
|
||||
// The remaining usable pieces of resumable uploads is exposed in each auto-generated API.
|
||||
type ProgressUpdater func(current, total int64)
|
||||
|
||||
// ResumableUpload is used by the generated APIs to provide resumable uploads.
|
||||
// It is not used by developers directly.
|
||||
type ResumableUpload struct {
|
||||
Client *http.Client
|
||||
// URI is the resumable resource destination provided by the server after specifying "&uploadType=resumable".
|
||||
URI string
|
||||
UserAgent string // User-Agent for header of the request
|
||||
// Media is the object being uploaded.
|
||||
Media io.ReaderAt
|
||||
// MediaType defines the media type, e.g. "image/jpeg".
|
||||
MediaType string
|
||||
// ContentLength is the full size of the object being uploaded.
|
||||
ContentLength int64
|
||||
|
||||
mu sync.Mutex // guards progress
|
||||
progress int64 // number of bytes uploaded so far
|
||||
started bool // whether the upload has been started
|
||||
|
||||
// Callback is an optional function that will be called upon every progress update.
|
||||
Callback ProgressUpdater
|
||||
}
|
||||
|
||||
var (
|
||||
// rangeRE matches the transfer status response from the server. $1 is the last byte index uploaded.
|
||||
rangeRE = regexp.MustCompile(`^bytes=0\-(\d+)$`)
|
||||
// chunkSize is the size of the chunks created during a resumable upload and should be a power of two.
|
||||
// 1<<18 is the minimum size supported by the Google uploader, and there is no maximum.
|
||||
chunkSize int64 = 1 << 18
|
||||
)
|
||||
|
||||
// Progress returns the number of bytes uploaded at this point.
|
||||
func (rx *ResumableUpload) Progress() int64 {
|
||||
rx.mu.Lock()
|
||||
defer rx.mu.Unlock()
|
||||
return rx.progress
|
||||
}
|
||||
|
||||
func (rx *ResumableUpload) transferStatus() (int64, *http.Response, error) {
|
||||
req, _ := http.NewRequest("POST", rx.URI, nil)
|
||||
req.ContentLength = 0
|
||||
req.Header.Set("User-Agent", rx.UserAgent)
|
||||
req.Header.Set("Content-Range", fmt.Sprintf("bytes */%v", rx.ContentLength))
|
||||
res, err := rx.Client.Do(req)
|
||||
if err != nil || res.StatusCode != statusResumeIncomplete {
|
||||
return 0, res, err
|
||||
}
|
||||
var start int64
|
||||
if m := rangeRE.FindStringSubmatch(res.Header.Get("Range")); len(m) == 2 {
|
||||
start, err = strconv.ParseInt(m[1], 10, 64)
|
||||
if err != nil {
|
||||
return 0, nil, fmt.Errorf("unable to parse range size %v", m[1])
|
||||
}
|
||||
start += 1 // Start at the next byte
|
||||
}
|
||||
return start, res, nil
|
||||
}
|
||||
|
||||
type chunk struct {
|
||||
body io.Reader
|
||||
size int64
|
||||
err error
|
||||
}
|
||||
|
||||
func (rx *ResumableUpload) transferChunks(ctx context.Context) (*http.Response, error) {
|
||||
var start int64
|
||||
var err error
|
||||
res := &http.Response{}
|
||||
if rx.started {
|
||||
start, res, err = rx.transferStatus()
|
||||
if err != nil || res.StatusCode != statusResumeIncomplete {
|
||||
return res, err
|
||||
}
|
||||
}
|
||||
rx.started = true
|
||||
|
||||
for {
|
||||
select { // Check for cancellation
|
||||
case <-ctx.Done():
|
||||
res.StatusCode = http.StatusRequestTimeout
|
||||
return res, ctx.Err()
|
||||
default:
|
||||
}
|
||||
reqSize := rx.ContentLength - start
|
||||
if reqSize > chunkSize {
|
||||
reqSize = chunkSize
|
||||
}
|
||||
r := io.NewSectionReader(rx.Media, start, reqSize)
|
||||
req, _ := http.NewRequest("POST", rx.URI, r)
|
||||
req.ContentLength = reqSize
|
||||
req.Header.Set("Content-Range", fmt.Sprintf("bytes %v-%v/%v", start, start+reqSize-1, rx.ContentLength))
|
||||
req.Header.Set("Content-Type", rx.MediaType)
|
||||
req.Header.Set("User-Agent", rx.UserAgent)
|
||||
res, err = rx.Client.Do(req)
|
||||
start += reqSize
|
||||
if err == nil && (res.StatusCode == statusResumeIncomplete || res.StatusCode == http.StatusOK) {
|
||||
rx.mu.Lock()
|
||||
rx.progress = start // keep track of number of bytes sent so far
|
||||
rx.mu.Unlock()
|
||||
if rx.Callback != nil {
|
||||
rx.Callback(start, rx.ContentLength)
|
||||
}
|
||||
}
|
||||
if err != nil || res.StatusCode != statusResumeIncomplete {
|
||||
break
|
||||
}
|
||||
}
|
||||
return res, err
|
||||
}
|
||||
|
||||
var sleep = time.Sleep // override in unit tests
|
||||
|
||||
// Upload starts the process of a resumable upload with a cancellable context.
|
||||
// It retries indefinitely (with a pause of uploadPause between attempts) until cancelled.
|
||||
// It is called from the auto-generated API code and is not visible to the user.
|
||||
// rx is private to the auto-generated API code.
|
||||
func (rx *ResumableUpload) Upload(ctx context.Context) (*http.Response, error) {
|
||||
var res *http.Response
|
||||
var err error
|
||||
for {
|
||||
res, err = rx.transferChunks(ctx)
|
||||
if err != nil || res.StatusCode == http.StatusCreated || res.StatusCode == http.StatusOK {
|
||||
return res, err
|
||||
}
|
||||
select { // Check for cancellation
|
||||
case <-ctx.Done():
|
||||
res.StatusCode = http.StatusRequestTimeout
|
||||
return res, ctx.Err()
|
||||
default:
|
||||
}
|
||||
sleep(uploadPause)
|
||||
}
|
||||
return res, err
|
||||
}
|
||||
|
||||
func ResolveRelative(basestr, relstr string) string {
|
|
@ -11,9 +11,15 @@ import (
|
|||
"io/ioutil"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"os"
|
||||
"reflect"
|
||||
"regexp"
|
||||
"strconv"
|
||||
"strings"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"golang.org/x/net/context"
|
||||
)
|
||||
|
||||
type SetOpaqueTest struct {
|
||||
|
@ -359,3 +365,234 @@ func TestConvertVariant(t *testing.T) {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
type unexpectedReader struct{}
|
||||
|
||||
func (unexpectedReader) Read([]byte) (int, error) {
|
||||
return 0, fmt.Errorf("unexpected read in test.")
|
||||
}
|
||||
|
||||
var contentRangeRE = regexp.MustCompile(`^bytes (\d+)\-(\d+)/(\d+)$`)
|
||||
|
||||
func (t *testTransport) RoundTrip(req *http.Request) (*http.Response, error) {
|
||||
t.req = req
|
||||
if rng := req.Header.Get("Content-Range"); rng != "" && !strings.HasPrefix(rng, "bytes */") { // Read the data
|
||||
m := contentRangeRE.FindStringSubmatch(rng)
|
||||
if len(m) != 4 {
|
||||
return nil, fmt.Errorf("unable to parse content range: %v", rng)
|
||||
}
|
||||
start, err := strconv.ParseInt(m[1], 10, 64)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("unable to parse content range: %v", rng)
|
||||
}
|
||||
end, err := strconv.ParseInt(m[2], 10, 64)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("unable to parse content range: %v", rng)
|
||||
}
|
||||
totalSize, err := strconv.ParseInt(m[3], 10, 64)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("unable to parse content range: %v", rng)
|
||||
}
|
||||
partialSize := end - start + 1
|
||||
t.buf, err = ioutil.ReadAll(req.Body)
|
||||
if err != nil || int64(len(t.buf)) != partialSize {
|
||||
return nil, fmt.Errorf("unable to read %v bytes from request data, n=%v: %v", partialSize, len(t.buf), err)
|
||||
}
|
||||
if totalSize == end+1 {
|
||||
t.statusCode = 200 // signify completion of transfer
|
||||
}
|
||||
}
|
||||
f := ioutil.NopCloser(unexpectedReader{})
|
||||
res := &http.Response{
|
||||
Body: f,
|
||||
StatusCode: t.statusCode,
|
||||
Header: http.Header{},
|
||||
}
|
||||
if t.rangeVal != "" {
|
||||
res.Header.Set("Range", t.rangeVal)
|
||||
}
|
||||
return res, nil
|
||||
}
|
||||
|
||||
type testTransport struct {
|
||||
req *http.Request
|
||||
statusCode int
|
||||
rangeVal string
|
||||
want int64
|
||||
buf []byte
|
||||
}
|
||||
|
||||
var statusTests = []*testTransport{
|
||||
&testTransport{statusCode: 308, want: 0},
|
||||
&testTransport{statusCode: 308, rangeVal: "bytes=0-0", want: 1},
|
||||
&testTransport{statusCode: 308, rangeVal: "bytes=0-42", want: 43},
|
||||
}
|
||||
|
||||
func TestTransferStatus(t *testing.T) {
|
||||
for _, tr := range statusTests {
|
||||
rx := &ResumableUpload{
|
||||
Client: &http.Client{Transport: tr},
|
||||
}
|
||||
g, _, err := rx.transferStatus()
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
if g != tr.want {
|
||||
t.Errorf("transferStatus got %v, want %v", g, tr.want)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (t *interruptedTransport) RoundTrip(req *http.Request) (*http.Response, error) {
|
||||
t.req = req
|
||||
if rng := req.Header.Get("Content-Range"); rng != "" && !strings.HasPrefix(rng, "bytes */") {
|
||||
t.interruptCount += 1
|
||||
if t.interruptCount%7 == 0 { // Respond with a "service unavailable" error
|
||||
res := &http.Response{
|
||||
StatusCode: http.StatusServiceUnavailable,
|
||||
Header: http.Header{},
|
||||
}
|
||||
t.rangeVal = fmt.Sprintf("bytes=0-%v", len(t.buf)-1) // Set the response for next time
|
||||
return res, nil
|
||||
}
|
||||
m := contentRangeRE.FindStringSubmatch(rng)
|
||||
if len(m) != 4 {
|
||||
return nil, fmt.Errorf("unable to parse content range: %v", rng)
|
||||
}
|
||||
start, err := strconv.ParseInt(m[1], 10, 64)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("unable to parse content range: %v", rng)
|
||||
}
|
||||
end, err := strconv.ParseInt(m[2], 10, 64)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("unable to parse content range: %v", rng)
|
||||
}
|
||||
totalSize, err := strconv.ParseInt(m[3], 10, 64)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("unable to parse content range: %v", rng)
|
||||
}
|
||||
partialSize := end - start + 1
|
||||
buf, err := ioutil.ReadAll(req.Body)
|
||||
if err != nil || int64(len(buf)) != partialSize {
|
||||
return nil, fmt.Errorf("unable to read %v bytes from request data, n=%v: %v", partialSize, len(buf), err)
|
||||
}
|
||||
t.buf = append(t.buf, buf...)
|
||||
if totalSize == end+1 {
|
||||
t.statusCode = 200 // signify completion of transfer
|
||||
}
|
||||
}
|
||||
f := ioutil.NopCloser(unexpectedReader{})
|
||||
res := &http.Response{
|
||||
Body: f,
|
||||
StatusCode: t.statusCode,
|
||||
Header: http.Header{},
|
||||
}
|
||||
if t.rangeVal != "" {
|
||||
res.Header.Set("Range", t.rangeVal)
|
||||
}
|
||||
return res, nil
|
||||
}
|
||||
|
||||
type interruptedTransport struct {
|
||||
req *http.Request
|
||||
statusCode int
|
||||
rangeVal string
|
||||
interruptCount int
|
||||
buf []byte
|
||||
progressBuf string
|
||||
}
|
||||
|
||||
func (tr *interruptedTransport) ProgressUpdate(current, total int64) {
|
||||
tr.progressBuf += fmt.Sprintf("%v, %v\n", current, total)
|
||||
}
|
||||
|
||||
func TestInterruptedTransferChunks(t *testing.T) {
|
||||
f, err := os.Open("googleapi.go")
|
||||
if err != nil {
|
||||
t.Fatalf("unable to open googleapi.go: %v", err)
|
||||
}
|
||||
defer f.Close()
|
||||
slurp, err := ioutil.ReadAll(f)
|
||||
if err != nil {
|
||||
t.Fatalf("unable to slurp file: %v", err)
|
||||
}
|
||||
st, err := f.Stat()
|
||||
if err != nil {
|
||||
t.Fatalf("unable to stat googleapi.go: %v", err)
|
||||
}
|
||||
tr := &interruptedTransport{
|
||||
statusCode: 308,
|
||||
buf: make([]byte, 0, st.Size()),
|
||||
}
|
||||
oldChunkSize := chunkSize
|
||||
defer func() { chunkSize = oldChunkSize }()
|
||||
chunkSize = 100 // override to process small chunks for test.
|
||||
|
||||
sleep = func(time.Duration) {} // override time.Sleep
|
||||
rx := &ResumableUpload{
|
||||
Client: &http.Client{Transport: tr},
|
||||
Media: f,
|
||||
MediaType: "text/plain",
|
||||
ContentLength: st.Size(),
|
||||
Callback: tr.ProgressUpdate,
|
||||
}
|
||||
res, err := rx.Upload(context.Background())
|
||||
if err != nil || res == nil || res.StatusCode != http.StatusOK {
|
||||
if res == nil {
|
||||
t.Errorf("transferChunks not successful, res=nil: %v", err)
|
||||
} else {
|
||||
t.Errorf("transferChunks not successful, statusCode=%v: %v", res.StatusCode, err)
|
||||
}
|
||||
}
|
||||
if len(tr.buf) != len(slurp) || bytes.Compare(tr.buf, slurp) != 0 {
|
||||
t.Errorf("transfered file corrupted:\ngot %s\nwant %s", tr.buf, slurp)
|
||||
}
|
||||
w := ""
|
||||
for i := chunkSize; i <= st.Size(); i += chunkSize {
|
||||
w += fmt.Sprintf("%v, %v\n", i, st.Size())
|
||||
}
|
||||
if st.Size()%chunkSize != 0 {
|
||||
w += fmt.Sprintf("%v, %v\n", st.Size(), st.Size())
|
||||
}
|
||||
if tr.progressBuf != w {
|
||||
t.Errorf("progress update error, got %v, want %v", tr.progressBuf, w)
|
||||
}
|
||||
}
|
||||
|
||||
func TestCancelUpload(t *testing.T) {
|
||||
f, err := os.Open("googleapi.go")
|
||||
if err != nil {
|
||||
t.Fatalf("unable to open googleapi.go: %v", err)
|
||||
}
|
||||
defer f.Close()
|
||||
st, err := f.Stat()
|
||||
if err != nil {
|
||||
t.Fatalf("unable to stat googleapi.go: %v", err)
|
||||
}
|
||||
tr := &interruptedTransport{
|
||||
statusCode: 308,
|
||||
buf: make([]byte, 0, st.Size()),
|
||||
}
|
||||
oldChunkSize := chunkSize
|
||||
defer func() { chunkSize = oldChunkSize }()
|
||||
chunkSize = 100 // override to process small chunks for test.
|
||||
|
||||
sleep = func(time.Duration) {} // override time.Sleep
|
||||
rx := &ResumableUpload{
|
||||
Client: &http.Client{Transport: tr},
|
||||
Media: f,
|
||||
MediaType: "text/plain",
|
||||
ContentLength: st.Size(),
|
||||
Callback: tr.ProgressUpdate,
|
||||
}
|
||||
ctx, cancelFunc := context.WithCancel(context.Background())
|
||||
cancelFunc() // stop the upload that hasn't started yet
|
||||
res, err := rx.Upload(ctx)
|
||||
if err == nil || res == nil || res.StatusCode != http.StatusRequestTimeout {
|
||||
if res == nil {
|
||||
t.Errorf("transferChunks not successful, got res=nil, err=%v, want StatusRequestTimeout", err)
|
||||
} else {
|
||||
t.Errorf("transferChunks not successful, got statusCode=%v, err=%v, want StatusRequestTimeout", res.StatusCode, err)
|
||||
}
|
||||
}
|
||||
}
|
|
@ -21,13 +21,13 @@ import (
|
|||
"strings"
|
||||
"time"
|
||||
|
||||
"code.google.com/p/go-uuid/uuid"
|
||||
"github.com/GoogleCloudPlatform/kubernetes/contrib/mesos/pkg/offers"
|
||||
annotation "github.com/GoogleCloudPlatform/kubernetes/contrib/mesos/pkg/scheduler/meta"
|
||||
"github.com/GoogleCloudPlatform/kubernetes/contrib/mesos/pkg/scheduler/metrics"
|
||||
mresource "github.com/GoogleCloudPlatform/kubernetes/contrib/mesos/pkg/scheduler/resource"
|
||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/api"
|
||||
"github.com/gogo/protobuf/proto"
|
||||
"github.com/pborman/uuid"
|
||||
|
||||
log "github.com/golang/glog"
|
||||
mesos "github.com/mesos/mesos-go/mesosproto"
|
||||
|
|
|
@ -21,8 +21,8 @@ import (
|
|||
"strconv"
|
||||
"strings"
|
||||
|
||||
"code.google.com/p/go-uuid/uuid"
|
||||
log "github.com/golang/glog"
|
||||
"github.com/pborman/uuid"
|
||||
)
|
||||
|
||||
type UID struct {
|
||||
|
|
|
@ -34,12 +34,12 @@ import (
|
|||
"github.com/GoogleCloudPlatform/kubernetes/pkg/util/wait"
|
||||
|
||||
"code.google.com/p/gcfg"
|
||||
compute "code.google.com/p/google-api-go-client/compute/v1"
|
||||
container "code.google.com/p/google-api-go-client/container/v1beta1"
|
||||
"code.google.com/p/google-api-go-client/googleapi"
|
||||
"github.com/golang/glog"
|
||||
"golang.org/x/oauth2"
|
||||
"golang.org/x/oauth2/google"
|
||||
compute "google.golang.org/api/compute/v1"
|
||||
container "google.golang.org/api/container/v1beta1"
|
||||
"google.golang.org/api/googleapi"
|
||||
"google.golang.org/cloud/compute/metadata"
|
||||
)
|
||||
|
||||
|
|
|
@ -23,10 +23,10 @@ import (
|
|||
|
||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/util"
|
||||
|
||||
"code.google.com/p/google-api-go-client/googleapi"
|
||||
"github.com/prometheus/client_golang/prometheus"
|
||||
"golang.org/x/oauth2"
|
||||
"golang.org/x/oauth2/google"
|
||||
"google.golang.org/api/googleapi"
|
||||
)
|
||||
|
||||
const (
|
||||
|
|
|
@ -20,8 +20,8 @@ import (
|
|||
"sync"
|
||||
"time"
|
||||
|
||||
"code.google.com/p/go-uuid/uuid"
|
||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/types"
|
||||
"github.com/pborman/uuid"
|
||||
)
|
||||
|
||||
var uuidLock sync.Mutex
|
||||
|
|
Loading…
Reference in New Issue