1
0
mirror of https://github.com/rancher/os.git synced 2025-09-09 10:40:30 +00:00

Godep updates

google.golang.org/cloud
github.com/fsouza/go-dockerclient
golang.org/x/net/context
This commit is contained in:
Darren Shepherd
2015-04-10 09:09:47 -07:00
parent 2a69c5f38e
commit 15bd54a841
16 changed files with 3811 additions and 4 deletions

View File

@@ -0,0 +1,37 @@
// Copyright 2015 Google Inc. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
// +build go1.3
package metadata
import (
"net"
"time"
)
// This is a workaround for https://github.com/golang/oauth2/issues/70, where
// net.Dialer.KeepAlive is unavailable on Go 1.2 (which App Engine as of
// Jan 2015 still runs).
//
// TODO(bradfitz,jbd,adg): remove this once App Engine supports Go
// 1.3+.
func init() {
go13Dialer = func() *net.Dialer {
return &net.Dialer{
Timeout: 750 * time.Millisecond,
KeepAlive: 30 * time.Second,
}
}
}

View File

@@ -0,0 +1,267 @@
// Copyright 2014 Google Inc. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
// Package metadata provides access to Google Compute Engine (GCE)
// metadata and API service accounts.
//
// This package is a wrapper around the GCE metadata service,
// as documented at https://developers.google.com/compute/docs/metadata.
package metadata
import (
"encoding/json"
"fmt"
"io/ioutil"
"net"
"net/http"
"strings"
"sync"
"time"
"google.golang.org/cloud/internal"
)
type cachedValue struct {
k string
trim bool
mu sync.Mutex
v string
}
var (
projID = &cachedValue{k: "project/project-id", trim: true}
projNum = &cachedValue{k: "project/numeric-project-id", trim: true}
instID = &cachedValue{k: "instance/id", trim: true}
)
var metaClient = &http.Client{
Transport: &internal.Transport{
Base: &http.Transport{
Dial: dialer().Dial,
ResponseHeaderTimeout: 750 * time.Millisecond,
},
},
}
// go13Dialer is nil until we're using Go 1.3+.
// This is a workaround for https://github.com/golang/oauth2/issues/70, where
// net.Dialer.KeepAlive is unavailable on Go 1.2 (which App Engine as of
// Jan 2015 still runs).
//
// TODO(bradfitz,jbd,adg,dsymonds): remove this once App Engine supports Go
// 1.3+ and go-app-builder also supports 1.3+, or when Go 1.2 is no longer an
// option on App Engine.
var go13Dialer func() *net.Dialer
func dialer() *net.Dialer {
if fn := go13Dialer; fn != nil {
return fn()
}
return &net.Dialer{
Timeout: 750 * time.Millisecond,
}
}
// NotDefinedError is returned when requested metadata is not defined.
//
// The underlying string is the suffix after "/computeMetadata/v1/".
//
// This error is not returned if the value is defined to be the empty
// string.
type NotDefinedError string
func (suffix NotDefinedError) Error() string {
return fmt.Sprintf("metadata: GCE metadata %q not defined", string(suffix))
}
// Get returns a value from the metadata service.
// The suffix is appended to "http://metadata/computeMetadata/v1/".
//
// If the requested metadata is not defined, the returned error will
// be of type NotDefinedError.
func Get(suffix string) (string, error) {
// Using 169.254.169.254 instead of "metadata" here because Go
// binaries built with the "netgo" tag and without cgo won't
// know the search suffix for "metadata" is
// ".google.internal", and this IP address is documented as
// being stable anyway.
url := "http://169.254.169.254/computeMetadata/v1/" + suffix
req, _ := http.NewRequest("GET", url, nil)
req.Header.Set("Metadata-Flavor", "Google")
res, err := metaClient.Do(req)
if err != nil {
return "", err
}
defer res.Body.Close()
if res.StatusCode == http.StatusNotFound {
return "", NotDefinedError(suffix)
}
if res.StatusCode != 200 {
return "", fmt.Errorf("status code %d trying to fetch %s", res.StatusCode, url)
}
all, err := ioutil.ReadAll(res.Body)
if err != nil {
return "", err
}
return string(all), nil
}
func getTrimmed(suffix string) (s string, err error) {
s, err = Get(suffix)
s = strings.TrimSpace(s)
return
}
func (c *cachedValue) get() (v string, err error) {
defer c.mu.Unlock()
c.mu.Lock()
if c.v != "" {
return c.v, nil
}
if c.trim {
v, err = getTrimmed(c.k)
} else {
v, err = Get(c.k)
}
if err == nil {
c.v = v
}
return
}
var onGCE struct {
sync.Mutex
set bool
v bool
}
// OnGCE reports whether this process is running on Google Compute Engine.
func OnGCE() bool {
defer onGCE.Unlock()
onGCE.Lock()
if onGCE.set {
return onGCE.v
}
onGCE.set = true
// We use the DNS name of the metadata service here instead of the IP address
// because we expect that to fail faster in the not-on-GCE case.
res, err := metaClient.Get("http://metadata.google.internal")
if err != nil {
return false
}
onGCE.v = res.Header.Get("Metadata-Flavor") == "Google"
return onGCE.v
}
// ProjectID returns the current instance's project ID string.
func ProjectID() (string, error) { return projID.get() }
// NumericProjectID returns the current instance's numeric project ID.
func NumericProjectID() (string, error) { return projNum.get() }
// InternalIP returns the instance's primary internal IP address.
func InternalIP() (string, error) {
return getTrimmed("instance/network-interfaces/0/ip")
}
// ExternalIP returns the instance's primary external (public) IP address.
func ExternalIP() (string, error) {
return getTrimmed("instance/network-interfaces/0/access-configs/0/external-ip")
}
// Hostname returns the instance's hostname. This will probably be of
// the form "INSTANCENAME.c.PROJECT.internal" but that isn't
// guaranteed.
//
// TODO: what is this defined to be? Docs say "The host name of the
// instance."
func Hostname() (string, error) {
return getTrimmed("network-interfaces/0/ip")
}
// InstanceTags returns the list of user-defined instance tags,
// assigned when initially creating a GCE instance.
func InstanceTags() ([]string, error) {
var s []string
j, err := Get("instance/tags")
if err != nil {
return nil, err
}
if err := json.NewDecoder(strings.NewReader(j)).Decode(&s); err != nil {
return nil, err
}
return s, nil
}
// InstanceID returns the current VM's numeric instance ID.
func InstanceID() (string, error) {
return instID.get()
}
// InstanceAttributes returns the list of user-defined attributes,
// assigned when initially creating a GCE VM instance. The value of an
// attribute can be obtained with InstanceAttributeValue.
func InstanceAttributes() ([]string, error) { return lines("instance/attributes/") }
// ProjectAttributes returns the list of user-defined attributes
// applying to the project as a whole, not just this VM. The value of
// an attribute can be obtained with ProjectAttributeValue.
func ProjectAttributes() ([]string, error) { return lines("project/attributes/") }
func lines(suffix string) ([]string, error) {
j, err := Get(suffix)
if err != nil {
return nil, err
}
s := strings.Split(strings.TrimSpace(j), "\n")
for i := range s {
s[i] = strings.TrimSpace(s[i])
}
return s, nil
}
// InstanceAttributeValue returns the value of the provided VM
// instance attribute.
//
// If the requested attribute is not defined, the returned error will
// be of type NotDefinedError.
//
// InstanceAttributeValue may return ("", nil) if the attribute was
// defined to be the empty string.
func InstanceAttributeValue(attr string) (string, error) {
return Get("instance/attributes/" + attr)
}
// ProjectAttributeValue returns the value of the provided
// project attribute.
//
// If the requested attribute is not defined, the returned error will
// be of type NotDefinedError.
//
// ProjectAttributeValue may return ("", nil) if the attribute was
// defined to be the empty string.
func ProjectAttributeValue(attr string) (string, error) {
return Get("project/attributes/" + attr)
}
// Scopes returns the service account scopes for the given account.
// The account may be empty or the string "default" to use the instance's
// main account.
func Scopes(serviceAccount string) ([]string, error) {
if serviceAccount == "" {
serviceAccount = "default"
}
return lines("instance/service-accounts/" + serviceAccount + "/scopes")
}

View File

@@ -0,0 +1,128 @@
// Copyright 2014 Google Inc. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
// Package internal provides support for the cloud packages.
//
// Users should not import this package directly.
package internal
import (
"fmt"
"net/http"
"sync"
"golang.org/x/net/context"
)
type contextKey struct{}
func WithContext(parent context.Context, projID string, c *http.Client) context.Context {
if c == nil {
panic("nil *http.Client passed to WithContext")
}
if projID == "" {
panic("empty project ID passed to WithContext")
}
return context.WithValue(parent, contextKey{}, &cloudContext{
ProjectID: projID,
HTTPClient: c,
})
}
const userAgent = "gcloud-golang/0.1"
type cloudContext struct {
ProjectID string
HTTPClient *http.Client
mu sync.Mutex // guards svc
svc map[string]interface{} // e.g. "storage" => *rawStorage.Service
}
// Service returns the result of the fill function if it's never been
// called before for the given name (which is assumed to be an API
// service name, like "datastore"). If it has already been cached, the fill
// func is not run.
// It's safe for concurrent use by multiple goroutines.
func Service(ctx context.Context, name string, fill func(*http.Client) interface{}) interface{} {
return cc(ctx).service(name, fill)
}
func (c *cloudContext) service(name string, fill func(*http.Client) interface{}) interface{} {
c.mu.Lock()
defer c.mu.Unlock()
if c.svc == nil {
c.svc = make(map[string]interface{})
} else if v, ok := c.svc[name]; ok {
return v
}
v := fill(c.HTTPClient)
c.svc[name] = v
return v
}
// Transport is an http.RoundTripper that appends
// Google Cloud client's user-agent to the original
// request's user-agent header.
type Transport struct {
// Base represents the actual http.RoundTripper
// the requests will be delegated to.
Base http.RoundTripper
}
// RoundTrip appends a user-agent to the existing user-agent
// header and delegates the request to the base http.RoundTripper.
func (t *Transport) RoundTrip(req *http.Request) (*http.Response, error) {
req = cloneRequest(req)
ua := req.Header.Get("User-Agent")
if ua == "" {
ua = userAgent
} else {
ua = fmt.Sprintf("%s %s", ua, userAgent)
}
req.Header.Set("User-Agent", ua)
return t.Base.RoundTrip(req)
}
// cloneRequest returns a clone of the provided *http.Request.
// The clone is a shallow copy of the struct and its Header map.
func cloneRequest(r *http.Request) *http.Request {
// shallow copy of the struct
r2 := new(http.Request)
*r2 = *r
// deep copy of the Header
r2.Header = make(http.Header)
for k, s := range r.Header {
r2.Header[k] = s
}
return r2
}
func ProjID(ctx context.Context) string {
return cc(ctx).ProjectID
}
func HTTPClient(ctx context.Context) *http.Client {
return cc(ctx).HTTPClient
}
// cc returns the internal *cloudContext (cc) state for a context.Context.
// It panics if the user did it wrong.
func cc(ctx context.Context) *cloudContext {
if c, ok := ctx.Value(contextKey{}).(*cloudContext); ok {
return c
}
panic("invalid context.Context type; it should be created with cloud.NewContext")
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,594 @@
// Copyright 2013 Google Inc. All Rights Reserved.
//
// The datastore v1 service proto definitions
syntax = "proto2";
package datastore;
option java_package = "com.google.api.services.datastore";
// An identifier for a particular subset of entities.
//
// Entities are partitioned into various subsets, each used by different
// datasets and different namespaces within a dataset and so forth.
//
// All input partition IDs are normalized before use.
// A partition ID is normalized as follows:
// If the partition ID is unset or is set to an empty partition ID, replace it
// with the context partition ID.
// Otherwise, if the partition ID has no dataset ID, assign it the context
// partition ID's dataset ID.
// Unless otherwise documented, the context partition ID has the dataset ID set
// to the context dataset ID and no other partition dimension set.
//
// A partition ID is empty if all of its fields are unset.
//
// Partition dimension:
// A dimension may be unset.
// A dimension's value must never be "".
// A dimension's value must match [A-Za-z\d\.\-_]{1,100}
// If the value of any dimension matches regex "__.*__",
// the partition is reserved/read-only.
// A reserved/read-only partition ID is forbidden in certain documented contexts.
//
// Dataset ID:
// A dataset id's value must never be "".
// A dataset id's value must match
// ([a-z\d\-]{1,100}~)?([a-z\d][a-z\d\-\.]{0,99}:)?([a-z\d][a-z\d\-]{0,99}
message PartitionId {
// The dataset ID.
optional string dataset_id = 3;
// The namespace.
optional string namespace = 4;
}
// A unique identifier for an entity.
// If a key's partition id or any of its path kinds or names are
// reserved/read-only, the key is reserved/read-only.
// A reserved/read-only key is forbidden in certain documented contexts.
message Key {
// Entities are partitioned into subsets, currently identified by a dataset
// (usually implicitly specified by the project) and namespace ID.
// Queries are scoped to a single partition.
optional PartitionId partition_id = 1;
// A (kind, ID/name) pair used to construct a key path.
//
// At most one of name or ID may be set.
// If either is set, the element is complete.
// If neither is set, the element is incomplete.
message PathElement {
// The kind of the entity.
// A kind matching regex "__.*__" is reserved/read-only.
// A kind must not contain more than 500 characters.
// Cannot be "".
required string kind = 1;
// The ID of the entity.
// Never equal to zero. Values less than zero are discouraged and will not
// be supported in the future.
optional int64 id = 2;
// The name of the entity.
// A name matching regex "__.*__" is reserved/read-only.
// A name must not be more than 500 characters.
// Cannot be "".
optional string name = 3;
}
// The entity path.
// An entity path consists of one or more elements composed of a kind and a
// string or numerical identifier, which identify entities. The first
// element identifies a <em>root entity</em>, the second element identifies
// a <em>child</em> of the root entity, the third element a child of the
// second entity, and so forth. The entities identified by all prefixes of
// the path are called the element's <em>ancestors</em>.
// An entity path is always fully complete: ALL of the entity's ancestors
// are required to be in the path along with the entity identifier itself.
// The only exception is that in some documented cases, the identifier in the
// last path element (for the entity) itself may be omitted. A path can never
// be empty.
repeated PathElement path_element = 2;
}
// A message that can hold any of the supported value types and associated
// metadata.
//
// At most one of the <type>Value fields may be set.
// If none are set the value is "null".
//
message Value {
// A boolean value.
optional bool boolean_value = 1;
// An integer value.
optional int64 integer_value = 2;
// A double value.
optional double double_value = 3;
// A timestamp value.
optional int64 timestamp_microseconds_value = 4;
// A key value.
optional Key key_value = 5;
// A blob key value.
optional string blob_key_value = 16;
// A UTF-8 encoded string value.
optional string string_value = 17;
// A blob value.
optional bytes blob_value = 18;
// An entity value.
// May have no key.
// May have a key with an incomplete key path.
// May have a reserved/read-only key.
optional Entity entity_value = 6;
// A list value.
// Cannot contain another list value.
// Cannot also have a meaning and indexing set.
repeated Value list_value = 7;
// The <code>meaning</code> field is reserved and should not be used.
optional int32 meaning = 14;
// If the value should be indexed.
//
// The <code>indexed</code> property may be set for a
// <code>null</code> value.
// When <code>indexed</code> is <code>true</code>, <code>stringValue</code>
// is limited to 500 characters and the blob value is limited to 500 bytes.
// Exception: If meaning is set to 2, string_value is limited to 2038
// characters regardless of indexed.
// When indexed is true, meaning 15 and 22 are not allowed, and meaning 16
// will be ignored on input (and will never be set on output).
// Input values by default have <code>indexed</code> set to
// <code>true</code>; however, you can explicitly set <code>indexed</code> to
// <code>true</code> if you want. (An output value never has
// <code>indexed</code> explicitly set to <code>true</code>.) If a value is
// itself an entity, it cannot have <code>indexed</code> set to
// <code>true</code>.
// Exception: An entity value with meaning 9, 20 or 21 may be indexed.
optional bool indexed = 15 [default = true];
}
// An entity property.
message Property {
// The name of the property.
// A property name matching regex "__.*__" is reserved.
// A reserved property name is forbidden in certain documented contexts.
// The name must not contain more than 500 characters.
// Cannot be "".
required string name = 1;
// The value(s) of the property.
// Each value can have only one value property populated. For example,
// you cannot have a values list of <code>{ value: { integerValue: 22,
// stringValue: "a" } }</code>, but you can have <code>{ value: { listValue:
// [ { integerValue: 22 }, { stringValue: "a" } ] }</code>.
required Value value = 4;
}
// An entity.
//
// An entity is limited to 1 megabyte when stored. That <em>roughly</em>
// corresponds to a limit of 1 megabyte for the serialized form of this
// message.
message Entity {
// The entity's key.
//
// An entity must have a key, unless otherwise documented (for example,
// an entity in <code>Value.entityValue</code> may have no key).
// An entity's kind is its key's path's last element's kind,
// or null if it has no key.
optional Key key = 1;
// The entity's properties.
// Each property's name must be unique for its entity.
repeated Property property = 2;
}
// The result of fetching an entity from the datastore.
message EntityResult {
// Specifies what data the 'entity' field contains.
// A ResultType is either implied (for example, in LookupResponse.found it
// is always FULL) or specified by context (for example, in message
// QueryResultBatch, field 'entity_result_type' specifies a ResultType
// for all the values in field 'entity_result').
enum ResultType {
FULL = 1; // The entire entity.
PROJECTION = 2; // A projected subset of properties.
// The entity may have no key.
// A property value may have meaning 18.
KEY_ONLY = 3; // Only the key.
}
// The resulting entity.
required Entity entity = 1;
}
// A query.
message Query {
// The projection to return. If not set the entire entity is returned.
repeated PropertyExpression projection = 2;
// The kinds to query (if empty, returns entities from all kinds).
repeated KindExpression kind = 3;
// The filter to apply (optional).
optional Filter filter = 4;
// The order to apply to the query results (if empty, order is unspecified).
repeated PropertyOrder order = 5;
// The properties to group by (if empty, no grouping is applied to the
// result set).
repeated PropertyReference group_by = 6;
// A starting point for the query results. Optional. Query cursors are
// returned in query result batches.
optional bytes /* serialized QueryCursor */ start_cursor = 7;
// An ending point for the query results. Optional. Query cursors are
// returned in query result batches.
optional bytes /* serialized QueryCursor */ end_cursor = 8;
// The number of results to skip. Applies before limit, but after all other
// constraints (optional, defaults to 0).
optional int32 offset = 10 [default=0];
// The maximum number of results to return. Applies after all other
// constraints. Optional.
optional int32 limit = 11;
}
// A representation of a kind.
message KindExpression {
// The name of the kind.
required string name = 1;
}
// A reference to a property relative to the kind expressions.
// exactly.
message PropertyReference {
// The name of the property.
required string name = 2;
}
// A representation of a property in a projection.
message PropertyExpression {
enum AggregationFunction {
FIRST = 1;
}
// The property to project.
required PropertyReference property = 1;
// The aggregation function to apply to the property. Optional.
// Can only be used when grouping by at least one property. Must
// then be set on all properties in the projection that are not
// being grouped by.
optional AggregationFunction aggregation_function = 2;
}
// The desired order for a specific property.
message PropertyOrder {
enum Direction {
ASCENDING = 1;
DESCENDING = 2;
}
// The property to order by.
required PropertyReference property = 1;
// The direction to order by.
optional Direction direction = 2 [default=ASCENDING];
}
// A holder for any type of filter. Exactly one field should be specified.
message Filter {
// A composite filter.
optional CompositeFilter composite_filter = 1;
// A filter on a property.
optional PropertyFilter property_filter = 2;
}
// A filter that merges the multiple other filters using the given operation.
message CompositeFilter {
enum Operator {
AND = 1;
}
// The operator for combining multiple filters.
required Operator operator = 1;
// The list of filters to combine.
// Must contain at least one filter.
repeated Filter filter = 2;
}
// A filter on a specific property.
message PropertyFilter {
enum Operator {
LESS_THAN = 1;
LESS_THAN_OR_EQUAL = 2;
GREATER_THAN = 3;
GREATER_THAN_OR_EQUAL = 4;
EQUAL = 5;
HAS_ANCESTOR = 11;
}
// The property to filter by.
required PropertyReference property = 1;
// The operator to filter by.
required Operator operator = 2;
// The value to compare the property to.
required Value value = 3;
}
// A GQL query.
message GqlQuery {
required string query_string = 1;
// When false, the query string must not contain a literal.
optional bool allow_literal = 2 [default = false];
// A named argument must set field GqlQueryArg.name.
// No two named arguments may have the same name.
// For each non-reserved named binding site in the query string,
// there must be a named argument with that name,
// but not necessarily the inverse.
repeated GqlQueryArg name_arg = 3;
// Numbered binding site @1 references the first numbered argument,
// effectively using 1-based indexing, rather than the usual 0.
// A numbered argument must NOT set field GqlQueryArg.name.
// For each binding site numbered i in query_string,
// there must be an ith numbered argument.
// The inverse must also be true.
repeated GqlQueryArg number_arg = 4;
}
// A binding argument for a GQL query.
// Exactly one of fields value and cursor must be set.
message GqlQueryArg {
// Must match regex "[A-Za-z_$][A-Za-z_$0-9]*".
// Must not match regex "__.*__".
// Must not be "".
optional string name = 1;
optional Value value = 2;
optional bytes cursor = 3;
}
// A batch of results produced by a query.
message QueryResultBatch {
// The possible values for the 'more_results' field.
enum MoreResultsType {
NOT_FINISHED = 1; // There are additional batches to fetch from this query.
MORE_RESULTS_AFTER_LIMIT = 2; // The query is finished, but there are more
// results after the limit.
NO_MORE_RESULTS = 3; // The query has been exhausted.
}
// The result type for every entity in entityResults.
required EntityResult.ResultType entity_result_type = 1;
// The results for this batch.
repeated EntityResult entity_result = 2;
// A cursor that points to the position after the last result in the batch.
// May be absent.
optional bytes /* serialized QueryCursor */ end_cursor = 4;
// The state of the query after the current batch.
required MoreResultsType more_results = 5;
// The number of results skipped because of <code>Query.offset</code>.
optional int32 skipped_results = 6;
}
// A set of changes to apply.
//
// No entity in this message may have a reserved property name,
// not even a property in an entity in a value.
// No value in this message may have meaning 18,
// not even a value in an entity in another value.
//
// If entities with duplicate keys are present, an arbitrary choice will
// be made as to which is written.
message Mutation {
// Entities to upsert.
// Each upserted entity's key must have a complete path and
// must not be reserved/read-only.
repeated Entity upsert = 1;
// Entities to update.
// Each updated entity's key must have a complete path and
// must not be reserved/read-only.
repeated Entity update = 2;
// Entities to insert.
// Each inserted entity's key must have a complete path and
// must not be reserved/read-only.
repeated Entity insert = 3;
// Insert entities with a newly allocated ID.
// Each inserted entity's key must omit the final identifier in its path and
// must not be reserved/read-only.
repeated Entity insert_auto_id = 4;
// Keys of entities to delete.
// Each key must have a complete key path and must not be reserved/read-only.
repeated Key delete = 5;
// Ignore a user specified read-only period. Optional.
optional bool force = 6;
}
// The result of applying a mutation.
message MutationResult {
// Number of index writes.
required int32 index_updates = 1;
// Keys for <code>insertAutoId</code> entities. One per entity from the
// request, in the same order.
repeated Key insert_auto_id_key = 2;
}
// Options shared by read requests.
message ReadOptions {
enum ReadConsistency {
DEFAULT = 0;
STRONG = 1;
EVENTUAL = 2;
}
// The read consistency to use.
// Cannot be set when transaction is set.
// Lookup and ancestor queries default to STRONG, global queries default to
// EVENTUAL and cannot be set to STRONG.
optional ReadConsistency read_consistency = 1 [default=DEFAULT];
// The transaction to use. Optional.
optional bytes /* serialized Transaction */ transaction = 2;
}
// The request for Lookup.
message LookupRequest {
// Options for this lookup request. Optional.
optional ReadOptions read_options = 1;
// Keys of entities to look up from the datastore.
repeated Key key = 3;
}
// The response for Lookup.
message LookupResponse {
// The order of results in these fields is undefined and has no relation to
// the order of the keys in the input.
// Entities found as ResultType.FULL entities.
repeated EntityResult found = 1;
// Entities not found as ResultType.KEY_ONLY entities.
repeated EntityResult missing = 2;
// A list of keys that were not looked up due to resource constraints.
repeated Key deferred = 3;
}
// The request for RunQuery.
message RunQueryRequest {
// The options for this query.
optional ReadOptions read_options = 1;
// Entities are partitioned into subsets, identified by a dataset (usually
// implicitly specified by the project) and namespace ID. Queries are scoped
// to a single partition.
// This partition ID is normalized with the standard default context
// partition ID, but all other partition IDs in RunQueryRequest are
// normalized with this partition ID as the context partition ID.
optional PartitionId partition_id = 2;
// The query to run.
// Either this field or field gql_query must be set, but not both.
optional Query query = 3;
// The GQL query to run.
// Either this field or field query must be set, but not both.
optional GqlQuery gql_query = 7;
}
// The response for RunQuery.
message RunQueryResponse {
// A batch of query results (always present).
optional QueryResultBatch batch = 1;
}
// The request for BeginTransaction.
message BeginTransactionRequest {
enum IsolationLevel {
SNAPSHOT = 0; // Read from a consistent snapshot. Concurrent transactions
// conflict if their mutations conflict. For example:
// Read(A),Write(B) may not conflict with Read(B),Write(A),
// but Read(B),Write(B) does conflict with Read(B),Write(B).
SERIALIZABLE = 1; // Read from a consistent snapshot. Concurrent
// transactions conflict if they cannot be serialized.
// For example Read(A),Write(B) does conflict with
// Read(B),Write(A) but Read(A) may not conflict with
// Write(A).
}
// The transaction isolation level.
optional IsolationLevel isolation_level = 1 [default=SNAPSHOT];
}
// The response for BeginTransaction.
message BeginTransactionResponse {
// The transaction identifier (always present).
optional bytes /* serialized Transaction */ transaction = 1;
}
// The request for Rollback.
message RollbackRequest {
// The transaction identifier, returned by a call to
// <code>beginTransaction</code>.
required bytes /* serialized Transaction */ transaction = 1;
}
// The response for Rollback.
message RollbackResponse {
// Empty
}
// The request for Commit.
message CommitRequest {
enum Mode {
TRANSACTIONAL = 1;
NON_TRANSACTIONAL = 2;
}
// The transaction identifier, returned by a call to
// <code>beginTransaction</code>. Must be set when mode is TRANSACTIONAL.
optional bytes /* serialized Transaction */ transaction = 1;
// The mutation to perform. Optional.
optional Mutation mutation = 2;
// The type of commit to perform. Either TRANSACTIONAL or NON_TRANSACTIONAL.
optional Mode mode = 5 [default=TRANSACTIONAL];
}
// The response for Commit.
message CommitResponse {
// The result of performing the mutation (if any).
optional MutationResult mutation_result = 1;
}
// The request for AllocateIds.
message AllocateIdsRequest {
// A list of keys with incomplete key paths to allocate IDs for.
// No key may be reserved/read-only.
repeated Key key = 1;
}
// The response for AllocateIds.
message AllocateIdsResponse {
// The keys specified in the request (in the same order), each with
// its key path completed with a newly allocated ID.
repeated Key key = 1;
}
// Each rpc normalizes the partition IDs of the keys in its input entities,
// and always returns entities with keys with normalized partition IDs.
// (Note that applies to all entities, including entities in values.)
service DatastoreService {
// Look up some entities by key.
rpc Lookup(LookupRequest) returns (LookupResponse) {
};
// Query for entities.
rpc RunQuery(RunQueryRequest) returns (RunQueryResponse) {
};
// Begin a new transaction.
rpc BeginTransaction(BeginTransactionRequest) returns (BeginTransactionResponse) {
};
// Commit a transaction, optionally creating, deleting or modifying some
// entities.
rpc Commit(CommitRequest) returns (CommitResponse) {
};
// Roll back a transaction.
rpc Rollback(RollbackRequest) returns (RollbackResponse) {
};
// Allocate IDs for incomplete keys (useful for referencing an entity before
// it is inserted).
rpc AllocateIds(AllocateIdsRequest) returns (AllocateIdsResponse) {
};
}

View File

@@ -0,0 +1,57 @@
// Copyright 2014 Google Inc. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
// Package testutil contains helper functions for writing tests.
package testutil
import (
"io/ioutil"
"log"
"net/http"
"os"
"golang.org/x/net/context"
"golang.org/x/oauth2"
"golang.org/x/oauth2/google"
"google.golang.org/cloud"
)
const (
envProjID = "GCLOUD_TESTS_GOLANG_PROJECT_ID"
envPrivateKey = "GCLOUD_TESTS_GOLANG_KEY"
)
func Context(scopes ...string) context.Context {
key, projID := os.Getenv(envPrivateKey), os.Getenv(envProjID)
if key == "" || projID == "" {
log.Fatal("GCLOUD_TESTS_GOLANG_KEY and GCLOUD_TESTS_GOLANG_PROJECT_ID must be set. See CONTRIBUTING.md for details.")
}
jsonKey, err := ioutil.ReadFile(key)
if err != nil {
log.Fatalf("Cannot read the JSON key file, err: %v", err)
}
conf, err := google.JWTConfigFromJSON(jsonKey, scopes...)
if err != nil {
log.Fatal(err)
}
return cloud.NewContext(projID, conf.Client(oauth2.NoContext))
}
func NoAuthContext() context.Context {
projID := os.Getenv(envProjID)
if projID == "" {
log.Fatal("GCLOUD_TESTS_GOLANG_PROJECT_ID must be set. See CONTRIBUTING.md for details.")
}
return cloud.NewContext(projID, &http.Client{Transport: http.DefaultTransport})
}