Merge pull request #36895 from dmcgowan/vendor-containerd-master

Update containerd to 1.1
This commit is contained in:
Sebastiaan van Stijn 2018-06-05 21:43:31 -07:00 committed by GitHub
commit fd2f2a919e
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
481 changed files with 41985 additions and 19231 deletions

View file

@ -4,7 +4,7 @@
# containerd is also pinned in vendor.conf. When updating the binary
# version you may also need to update the vendor version to pick up bug
# fixes or new APIs.
CONTAINERD_COMMIT=773c489c9c1b21a6d78b5c538cd395416ec50f88 # v1.0.3
CONTAINERD_COMMIT=395068d2b7256518259816ae19e45824b15da071 # v1.1.1-rc.0
install_containerd() {
echo "Install containerd version $CONTAINERD_COMMIT"

View file

@ -1,7 +1,7 @@
#!/bin/sh
# When updating RUNC_COMMIT, also update runc in vendor.conf accordingly
RUNC_COMMIT=4fc53a81fb7c994640722ac585fa9ca548971871
RUNC_COMMIT=69663f0bd4b60df09991c08812a60108003fa340
install_runc() {
# Do not build with ambient capabilities support

View file

@ -94,7 +94,7 @@ func testBuildWithSession(t *testing.T, client dclient.APIClient, daemonHost str
})
sess.Allow(fsProvider)
g, ctx := errgroup.WithContext(context.Background())
g, ctx := errgroup.WithContext(ctx)
g.Go(func() error {
return sess.Run(ctx, client.DialSession)

View file

@ -16,18 +16,17 @@ import (
"syscall"
"time"
"google.golang.org/grpc"
"google.golang.org/grpc/codes"
"google.golang.org/grpc/status"
"github.com/containerd/containerd"
"github.com/containerd/containerd/api/events"
eventsapi "github.com/containerd/containerd/api/services/events/v1"
apievents "github.com/containerd/containerd/api/events"
"github.com/containerd/containerd/api/types"
"github.com/containerd/containerd/archive"
"github.com/containerd/containerd/cio"
"github.com/containerd/containerd/content"
containerderrors "github.com/containerd/containerd/errdefs"
"github.com/containerd/containerd/events"
"github.com/containerd/containerd/images"
"github.com/containerd/containerd/linux/runctypes"
"github.com/containerd/typeurl"
@ -295,7 +294,8 @@ func (c *client) Start(ctx context.Context, id, checkpointDir string, withStdin
t, err = ctr.ctr.NewTask(ctx,
func(id string) (cio.IO, error) {
fifos := newFIFOSet(ctr.bundleDir, InitProcessName, withStdin, spec.Process.Terminal)
rio, err = c.createIO(fifos, id, InitProcessName, stdinCloseSync, attachStdio)
rio, err = c.createIO(fifos, id, InitProcessName, stdinCloseSync, attachStdio, spec.Process.Terminal)
return rio, err
},
func(_ context.Context, _ *containerd.Client, info *containerd.TaskInfo) error {
@ -366,7 +366,7 @@ func (c *client) Exec(ctx context.Context, containerID, processID string, spec *
}()
p, err = t.Exec(ctx, processID, spec, func(id string) (cio.IO, error) {
rio, err = c.createIO(fifos, containerID, processID, stdinCloseSync, attachStdio)
rio, err = c.createIO(fifos, containerID, processID, stdinCloseSync, attachStdio, spec.Terminal)
return rio, err
})
if err != nil {
@ -645,8 +645,16 @@ func (c *client) getProcess(containerID, processID string) (containerd.Process,
// createIO creates the io to be used by a process
// This needs to get a pointer to interface as upon closure the process may not have yet been registered
func (c *client) createIO(fifos *cio.FIFOSet, containerID, processID string, stdinCloseSync chan struct{}, attachStdio StdioCallback) (cio.IO, error) {
io, err := cio.NewDirectIO(context.Background(), fifos)
func (c *client) createIO(fifos *cio.FIFOSet, containerID, processID string, stdinCloseSync chan struct{}, attachStdio StdioCallback, terminal bool) (cio.IO, error) {
var (
io *cio.DirectIO
err error
)
if terminal {
io, err = cio.NewDirectIOWithTerminal(context.Background(), fifos)
} else {
io, err = cio.NewDirectIO(context.Background(), fifos)
}
if err != nil {
return nil, err
}
@ -729,137 +737,123 @@ func (c *client) processEvent(ctr *container, et EventType, ei EventInfo) {
func (c *client) processEventStream(ctx context.Context) {
var (
err error
eventStream eventsapi.Events_SubscribeClient
ev *eventsapi.Envelope
et EventType
ei EventInfo
ctr *container
err error
ev *events.Envelope
et EventType
ei EventInfo
ctr *container
)
defer func() {
if err != nil {
select {
case <-ctx.Done():
c.logger.WithError(ctx.Err()).
Info("stopping event stream following graceful shutdown")
default:
go c.processEventStream(ctx)
}
}
}()
eventStream, err = c.getRemote().EventService().Subscribe(ctx, &eventsapi.SubscribeRequest{
Filters: []string{
// Filter on both namespace *and* topic. To create an "and" filter,
// this must be a single, comma-separated string
"namespace==" + c.namespace + ",topic~=|^/tasks/|",
},
}, grpc.FailFast(false))
if err != nil {
return
}
// Filter on both namespace *and* topic. To create an "and" filter,
// this must be a single, comma-separated string
eventStream, errC := c.getRemote().EventService().Subscribe(ctx, "namespace=="+c.namespace+",topic~=|^/tasks/|")
c.logger.WithField("namespace", c.namespace).Debug("processing event stream")
var oomKilled bool
for {
ev, err = eventStream.Recv()
if err != nil {
errStatus, ok := status.FromError(err)
if !ok || errStatus.Code() != codes.Canceled {
c.logger.WithError(err).Error("failed to get event")
select {
case err = <-errC:
if err != nil {
errStatus, ok := status.FromError(err)
if !ok || errStatus.Code() != codes.Canceled {
c.logger.WithError(err).Error("failed to get event")
go c.processEventStream(ctx)
} else {
c.logger.WithError(ctx.Err()).Info("stopping event stream following graceful shutdown")
}
}
return
case ev = <-eventStream:
if ev.Event == nil {
c.logger.WithField("event", ev).Warn("invalid event")
continue
}
v, err := typeurl.UnmarshalAny(ev.Event)
if err != nil {
c.logger.WithError(err).WithField("event", ev).Warn("failed to unmarshal event")
continue
}
c.logger.WithField("topic", ev.Topic).Debug("event")
switch t := v.(type) {
case *apievents.TaskCreate:
et = EventCreate
ei = EventInfo{
ContainerID: t.ContainerID,
ProcessID: t.ContainerID,
Pid: t.Pid,
}
case *apievents.TaskStart:
et = EventStart
ei = EventInfo{
ContainerID: t.ContainerID,
ProcessID: t.ContainerID,
Pid: t.Pid,
}
case *apievents.TaskExit:
et = EventExit
ei = EventInfo{
ContainerID: t.ContainerID,
ProcessID: t.ID,
Pid: t.Pid,
ExitCode: t.ExitStatus,
ExitedAt: t.ExitedAt,
}
case *apievents.TaskOOM:
et = EventOOM
ei = EventInfo{
ContainerID: t.ContainerID,
OOMKilled: true,
}
oomKilled = true
case *apievents.TaskExecAdded:
et = EventExecAdded
ei = EventInfo{
ContainerID: t.ContainerID,
ProcessID: t.ExecID,
}
case *apievents.TaskExecStarted:
et = EventExecStarted
ei = EventInfo{
ContainerID: t.ContainerID,
ProcessID: t.ExecID,
Pid: t.Pid,
}
case *apievents.TaskPaused:
et = EventPaused
ei = EventInfo{
ContainerID: t.ContainerID,
}
case *apievents.TaskResumed:
et = EventResumed
ei = EventInfo{
ContainerID: t.ContainerID,
}
default:
c.logger.WithFields(logrus.Fields{
"topic": ev.Topic,
"type": reflect.TypeOf(t)},
).Info("ignoring event")
continue
}
ctr = c.getContainer(ei.ContainerID)
if ctr == nil {
c.logger.WithField("container", ei.ContainerID).Warn("unknown container")
continue
}
if oomKilled {
ctr.setOOMKilled(true)
oomKilled = false
}
ei.OOMKilled = ctr.getOOMKilled()
c.processEvent(ctr, et, ei)
}
if ev.Event == nil {
c.logger.WithField("event", ev).Warn("invalid event")
continue
}
v, err := typeurl.UnmarshalAny(ev.Event)
if err != nil {
c.logger.WithError(err).WithField("event", ev).Warn("failed to unmarshal event")
continue
}
c.logger.WithField("topic", ev.Topic).Debug("event")
switch t := v.(type) {
case *events.TaskCreate:
et = EventCreate
ei = EventInfo{
ContainerID: t.ContainerID,
ProcessID: t.ContainerID,
Pid: t.Pid,
}
case *events.TaskStart:
et = EventStart
ei = EventInfo{
ContainerID: t.ContainerID,
ProcessID: t.ContainerID,
Pid: t.Pid,
}
case *events.TaskExit:
et = EventExit
ei = EventInfo{
ContainerID: t.ContainerID,
ProcessID: t.ID,
Pid: t.Pid,
ExitCode: t.ExitStatus,
ExitedAt: t.ExitedAt,
}
case *events.TaskOOM:
et = EventOOM
ei = EventInfo{
ContainerID: t.ContainerID,
OOMKilled: true,
}
oomKilled = true
case *events.TaskExecAdded:
et = EventExecAdded
ei = EventInfo{
ContainerID: t.ContainerID,
ProcessID: t.ExecID,
}
case *events.TaskExecStarted:
et = EventExecStarted
ei = EventInfo{
ContainerID: t.ContainerID,
ProcessID: t.ExecID,
Pid: t.Pid,
}
case *events.TaskPaused:
et = EventPaused
ei = EventInfo{
ContainerID: t.ContainerID,
}
case *events.TaskResumed:
et = EventResumed
ei = EventInfo{
ContainerID: t.ContainerID,
}
default:
c.logger.WithFields(logrus.Fields{
"topic": ev.Topic,
"type": reflect.TypeOf(t)},
).Info("ignoring event")
continue
}
ctr = c.getContainer(ei.ContainerID)
if ctr == nil {
c.logger.WithField("container", ei.ContainerID).Warn("unknown container")
continue
}
if oomKilled {
ctr.setOOMKilled(true)
oomKilled = false
}
ei.OOMKilled = ctr.getOOMKilled()
c.processEvent(ctr, et, ei)
}
}

View file

@ -18,7 +18,7 @@ import (
"github.com/BurntSushi/toml"
"github.com/containerd/containerd"
"github.com/containerd/containerd/server"
"github.com/containerd/containerd/services/server"
"github.com/docker/docker/pkg/system"
"github.com/pkg/errors"
"github.com/sirupsen/logrus"

View file

@ -6,6 +6,7 @@ import (
"syscall"
"time"
"github.com/containerd/containerd/defaults"
"github.com/docker/docker/pkg/system"
)
@ -18,6 +19,12 @@ func (r *remote) setDefaults() {
if r.GRPC.Address == "" {
r.GRPC.Address = filepath.Join(r.stateDir, sockFile)
}
if r.GRPC.MaxRecvMsgSize == 0 {
r.GRPC.MaxRecvMsgSize = defaults.DefaultMaxRecvMsgSize
}
if r.GRPC.MaxSendMsgSize == 0 {
r.GRPC.MaxSendMsgSize = defaults.DefaultMaxSendMsgSize
}
if r.Debug.Address == "" {
r.Debug.Address = filepath.Join(r.stateDir, debugSockFile)
}

View file

@ -1,7 +1,7 @@
# the following lines are in sorted order, FYI
github.com/Azure/go-ansiterm d6e3b3328b783f23731bc4d058875b0371ff8109
github.com/Microsoft/hcsshim v0.6.11
github.com/Microsoft/go-winio v0.4.6
github.com/Microsoft/go-winio v0.4.7
github.com/docker/libtrust 9cbd2a1374f46905c68a4eb3694a130610adc62a
github.com/go-check/check 4ed411733c5785b40214c70bce814c3a3a689609 https://github.com/cpuguy83/check.git
github.com/golang/gddo 9b12a26f3fbd7397dee4e20939ddca719d840d2a
@ -27,7 +27,7 @@ github.com/imdario/mergo 0.2.1
golang.org/x/sync fd80eb99c8f653c847d294a001bdf2a3a6f768f5
# buildkit
github.com/moby/buildkit b14fd548fe80c0399b105aeec5dbd96ccd2f7720
github.com/moby/buildkit 43e758232a0ac7d50c6a11413186e16684fc1e4f
github.com/tonistiigi/fsutil dc68c74458923f357474a9178bd198aa3ed11a5f
github.com/grpc-ecosystem/grpc-opentracing 8e809c8a86450a29b90dcc9efbf062d0fe6d9746
github.com/opentracing/opentracing-go 1361b9cd60be79c4c3a7fa9841b3c132e40066a7
@ -70,10 +70,10 @@ github.com/opencontainers/go-digest v1.0.0-rc1
github.com/mistifyio/go-zfs 22c9b32c84eb0d0c6f4043b6e90fc94073de92fa
github.com/pborman/uuid v1.0
google.golang.org/grpc v1.3.0
google.golang.org/grpc v1.12.0
# When updating, also update RUNC_COMMIT in hack/dockerfile/install/runc accordingly
github.com/opencontainers/runc 4fc53a81fb7c994640722ac585fa9ca548971871
github.com/opencontainers/runc 69663f0bd4b60df09991c08812a60108003fa340
github.com/opencontainers/runtime-spec v1.0.1
github.com/opencontainers/image-spec v1.0.1
github.com/seccomp/libseccomp-golang 32f571b70023028bd57d9288c20efbcb237f3ce0
@ -82,7 +82,7 @@ github.com/seccomp/libseccomp-golang 32f571b70023028bd57d9288c20efbcb237f3ce0
github.com/coreos/go-systemd v17
github.com/godbus/dbus v4.0.0
github.com/syndtr/gocapability 2c00daeb6c3b45114c80ac44119e7b8801fdd852
github.com/golang/protobuf 7a211bcf3bce0e3f1d74f9894916e6f116ae83b4
github.com/golang/protobuf v1.1.0
# gelf logging driver deps
github.com/Graylog2/go-gelf 4143646226541087117ff2f83334ea48b3201841
@ -104,26 +104,27 @@ github.com/jmespath/go-jmespath 0b12d6b521d83fc7f755e7cfc1b1fbdd35a01a74
github.com/bsphere/le_go 7a984a84b5492ae539b79b62fb4a10afc63c7bcf
# gcplogs deps
golang.org/x/oauth2 96382aa079b72d8c014eb0c50f6c223d1e6a2de0
google.golang.org/api 3cc2e591b550923a2c5f0ab5a803feda924d5823
cloud.google.com/go 9d965e63e8cceb1b5d7977a202f0fcb8866d6525
github.com/googleapis/gax-go da06d194a00e19ce00d9011a13931c3f6f6887c7
google.golang.org/genproto d80a6e20e776b0b17a324d0ba1ab50a39c8e8944
golang.org/x/oauth2 ec22f46f877b4505e0117eeaab541714644fdd28
google.golang.org/api de943baf05a022a8f921b544b7827bacaba1aed5
go.opencensus.io v0.11.0
cloud.google.com/go v0.23.0
github.com/googleapis/gax-go v2.0.0
google.golang.org/genproto 694d95ba50e67b2e363f3483057db5d4910c18f9
# containerd
github.com/containerd/containerd 4ac4fd0b6a268fe6f38b2b2e32e40daa7e424fac
github.com/containerd/fifo fbfb6a11ec671efbe94ad1c12c2e98773f19e1e6
github.com/containerd/continuity 2d3749b4da569ac97ca63dccba5eee4f5ee2beab
github.com/containerd/containerd c7083eed5d8633d54c25fe81aa609010a4f2e495
github.com/containerd/fifo 3d5202aec260678c48179c56f40e6f38a095738c
github.com/containerd/continuity d3c23511c1bf5851696cba83143d9cbcd666869b
github.com/containerd/cgroups fe281dd265766145e943a034aa41086474ea6130
github.com/containerd/console 2748ece16665b45a47f884001d5831ec79703880
github.com/containerd/go-runc 4f6e87ae043f859a38255247b49c9abc262d002f
github.com/containerd/console cb7008ab3d8359b78c5f464cb7cf160107ad5925
github.com/containerd/go-runc f271fa2021de855d4d918dbef83c5fe19db1bdd
github.com/containerd/typeurl f6943554a7e7e88b3c14aad190bf05932da84788
github.com/dmcgowan/go-tar go1.10
github.com/stevvooe/ttrpc d4528379866b0ce7e9d71f3eb96f0582fc374577
github.com/gogo/googleapis 08a7655d27152912db7aaf4f983275eaf8d128ef
# cluster
github.com/docker/swarmkit bd69f6e8e301645afd344913fa1ede53a0a111fb
github.com/gogo/protobuf v0.4
github.com/docker/swarmkit edd5641391926a50bc5f7040e20b7efc05003c26
github.com/gogo/protobuf v1.0.0
github.com/cloudflare/cfssl 7fb22c8cba7ecaf98e4082d22d65800cf45e042a
github.com/fernet/fernet-go 1b2437bc582b3cfbb341ee5a29f8ef5b42912ff2
github.com/google/certificate-transparency d90e65c3a07988180c5b1ece71791c0b6506826e

2
vendor/cloud.google.com/go/LICENSE generated vendored
View file

@ -187,7 +187,7 @@
same "printed page" as the copyright notice for easier
identification within third-party archives.
Copyright 2014 Google Inc.
Copyright [yyyy] [name of copyright owner]
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.

488
vendor/cloud.google.com/go/README.md generated vendored
View file

@ -1,159 +1,283 @@
# Google Cloud for Go
# Google Cloud Client Libraries for Go
[![Build Status](https://travis-ci.org/GoogleCloudPlatform/google-cloud-go.svg?branch=master)](https://travis-ci.org/GoogleCloudPlatform/google-cloud-go)
[![GoDoc](https://godoc.org/cloud.google.com/go?status.svg)](https://godoc.org/cloud.google.com/go)
Go packages for [Google Cloud Platform](https://cloud.google.com) services.
``` go
import "cloud.google.com/go"
```
Go packages for Google Cloud Platform services.
To install the packages on your system,
```
$ go get -u cloud.google.com/go/...
```
**NOTE:** These packages are under development, and may occasionally make
backwards-incompatible changes.
**NOTE:** Some of these packages are under development, and may occasionally
make backwards-incompatible changes.
**NOTE:** Github repo is a mirror of [https://code.googlesource.com/gocloud](https://code.googlesource.com/gocloud).
* [News](#news)
* [Supported APIs](#supported-apis)
* [Go Versions Supported](#go-versions-supported)
* [Authorization](#authorization)
* [Cloud Datastore](#cloud-datastore-)
* [Cloud Storage](#cloud-storage-)
* [Cloud Pub/Sub](#cloud-pub-sub-)
* [Cloud BigQuery](#cloud-bigquery-)
* [Stackdriver Logging](#stackdriver-logging-)
* [Cloud Spanner](#cloud-spanner-)
## News
_December 5, 2016_
_May 18, 2018_
More changes to BigQuery:
*v0.23.0*
* The `ValueList` type was removed. It is no longer necessary. Instead of
```go
var v ValueList
... it.Next(&v) ..
```
use
- bigquery: Add DDL stats to query statistics.
- bigtable:
- cbt: Add cells-per-column limit for row lookup.
- cbt: Make it possible to combine read filters.
- dlp: v2beta2 client removed. Use the v2 client instead.
- firestore, spanner: Fix compilation errors due to protobuf changes.
```go
var v []Value
... it.Next(&v) ...
```
_May 8, 2018_
* Previously, repeatedly calling `RowIterator.Next` on the same `[]Value` or
`ValueList` would append to the slice. Now each call resets the size to zero first.
*v0.22.0*
* Schema inference will infer the SQL type BYTES for a struct field of
type []byte. Previously it inferred STRING.
- bigtable:
- cbt: Support cells per column limit for row read.
- bttest: Correctly handle empty RowSet.
- Fix ReadModifyWrite operation in emulator.
- Fix API path in GetCluster.
* The types `uint`, `uint64` and `uintptr` are no longer supported in schema
inference. BigQuery's integer type is INT64, and those types may hold values
that are not correctly represented in a 64-bit signed integer.
- bigquery:
- BEHAVIOR CHANGE: Retry on 503 status code.
- Add dataset.DeleteWithContents.
- Add SchemaUpdateOptions for query jobs.
- Add Timeline to QueryStatistics.
- Add more stats to ExplainQueryStage.
- Support Parquet data format.
* The SQL types DATE, TIME and DATETIME are now supported. They correspond to
the `Date`, `Time` and `DateTime` types in the new `cloud.google.com/go/civil`
package.
- datastore:
- Support omitempty for times.
_November 17, 2016_
- dlp:
- **BREAKING CHANGE:** Remove v1beta1 client. Please migrate to the v2 client,
which is now out of beta.
- Add v2 client.
Change to BigQuery: values from INTEGER columns will now be returned as int64,
not int. This will avoid errors arising from large values on 32-bit systems.
- firestore:
- BEHAVIOR CHANGE: Treat set({}, MergeAll) as valid.
_November 8, 2016_
- iam:
- Support JWT signing via SignJwt callopt.
New datastore feature: datastore now encodes your nested Go structs as Entity values,
instead of a flattened list of the embedded struct's fields.
This means that you may now have twice-nested slices, eg.
```go
type State struct {
Cities []struct{
Populations []int
}
}
```
- profiler:
- BEHAVIOR CHANGE: PollForSerialOutput returns an error when context.Done.
- BEHAVIOR CHANGE: Increase the initial backoff to 1 minute.
- Avoid returning empty serial port output.
See [the announcement](https://groups.google.com/forum/#!topic/google-api-go-announce/79jtrdeuJAg) for
more details.
- pubsub:
- BEHAVIOR CHANGE: Don't backoff during next retryable error once stream is healthy.
- BEHAVIOR CHANGE: Don't backoff on EOF.
- pstest: Support Acknowledge and ModifyAckDeadline RPCs.
_November 8, 2016_
- redis:
- Add v1 beta Redis client.
Breaking changes to datastore: contexts no longer hold namespaces; instead you
must set a key's namespace explicitly. Also, key functions have been changed
and renamed.
- spanner:
- Support SessionLabels.
* The WithNamespace function has been removed. To specify a namespace in a Query, use the Query.Namespace method:
```go
q := datastore.NewQuery("Kind").Namespace("ns")
```
- speech:
- Add api v1 beta1 client.
* All the fields of Key are exported. That means you can construct any Key with a struct literal:
```go
k := &Key{Kind: "Kind", ID: 37, Namespace: "ns"}
```
- storage:
- BEHAVIOR CHANGE: Retry reads when retryable error occurs.
- Fix delete of object in requester-pays bucket.
- Support KMS integration.
* As a result of the above, the Key methods Kind, ID, d.Name, Parent, SetParent and Namespace have been removed.
_April 9, 2018_
* `NewIncompleteKey` has been removed, replaced by `IncompleteKey`. Replace
```go
NewIncompleteKey(ctx, kind, parent)
```
with
```go
IncompleteKey(kind, parent)
```
and if you do use namespaces, make sure you set the namespace on the returned key.
*v0.21.0*
* `NewKey` has been removed, replaced by `NameKey` and `IDKey`. Replace
```go
NewKey(ctx, kind, name, 0, parent)
NewKey(ctx, kind, "", id, parent)
```
with
```go
NameKey(kind, name, parent)
IDKey(kind, id, parent)
```
and if you do use namespaces, make sure you set the namespace on the returned key.
- bigquery:
- Add OpenCensus tracing.
* The `Done` variable has been removed. Replace `datastore.Done` with `iterator.Done`, from the package `google.golang.org/api/iterator`.
- firestore:
- **BREAKING CHANGE:** If a document does not exist, return a DocumentSnapshot
whose Exists method returns false. DocumentRef.Get and Transaction.Get
return the non-nil DocumentSnapshot in addition to a NotFound error.
**DocumentRef.GetAll and Transaction.GetAll return a non-nil
DocumentSnapshot instead of nil.**
- Add DocumentIterator.Stop. **Call Stop whenever you are done with a
DocumentIterator.**
- Added Query.Snapshots and DocumentRef.Snapshots, which provide realtime
notification of updates. See https://cloud.google.com/firestore/docs/query-data/listen.
- Canceling an RPC now always returns a grpc.Status with codes.Canceled.
* The `Client.Close` method will have a return type of error. It will return the result of closing the underlying gRPC connection.
- spanner:
- Add `CommitTimestamp`, which supports inserting the commit timestamp of a
transaction into a column.
See [the announcement](https://groups.google.com/forum/#!topic/google-api-go-announce/hqXtM_4Ix-0) for
more details.
_March 22, 2018_
_October 27, 2016_
*v0.20.0*
Breaking change to bigquery: `NewGCSReference` is now a function,
not a method on `Client`.
- bigquery: Support SchemaUpdateOptions for load jobs.
New bigquery feature: `Table.LoaderFrom` now accepts a `ReaderSource`, enabling
loading data into a table from a file or any `io.Reader`.
- bigtable:
- Add SampleRowKeys.
- cbt: Support union, intersection GCPolicy.
- Retry admin RPCS.
- Add trace spans to retries.
_October 21, 2016_
- datastore: Add OpenCensus tracing.
Breaking change to pubsub: removed `pubsub.Done`.
- firestore:
- Fix queries involving Null and NaN.
- Allow Timestamp protobuffers for time values.
Use `iterator.Done` instead, where `iterator` is the package
`google.golang.org/api/iterator`.
- logging: Add a WriteTimeout option.
- spanner: Support Batch API.
- storage: Add OpenCensus tracing.
_February 26, 2018_
*v0.19.0*
- bigquery:
- Support customer-managed encryption keys.
- bigtable:
- Improved emulator support.
- Support GetCluster.
- datastore:
- Add general mutations.
- Support pointer struct fields.
- Support transaction options.
- firestore:
- Add Transaction.GetAll.
- Support document cursors.
- logging:
- Support concurrent RPCs to the service.
- Support per-entry resources.
- profiler:
- Add config options to disable heap and thread profiling.
- Read the project ID from $GOOGLE_CLOUD_PROJECT when it's set.
- pubsub:
- BEHAVIOR CHANGE: Release flow control after ack/nack (instead of after the
callback returns).
- Add SubscriptionInProject.
- Add OpenCensus instrumentation for streaming pull.
- storage:
- Support CORS.
_January 18, 2018_
*v0.18.0*
- bigquery:
- Marked stable.
- Schema inference of nullable fields supported.
- Added TimePartitioning to QueryConfig.
- firestore: Data provided to DocumentRef.Set with a Merge option can contain
Delete sentinels.
- logging: Clients can accept parent resources other than projects.
- pubsub:
- pubsub/pstest: A lighweight fake for pubsub. Experimental; feedback welcome.
- Support updating more subscription metadata: AckDeadline,
RetainAckedMessages and RetentionDuration.
- oslogin/apiv1beta: New client for the Cloud OS Login API.
- rpcreplay: A package for recording and replaying gRPC traffic.
- spanner:
- Add a ReadWithOptions that supports a row limit, as well as an index.
- Support query plan and execution statistics.
- Added [OpenCensus](http://opencensus.io) support.
- storage: Clarify checksum validation for gzipped files (it is not validated
when the file is served uncompressed).
_December 11, 2017_
*v0.17.0*
- firestore BREAKING CHANGES:
- Remove UpdateMap and UpdateStruct; rename UpdatePaths to Update.
Change
`docref.UpdateMap(ctx, map[string]interface{}{"a.b", 1})`
to
`docref.Update(ctx, []firestore.Update{{Path: "a.b", Value: 1}})`
Change
`docref.UpdateStruct(ctx, []string{"Field"}, aStruct)`
to
`docref.Update(ctx, []firestore.Update{{Path: "Field", Value: aStruct.Field}})`
- Rename MergePaths to Merge; require args to be FieldPaths
- A value stored as an integer can be read into a floating-point field, and vice versa.
- bigtable/cmd/cbt:
- Support deleting a column.
- Add regex option for row read.
- spanner: Mark stable.
- storage:
- Add Reader.ContentEncoding method.
- Fix handling of SignedURL headers.
- bigquery:
- If Uploader.Put is called with no rows, it returns nil without making a
call.
- Schema inference supports the "nullable" option in struct tags for
non-required fields.
- TimePartitioning supports "Field".
[Older news](https://github.com/GoogleCloudPlatform/google-cloud-go/blob/master/old-news.md)
## Supported APIs
Google API | Status | Package
-------------------------------|--------------|-----------------------------------------------------------
[Datastore][cloud-datastore] | beta | [`cloud.google.com/go/datastore`][cloud-datastore-ref]
[Storage][cloud-storage] | beta | [`cloud.google.com/go/storage`][cloud-storage-ref]
[Bigtable][cloud-bigtable] | beta | [`cloud.google.com/go/bigtable`][cloud-bigtable-ref]
[BigQuery][cloud-bigquery] | beta | [`cloud.google.com/go/bigquery`][cloud-bigquery-ref]
[Logging][cloud-logging] | beta | [`cloud.google.com/go/logging`][cloud-logging-ref]
[Pub/Sub][cloud-pubsub] | experimental | [`cloud.google.com/go/pubsub`][cloud-pubsub-ref]
[Vision][cloud-vision] | experimental | [`cloud.google.com/go/vision`][cloud-vision-ref]
[Language][cloud-language] | experimental | [`cloud.google.com/go/language/apiv1beta1`][cloud-language-ref]
[Speech][cloud-speech] | experimental | [`cloud.google.com/go/speech/apiv1beta`][cloud-speech-ref]
Google API | Status | Package
---------------------------------|--------------|-----------------------------------------------------------
[BigQuery][cloud-bigquery] | stable | [`cloud.google.com/go/bigquery`][cloud-bigquery-ref]
[Bigtable][cloud-bigtable] | stable | [`cloud.google.com/go/bigtable`][cloud-bigtable-ref]
[Container][cloud-container] | alpha | [`cloud.google.com/go/container/apiv1`][cloud-container-ref]
[Data Loss Prevention][cloud-dlp]| alpha | [`cloud.google.com/go/dlp/apiv2beta1`][cloud-dlp-ref]
[Datastore][cloud-datastore] | stable | [`cloud.google.com/go/datastore`][cloud-datastore-ref]
[Debugger][cloud-debugger] | alpha | [`cloud.google.com/go/debugger/apiv2`][cloud-debugger-ref]
[ErrorReporting][cloud-errors] | alpha | [`cloud.google.com/go/errorreporting`][cloud-errors-ref]
[Firestore][cloud-firestore] | beta | [`cloud.google.com/go/firestore`][cloud-firestore-ref]
[Language][cloud-language] | stable | [`cloud.google.com/go/language/apiv1`][cloud-language-ref]
[Logging][cloud-logging] | stable | [`cloud.google.com/go/logging`][cloud-logging-ref]
[Monitoring][cloud-monitoring] | beta | [`cloud.google.com/go/monitoring/apiv3`][cloud-monitoring-ref]
[OS Login][cloud-oslogin] | alpha | [`cloud.google.com/compute/docs/oslogin/rest`][cloud-oslogin-ref]
[Pub/Sub][cloud-pubsub] | beta | [`cloud.google.com/go/pubsub`][cloud-pubsub-ref]
[Spanner][cloud-spanner] | stable | [`cloud.google.com/go/spanner`][cloud-spanner-ref]
[Speech][cloud-speech] | stable | [`cloud.google.com/go/speech/apiv1`][cloud-speech-ref]
[Storage][cloud-storage] | stable | [`cloud.google.com/go/storage`][cloud-storage-ref]
[Translation][cloud-translation] | stable | [`cloud.google.com/go/translate`][cloud-translation-ref]
[Video Intelligence][cloud-video]| beta | [`cloud.google.com/go/videointelligence/apiv1beta1`][cloud-video-ref]
[Vision][cloud-vision] | stable | [`cloud.google.com/go/vision/apiv1`][cloud-vision-ref]
> **Experimental status**: the API is still being actively developed. As a
> **Alpha status**: the API is still being actively developed. As a
> result, it might change in backward-incompatible ways and is not recommended
> for production use.
>
@ -184,12 +308,18 @@ By default, each API will use [Google Application Default Credentials][default-c
for authorization credentials used in calling the API endpoints. This will allow your
application to run in many environments without requiring explicit configuration.
[snip]:# (auth)
```go
client, err := storage.NewClient(ctx)
```
To authorize using a
[JSON key file](https://cloud.google.com/iam/docs/managing-service-account-keys),
pass
[`option.WithServiceAccountFile`](https://godoc.org/google.golang.org/api/option#WithServiceAccountFile)
to the `NewClient` function of the desired package. For example:
[snip]:# (auth-JSON)
```go
client, err := storage.NewClient(ctx, option.WithServiceAccountFile("path/to/keyfile.json"))
```
@ -199,6 +329,7 @@ You can exert more control over authorization by using the
create an `oauth2.TokenSource`. Then pass
[`option.WithTokenSource`](https://godoc.org/google.golang.org/api/option#WithTokenSource)
to the `NewClient` function:
[snip]:# (auth-ts)
```go
tokenSource := ...
client, err := storage.NewClient(ctx, option.WithTokenSource(tokenSource))
@ -216,6 +347,7 @@ client, err := storage.NewClient(ctx, option.WithTokenSource(tokenSource))
First create a `datastore.Client` to use throughout your application:
[snip]:# (datastore-1)
```go
client, err := datastore.NewClient(ctx, "my-project-id")
if err != nil {
@ -225,6 +357,7 @@ if err != nil {
Then use that client to interact with the API:
[snip]:# (datastore-2)
```go
type Post struct {
Title string
@ -232,8 +365,8 @@ type Post struct {
PublishedAt time.Time
}
keys := []*datastore.Key{
datastore.NewKey(ctx, "Post", "post1", 0, nil),
datastore.NewKey(ctx, "Post", "post2", 0, nil),
datastore.NameKey("Post", "post1", nil),
datastore.NameKey("Post", "post2", nil),
}
posts := []*Post{
{Title: "Post 1", Body: "...", PublishedAt: time.Now()},
@ -255,6 +388,7 @@ if _, err := client.PutMulti(ctx, keys, posts); err != nil {
First create a `storage.Client` to use throughout your application:
[snip]:# (storage-1)
```go
client, err := storage.NewClient(ctx)
if err != nil {
@ -262,6 +396,7 @@ if err != nil {
}
```
[snip]:# (storage-2)
```go
// Read the object1 from bucket.
rc, err := client.Bucket("bucket").Object("object1").NewReader(ctx)
@ -286,6 +421,7 @@ if err != nil {
First create a `pubsub.Client` to use throughout your application:
[snip]:# (pubsub-1)
```go
client, err := pubsub.NewClient(ctx, "project-id")
if err != nil {
@ -293,36 +429,32 @@ if err != nil {
}
```
Then use the client to publish and subscribe:
[snip]:# (pubsub-2)
```go
// Publish "hello world" on topic1.
topic := client.Topic("topic1")
msgIDs, err := topic.Publish(ctx, &pubsub.Message{
res := topic.Publish(ctx, &pubsub.Message{
Data: []byte("hello world"),
})
// The publish happens asynchronously.
// Later, you can get the result from res:
...
msgID, err := res.Get(ctx)
if err != nil {
log.Fatal(err)
}
// Create an iterator to pull messages via subscription1.
it, err := client.Subscription("subscription1").Pull(ctx)
// Use a callback to receive messages via subscription1.
sub := client.Subscription("subscription1")
err = sub.Receive(ctx, func(ctx context.Context, m *pubsub.Message) {
fmt.Println(m.Data)
m.Ack() // Acknowledge that we've consumed the message.
})
if err != nil {
log.Println(err)
}
defer it.Stop()
// Consume N messages from the iterator.
for i := 0; i < N; i++ {
msg, err := it.Next()
if err == iterator.Done {
break
}
if err != nil {
log.Fatalf("Failed to retrieve message: %v", err)
}
fmt.Printf("Message %d: %s\n", i, msg.Data)
msg.Done(true) // Acknowledge that we've consumed the message.
}
```
## Cloud BigQuery [![GoDoc](https://godoc.org/cloud.google.com/go/bigquery?status.svg)](https://godoc.org/cloud.google.com/go/bigquery)
@ -335,13 +467,16 @@ for i := 0; i < N; i++ {
### Example Usage
First create a `bigquery.Client` to use throughout your application:
[snip]:# (bq-1)
```go
c, err := bigquery.NewClient(ctx, "my-project-ID")
if err != nil {
// TODO: Handle error.
// TODO: Handle error.
}
```
Then use that client to interact with the API:
[snip]:# (bq-2)
```go
// Construct a query.
q := c.Query(`
@ -354,19 +489,19 @@ q := c.Query(`
// Execute the query.
it, err := q.Read(ctx)
if err != nil {
// TODO: Handle error.
// TODO: Handle error.
}
// Iterate through the results.
for {
var values bigquery.ValueList
err := it.Next(&values)
if err == iterator.Done {
break
}
if err != nil {
// TODO: Handle error.
}
fmt.Println(values)
var values []bigquery.Value
err := it.Next(&values)
if err == iterator.Done {
break
}
if err != nil {
// TODO: Handle error.
}
fmt.Println(values)
}
```
@ -381,28 +516,68 @@ for {
### Example Usage
First create a `logging.Client` to use throughout your application:
[snip]:# (logging-1)
```go
ctx := context.Background()
client, err := logging.NewClient(ctx, "my-project")
if err != nil {
// TODO: Handle error.
// TODO: Handle error.
}
```
Usually, you'll want to add log entries to a buffer to be periodically flushed
(automatically and asynchronously) to the Stackdriver Logging service.
[snip]:# (logging-2)
```go
logger := client.Logger("my-log")
logger.Log(logging.Entry{Payload: "something happened!"})
```
Close your client before your program exits, to flush any buffered log entries.
[snip]:# (logging-3)
```go
err = client.Close()
if err != nil {
// TODO: Handle error.
// TODO: Handle error.
}
```
## Cloud Spanner [![GoDoc](https://godoc.org/cloud.google.com/go/spanner?status.svg)](https://godoc.org/cloud.google.com/go/spanner)
- [About Cloud Spanner][cloud-spanner]
- [API documentation][cloud-spanner-docs]
- [Go client documentation](https://godoc.org/cloud.google.com/go/spanner)
### Example Usage
First create a `spanner.Client` to use throughout your application:
[snip]:# (spanner-1)
```go
client, err := spanner.NewClient(ctx, "projects/P/instances/I/databases/D")
if err != nil {
log.Fatal(err)
}
```
[snip]:# (spanner-2)
```go
// Simple Reads And Writes
_, err = client.Apply(ctx, []*spanner.Mutation{
spanner.Insert("Users",
[]string{"name", "email"},
[]interface{}{"alice", "a@example.com"})})
if err != nil {
log.Fatal(err)
}
row, err := client.Single().ReadRow(ctx, "Users",
spanner.Key{"alice"}, []string{"email"})
if err != nil {
log.Fatal(err)
}
```
## Contributing
Contributions are welcome. Please, see the
@ -420,6 +595,11 @@ for more information.
[cloud-datastore-docs]: https://cloud.google.com/datastore/docs
[cloud-datastore-activation]: https://cloud.google.com/datastore/docs/activate
[cloud-firestore]: https://cloud.google.com/firestore/
[cloud-firestore-ref]: https://godoc.org/cloud.google.com/go/firestore
[cloud-firestore-docs]: https://cloud.google.com/firestore/docs
[cloud-firestore-activation]: https://cloud.google.com/firestore/docs/activate
[cloud-pubsub]: https://cloud.google.com/pubsub/
[cloud-pubsub-ref]: https://godoc.org/cloud.google.com/go/pubsub
[cloud-pubsub-docs]: https://cloud.google.com/pubsub/docs
@ -440,13 +620,41 @@ for more information.
[cloud-logging-docs]: https://cloud.google.com/logging/docs
[cloud-logging-ref]: https://godoc.org/cloud.google.com/go/logging
[cloud-vision]: https://cloud.google.com/vision/
[cloud-vision-ref]: https://godoc.org/cloud.google.com/go/vision
[cloud-monitoring]: https://cloud.google.com/monitoring/
[cloud-monitoring-ref]: https://godoc.org/cloud.google.com/go/monitoring/apiv3
[cloud-vision]: https://cloud.google.com/vision
[cloud-vision-ref]: https://godoc.org/cloud.google.com/go/vision/apiv1
[cloud-language]: https://cloud.google.com/natural-language
[cloud-language-ref]: https://godoc.org/cloud.google.com/go/language/apiv1beta1
[cloud-language-ref]: https://godoc.org/cloud.google.com/go/language/apiv1
[cloud-oslogin]: https://cloud.google.com/compute/docs/oslogin/rest
[cloud-oslogin-ref]: https://cloud.google.com/compute/docs/oslogin/rest
[cloud-speech]: https://cloud.google.com/speech
[cloud-speech-ref]: https://godoc.org/cloud.google.com/go/speech/apiv1beta1
[cloud-speech-ref]: https://godoc.org/cloud.google.com/go/speech/apiv1
[cloud-spanner]: https://cloud.google.com/spanner/
[cloud-spanner-ref]: https://godoc.org/cloud.google.com/go/spanner
[cloud-spanner-docs]: https://cloud.google.com/spanner/docs
[cloud-translation]: https://cloud.google.com/translation
[cloud-translation-ref]: https://godoc.org/cloud.google.com/go/translation
[cloud-video]: https://cloud.google.com/video-intelligence/
[cloud-video-ref]: https://godoc.org/cloud.google.com/go/videointelligence/apiv1beta1
[cloud-errors]: https://cloud.google.com/error-reporting/
[cloud-errors-ref]: https://godoc.org/cloud.google.com/go/errorreporting
[cloud-container]: https://cloud.google.com/containers/
[cloud-container-ref]: https://godoc.org/cloud.google.com/go/container/apiv1
[cloud-debugger]: https://cloud.google.com/debugger/
[cloud-debugger-ref]: https://godoc.org/cloud.google.com/go/debugger/apiv2
[cloud-dlp]: https://cloud.google.com/dlp/
[cloud-dlp-ref]: https://godoc.org/cloud.google.com/go/dlp/apiv2beta1
[default-creds]: https://developers.google.com/identity/protocols/application-default-credentials

View file

@ -34,8 +34,6 @@ import (
"golang.org/x/net/context"
"golang.org/x/net/context/ctxhttp"
"cloud.google.com/go/internal"
)
const (
@ -48,6 +46,8 @@ const (
// This is variable name is not defined by any spec, as far as
// I know; it was made up for the Go package.
metadataHostEnv = "GCE_METADATA_HOST"
userAgent = "gcloud-golang/0.1"
)
type cachedValue struct {
@ -65,24 +65,20 @@ var (
var (
metaClient = &http.Client{
Transport: &internal.Transport{
Base: &http.Transport{
Dial: (&net.Dialer{
Timeout: 2 * time.Second,
KeepAlive: 30 * time.Second,
}).Dial,
ResponseHeaderTimeout: 2 * time.Second,
},
Transport: &http.Transport{
Dial: (&net.Dialer{
Timeout: 2 * time.Second,
KeepAlive: 30 * time.Second,
}).Dial,
ResponseHeaderTimeout: 2 * time.Second,
},
}
subscribeClient = &http.Client{
Transport: &internal.Transport{
Base: &http.Transport{
Dial: (&net.Dialer{
Timeout: 2 * time.Second,
KeepAlive: 30 * time.Second,
}).Dial,
},
Transport: &http.Transport{
Dial: (&net.Dialer{
Timeout: 2 * time.Second,
KeepAlive: 30 * time.Second,
}).Dial,
},
}
)
@ -132,6 +128,7 @@ func getETag(client *http.Client, suffix string) (value, etag string, err error)
url := "http://" + host + "/computeMetadata/v1/" + suffix
req, _ := http.NewRequest("GET", url, nil)
req.Header.Set("Metadata-Flavor", "Google")
req.Header.Set("User-Agent", userAgent)
res, err := client.Do(req)
if err != nil {
return "", "", err
@ -202,7 +199,9 @@ func testOnGCE() bool {
// Try two strategies in parallel.
// See https://github.com/GoogleCloudPlatform/google-cloud-go/issues/194
go func() {
res, err := ctxhttp.Get(ctx, metaClient, "http://"+metadataIP)
req, _ := http.NewRequest("GET", "http://"+metadataIP, nil)
req.Header.Set("User-Agent", userAgent)
res, err := ctxhttp.Do(ctx, metaClient, req)
if err != nil {
resc <- false
return

View file

@ -1,64 +0,0 @@
// Copyright 2014 Google Inc. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
// Package internal provides support for the cloud packages.
//
// Users should not import this package directly.
package internal
import (
"fmt"
"net/http"
)
const userAgent = "gcloud-golang/0.1"
// Transport is an http.RoundTripper that appends Google Cloud client's
// user-agent to the original request's user-agent header.
type Transport struct {
// TODO(bradfitz): delete internal.Transport. It's too wrappy for what it does.
// Do User-Agent some other way.
// Base is the actual http.RoundTripper
// requests will use. It must not be nil.
Base http.RoundTripper
}
// RoundTrip appends a user-agent to the existing user-agent
// header and delegates the request to the base http.RoundTripper.
func (t *Transport) RoundTrip(req *http.Request) (*http.Response, error) {
req = cloneRequest(req)
ua := req.Header.Get("User-Agent")
if ua == "" {
ua = userAgent
} else {
ua = fmt.Sprintf("%s %s", ua, userAgent)
}
req.Header.Set("User-Agent", ua)
return t.Base.RoundTrip(req)
}
// cloneRequest returns a clone of the provided *http.Request.
// The clone is a shallow copy of the struct and its Header map.
func cloneRequest(r *http.Request) *http.Request {
// shallow copy of the struct
r2 := new(http.Request)
*r2 = *r
// deep copy of the Header
r2.Header = make(http.Header)
for k, s := range r.Header {
r2.Header[k] = s
}
return r2
}

View file

@ -1,55 +0,0 @@
// Copyright 2016 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
import (
"fmt"
"time"
gax "github.com/googleapis/gax-go"
"golang.org/x/net/context"
)
// Retry calls the supplied function f repeatedly according to the provided
// backoff parameters. It returns when one of the following occurs:
// When f's first return value is true, Retry immediately returns with f's second
// return value.
// When the provided context is done, Retry returns with ctx.Err().
func Retry(ctx context.Context, bo gax.Backoff, f func() (stop bool, err error)) error {
return retry(ctx, bo, f, gax.Sleep)
}
func retry(ctx context.Context, bo gax.Backoff, f func() (stop bool, err error),
sleep func(context.Context, time.Duration) error) error {
var lastErr error
for {
stop, err := f()
if stop {
return err
}
// Remember the last "real" error from f.
if err != nil && err != context.Canceled && err != context.DeadlineExceeded {
lastErr = err
}
p := bo.Pause()
if cerr := sleep(ctx, p); cerr != nil {
if lastErr != nil {
return fmt.Errorf("%v; last function err: %v", cerr, lastErr)
}
return cerr
}
}
}

71
vendor/cloud.google.com/go/internal/version/version.go generated vendored Normal file
View file

@ -0,0 +1,71 @@
// Copyright 2016 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.
//go:generate ./update_version.sh
// Package version contains version information for Google Cloud Client
// Libraries for Go, as reported in request headers.
package version
import (
"runtime"
"strings"
"unicode"
)
// Repo is the current version of the client libraries in this
// repo. It should be a date in YYYYMMDD format.
const Repo = "20180226"
// Go returns the Go runtime version. The returned string
// has no whitespace.
func Go() string {
return goVersion
}
var goVersion = goVer(runtime.Version())
const develPrefix = "devel +"
func goVer(s string) string {
if strings.HasPrefix(s, develPrefix) {
s = s[len(develPrefix):]
if p := strings.IndexFunc(s, unicode.IsSpace); p >= 0 {
s = s[:p]
}
return s
}
if strings.HasPrefix(s, "go1") {
s = s[2:]
var prerelease string
if p := strings.IndexFunc(s, notSemverRune); p >= 0 {
s, prerelease = s[:p], s[p:]
}
if strings.HasSuffix(s, ".") {
s += "0"
} else if strings.Count(s, ".") < 2 {
s += ".0"
}
if prerelease != "" {
s += "-" + prerelease
}
return s
}
return ""
}
func notSemverRune(r rune) bool {
return strings.IndexRune("0123456789.", r) < 0
}

View file

@ -1,10 +1,10 @@
// Copyright 2016, Google Inc. All rights reserved.
// Copyright 2018 Google LLC
//
// 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
// https://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,
@ -17,12 +17,10 @@
package logging
import (
"fmt"
"math"
"runtime"
"strings"
"time"
"cloud.google.com/go/internal/version"
gax "github.com/googleapis/gax-go"
"golang.org/x/net/context"
"google.golang.org/api/iterator"
@ -34,30 +32,24 @@ import (
"google.golang.org/grpc/metadata"
)
var (
configParentPathTemplate = gax.MustCompilePathTemplate("projects/{project}")
configSinkPathTemplate = gax.MustCompilePathTemplate("projects/{project}/sinks/{sink}")
)
// ConfigCallOptions contains the retry settings for each method of ConfigClient.
type ConfigCallOptions struct {
ListSinks []gax.CallOption
GetSink []gax.CallOption
CreateSink []gax.CallOption
UpdateSink []gax.CallOption
DeleteSink []gax.CallOption
ListSinks []gax.CallOption
GetSink []gax.CallOption
CreateSink []gax.CallOption
UpdateSink []gax.CallOption
DeleteSink []gax.CallOption
ListExclusions []gax.CallOption
GetExclusion []gax.CallOption
CreateExclusion []gax.CallOption
UpdateExclusion []gax.CallOption
DeleteExclusion []gax.CallOption
}
func defaultConfigClientOptions() []option.ClientOption {
return []option.ClientOption{
option.WithEndpoint("logging.googleapis.com:443"),
option.WithScopes(
"https://www.googleapis.com/auth/cloud-platform",
"https://www.googleapis.com/auth/cloud-platform.read-only",
"https://www.googleapis.com/auth/logging.admin",
"https://www.googleapis.com/auth/logging.read",
"https://www.googleapis.com/auth/logging.write",
),
option.WithScopes(DefaultAuthScopes()...),
}
}
@ -67,6 +59,7 @@ func defaultConfigCallOptions() *ConfigCallOptions {
gax.WithRetry(func() gax.Retryer {
return gax.OnCodes([]codes.Code{
codes.DeadlineExceeded,
codes.Internal,
codes.Unavailable,
}, gax.Backoff{
Initial: 100 * time.Millisecond,
@ -77,11 +70,16 @@ func defaultConfigCallOptions() *ConfigCallOptions {
},
}
return &ConfigCallOptions{
ListSinks: retry[[2]string{"default", "idempotent"}],
GetSink: retry[[2]string{"default", "idempotent"}],
CreateSink: retry[[2]string{"default", "non_idempotent"}],
UpdateSink: retry[[2]string{"default", "non_idempotent"}],
DeleteSink: retry[[2]string{"default", "idempotent"}],
ListSinks: retry[[2]string{"default", "idempotent"}],
GetSink: retry[[2]string{"default", "idempotent"}],
CreateSink: retry[[2]string{"default", "non_idempotent"}],
UpdateSink: retry[[2]string{"default", "non_idempotent"}],
DeleteSink: retry[[2]string{"default", "idempotent"}],
ListExclusions: retry[[2]string{"default", "idempotent"}],
GetExclusion: retry[[2]string{"default", "idempotent"}],
CreateExclusion: retry[[2]string{"default", "non_idempotent"}],
UpdateExclusion: retry[[2]string{"default", "non_idempotent"}],
DeleteExclusion: retry[[2]string{"default", "idempotent"}],
}
}
@ -96,8 +94,8 @@ type ConfigClient struct {
// The call options for this service.
CallOptions *ConfigCallOptions
// The metadata to be sent with each request.
metadata metadata.MD
// The x-goog-* metadata to be sent with each request.
xGoogMetadata metadata.MD
}
// NewConfigClient creates a new config service v2 client.
@ -115,7 +113,7 @@ func NewConfigClient(ctx context.Context, opts ...option.ClientOption) (*ConfigC
configClient: loggingpb.NewConfigServiceV2Client(conn),
}
c.SetGoogleClientInfo("gax", gax.Version)
c.SetGoogleClientInfo()
return c, nil
}
@ -133,39 +131,16 @@ func (c *ConfigClient) Close() error {
// SetGoogleClientInfo sets the name and version of the application in
// the `x-goog-api-client` header passed on each request. Intended for
// use by Google-written clients.
func (c *ConfigClient) SetGoogleClientInfo(name, version string) {
goVersion := strings.Replace(runtime.Version(), " ", "_", -1)
v := fmt.Sprintf("%s/%s %s gax/%s go/%s", name, version, gapicNameVersion, gax.Version, goVersion)
c.metadata = metadata.Pairs("x-goog-api-client", v)
}
// ConfigParentPath returns the path for the parent resource.
func ConfigParentPath(project string) string {
path, err := configParentPathTemplate.Render(map[string]string{
"project": project,
})
if err != nil {
panic(err)
}
return path
}
// ConfigSinkPath returns the path for the sink resource.
func ConfigSinkPath(project, sink string) string {
path, err := configSinkPathTemplate.Render(map[string]string{
"project": project,
"sink": sink,
})
if err != nil {
panic(err)
}
return path
func (c *ConfigClient) SetGoogleClientInfo(keyval ...string) {
kv := append([]string{"gl-go", version.Go()}, keyval...)
kv = append(kv, "gapic", version.Repo, "gax", gax.Version, "grpc", grpc.Version)
c.xGoogMetadata = metadata.Pairs("x-goog-api-client", gax.XGoogHeader(kv...))
}
// ListSinks lists sinks.
func (c *ConfigClient) ListSinks(ctx context.Context, req *loggingpb.ListSinksRequest) *LogSinkIterator {
md, _ := metadata.FromContext(ctx)
ctx = metadata.NewContext(ctx, metadata.Join(md, c.metadata))
func (c *ConfigClient) ListSinks(ctx context.Context, req *loggingpb.ListSinksRequest, opts ...gax.CallOption) *LogSinkIterator {
ctx = insertMetadata(ctx, c.xGoogMetadata)
opts = append(c.CallOptions.ListSinks[0:len(c.CallOptions.ListSinks):len(c.CallOptions.ListSinks)], opts...)
it := &LogSinkIterator{}
it.InternalFetch = func(pageSize int, pageToken string) ([]*loggingpb.LogSink, string, error) {
var resp *loggingpb.ListSinksResponse
@ -175,11 +150,11 @@ func (c *ConfigClient) ListSinks(ctx context.Context, req *loggingpb.ListSinksRe
} else {
req.PageSize = int32(pageSize)
}
err := gax.Invoke(ctx, func(ctx context.Context) error {
err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error {
var err error
resp, err = c.configClient.ListSinks(ctx, req)
resp, err = c.configClient.ListSinks(ctx, req, settings.GRPC...)
return err
}, c.CallOptions.ListSinks...)
}, opts...)
if err != nil {
return nil, "", err
}
@ -198,65 +173,211 @@ func (c *ConfigClient) ListSinks(ctx context.Context, req *loggingpb.ListSinksRe
}
// GetSink gets a sink.
func (c *ConfigClient) GetSink(ctx context.Context, req *loggingpb.GetSinkRequest) (*loggingpb.LogSink, error) {
md, _ := metadata.FromContext(ctx)
ctx = metadata.NewContext(ctx, metadata.Join(md, c.metadata))
func (c *ConfigClient) GetSink(ctx context.Context, req *loggingpb.GetSinkRequest, opts ...gax.CallOption) (*loggingpb.LogSink, error) {
ctx = insertMetadata(ctx, c.xGoogMetadata)
opts = append(c.CallOptions.GetSink[0:len(c.CallOptions.GetSink):len(c.CallOptions.GetSink)], opts...)
var resp *loggingpb.LogSink
err := gax.Invoke(ctx, func(ctx context.Context) error {
err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error {
var err error
resp, err = c.configClient.GetSink(ctx, req)
resp, err = c.configClient.GetSink(ctx, req, settings.GRPC...)
return err
}, c.CallOptions.GetSink...)
}, opts...)
if err != nil {
return nil, err
}
return resp, nil
}
// CreateSink creates a sink.
func (c *ConfigClient) CreateSink(ctx context.Context, req *loggingpb.CreateSinkRequest) (*loggingpb.LogSink, error) {
md, _ := metadata.FromContext(ctx)
ctx = metadata.NewContext(ctx, metadata.Join(md, c.metadata))
// CreateSink creates a sink that exports specified log entries to a destination. The
// export of newly-ingested log entries begins immediately, unless the sink's
// writer_identity is not permitted to write to the destination. A sink can
// export log entries only from the resource owning the sink.
func (c *ConfigClient) CreateSink(ctx context.Context, req *loggingpb.CreateSinkRequest, opts ...gax.CallOption) (*loggingpb.LogSink, error) {
ctx = insertMetadata(ctx, c.xGoogMetadata)
opts = append(c.CallOptions.CreateSink[0:len(c.CallOptions.CreateSink):len(c.CallOptions.CreateSink)], opts...)
var resp *loggingpb.LogSink
err := gax.Invoke(ctx, func(ctx context.Context) error {
err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error {
var err error
resp, err = c.configClient.CreateSink(ctx, req)
resp, err = c.configClient.CreateSink(ctx, req, settings.GRPC...)
return err
}, c.CallOptions.CreateSink...)
}, opts...)
if err != nil {
return nil, err
}
return resp, nil
}
// UpdateSink updates or creates a sink.
func (c *ConfigClient) UpdateSink(ctx context.Context, req *loggingpb.UpdateSinkRequest) (*loggingpb.LogSink, error) {
md, _ := metadata.FromContext(ctx)
ctx = metadata.NewContext(ctx, metadata.Join(md, c.metadata))
// UpdateSink updates a sink. This method replaces the following fields in the existing
// sink with values from the new sink: destination, and filter.
// The updated sink might also have a new writer_identity; see the
// unique_writer_identity field.
func (c *ConfigClient) UpdateSink(ctx context.Context, req *loggingpb.UpdateSinkRequest, opts ...gax.CallOption) (*loggingpb.LogSink, error) {
ctx = insertMetadata(ctx, c.xGoogMetadata)
opts = append(c.CallOptions.UpdateSink[0:len(c.CallOptions.UpdateSink):len(c.CallOptions.UpdateSink)], opts...)
var resp *loggingpb.LogSink
err := gax.Invoke(ctx, func(ctx context.Context) error {
err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error {
var err error
resp, err = c.configClient.UpdateSink(ctx, req)
resp, err = c.configClient.UpdateSink(ctx, req, settings.GRPC...)
return err
}, c.CallOptions.UpdateSink...)
}, opts...)
if err != nil {
return nil, err
}
return resp, nil
}
// DeleteSink deletes a sink.
func (c *ConfigClient) DeleteSink(ctx context.Context, req *loggingpb.DeleteSinkRequest) error {
md, _ := metadata.FromContext(ctx)
ctx = metadata.NewContext(ctx, metadata.Join(md, c.metadata))
err := gax.Invoke(ctx, func(ctx context.Context) error {
// DeleteSink deletes a sink. If the sink has a unique writer_identity, then that
// service account is also deleted.
func (c *ConfigClient) DeleteSink(ctx context.Context, req *loggingpb.DeleteSinkRequest, opts ...gax.CallOption) error {
ctx = insertMetadata(ctx, c.xGoogMetadata)
opts = append(c.CallOptions.DeleteSink[0:len(c.CallOptions.DeleteSink):len(c.CallOptions.DeleteSink)], opts...)
err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error {
var err error
_, err = c.configClient.DeleteSink(ctx, req)
_, err = c.configClient.DeleteSink(ctx, req, settings.GRPC...)
return err
}, c.CallOptions.DeleteSink...)
}, opts...)
return err
}
// ListExclusions lists all the exclusions in a parent resource.
func (c *ConfigClient) ListExclusions(ctx context.Context, req *loggingpb.ListExclusionsRequest, opts ...gax.CallOption) *LogExclusionIterator {
ctx = insertMetadata(ctx, c.xGoogMetadata)
opts = append(c.CallOptions.ListExclusions[0:len(c.CallOptions.ListExclusions):len(c.CallOptions.ListExclusions)], opts...)
it := &LogExclusionIterator{}
it.InternalFetch = func(pageSize int, pageToken string) ([]*loggingpb.LogExclusion, string, error) {
var resp *loggingpb.ListExclusionsResponse
req.PageToken = pageToken
if pageSize > math.MaxInt32 {
req.PageSize = math.MaxInt32
} else {
req.PageSize = int32(pageSize)
}
err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error {
var err error
resp, err = c.configClient.ListExclusions(ctx, req, settings.GRPC...)
return err
}, opts...)
if err != nil {
return nil, "", err
}
return resp.Exclusions, resp.NextPageToken, nil
}
fetch := func(pageSize int, pageToken string) (string, error) {
items, nextPageToken, err := it.InternalFetch(pageSize, pageToken)
if err != nil {
return "", err
}
it.items = append(it.items, items...)
return nextPageToken, nil
}
it.pageInfo, it.nextFunc = iterator.NewPageInfo(fetch, it.bufLen, it.takeBuf)
return it
}
// GetExclusion gets the description of an exclusion.
func (c *ConfigClient) GetExclusion(ctx context.Context, req *loggingpb.GetExclusionRequest, opts ...gax.CallOption) (*loggingpb.LogExclusion, error) {
ctx = insertMetadata(ctx, c.xGoogMetadata)
opts = append(c.CallOptions.GetExclusion[0:len(c.CallOptions.GetExclusion):len(c.CallOptions.GetExclusion)], opts...)
var resp *loggingpb.LogExclusion
err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error {
var err error
resp, err = c.configClient.GetExclusion(ctx, req, settings.GRPC...)
return err
}, opts...)
if err != nil {
return nil, err
}
return resp, nil
}
// CreateExclusion creates a new exclusion in a specified parent resource.
// Only log entries belonging to that resource can be excluded.
// You can have up to 10 exclusions in a resource.
func (c *ConfigClient) CreateExclusion(ctx context.Context, req *loggingpb.CreateExclusionRequest, opts ...gax.CallOption) (*loggingpb.LogExclusion, error) {
ctx = insertMetadata(ctx, c.xGoogMetadata)
opts = append(c.CallOptions.CreateExclusion[0:len(c.CallOptions.CreateExclusion):len(c.CallOptions.CreateExclusion)], opts...)
var resp *loggingpb.LogExclusion
err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error {
var err error
resp, err = c.configClient.CreateExclusion(ctx, req, settings.GRPC...)
return err
}, opts...)
if err != nil {
return nil, err
}
return resp, nil
}
// UpdateExclusion changes one or more properties of an existing exclusion.
func (c *ConfigClient) UpdateExclusion(ctx context.Context, req *loggingpb.UpdateExclusionRequest, opts ...gax.CallOption) (*loggingpb.LogExclusion, error) {
ctx = insertMetadata(ctx, c.xGoogMetadata)
opts = append(c.CallOptions.UpdateExclusion[0:len(c.CallOptions.UpdateExclusion):len(c.CallOptions.UpdateExclusion)], opts...)
var resp *loggingpb.LogExclusion
err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error {
var err error
resp, err = c.configClient.UpdateExclusion(ctx, req, settings.GRPC...)
return err
}, opts...)
if err != nil {
return nil, err
}
return resp, nil
}
// DeleteExclusion deletes an exclusion.
func (c *ConfigClient) DeleteExclusion(ctx context.Context, req *loggingpb.DeleteExclusionRequest, opts ...gax.CallOption) error {
ctx = insertMetadata(ctx, c.xGoogMetadata)
opts = append(c.CallOptions.DeleteExclusion[0:len(c.CallOptions.DeleteExclusion):len(c.CallOptions.DeleteExclusion)], opts...)
err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error {
var err error
_, err = c.configClient.DeleteExclusion(ctx, req, settings.GRPC...)
return err
}, opts...)
return err
}
// LogExclusionIterator manages a stream of *loggingpb.LogExclusion.
type LogExclusionIterator struct {
items []*loggingpb.LogExclusion
pageInfo *iterator.PageInfo
nextFunc func() error
// InternalFetch is for use by the Google Cloud Libraries only.
// It is not part of the stable interface of this package.
//
// InternalFetch returns results from a single call to the underlying RPC.
// The number of results is no greater than pageSize.
// If there are no more results, nextPageToken is empty and err is nil.
InternalFetch func(pageSize int, pageToken string) (results []*loggingpb.LogExclusion, nextPageToken string, err error)
}
// PageInfo supports pagination. See the google.golang.org/api/iterator package for details.
func (it *LogExclusionIterator) PageInfo() *iterator.PageInfo {
return it.pageInfo
}
// Next returns the next result. Its second return value is iterator.Done if there are no more
// results. Once Next returns Done, all subsequent calls will return Done.
func (it *LogExclusionIterator) Next() (*loggingpb.LogExclusion, error) {
var item *loggingpb.LogExclusion
if err := it.nextFunc(); err != nil {
return item, err
}
item = it.items[0]
it.items = it.items[1:]
return item, nil
}
func (it *LogExclusionIterator) bufLen() int {
return len(it.items)
}
func (it *LogExclusionIterator) takeBuf() interface{} {
b := it.items
it.items = nil
return b
}
// LogSinkIterator manages a stream of *loggingpb.LogSink.
type LogSinkIterator struct {
items []*loggingpb.LogSink

View file

@ -1,10 +1,10 @@
// Copyright 2016, Google Inc. All rights reserved.
// Copyright 2018 Google LLC
//
// 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
// https://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,
@ -14,13 +14,39 @@
// AUTO-GENERATED CODE. DO NOT EDIT.
// Package logging is an experimental, auto-generated package for the
// logging API.
// Package logging is an auto-generated package for the
// Stackdriver Logging API.
//
// The Stackdriver Logging API lets you write log entries and manage your
// logs, log sinks and logs-based metrics.
// NOTE: This package is in alpha. It is not stable, and is likely to change.
//
// Writes log entries and manages your Stackdriver Logging configuration.
//
// Use the client at cloud.google.com/go/logging in preference to this.
package logging // import "cloud.google.com/go/logging/apiv2"
const gapicNameVersion = "gapic/0.1.0"
import (
"golang.org/x/net/context"
"google.golang.org/grpc/metadata"
)
func insertMetadata(ctx context.Context, mds ...metadata.MD) context.Context {
out, _ := metadata.FromOutgoingContext(ctx)
out = out.Copy()
for _, md := range mds {
for k, v := range md {
out[k] = append(out[k], v...)
}
}
return metadata.NewOutgoingContext(ctx, out)
}
// DefaultAuthScopes reports the default set of authentication scopes to use with this package.
func DefaultAuthScopes() []string {
return []string{
"https://www.googleapis.com/auth/cloud-platform",
"https://www.googleapis.com/auth/cloud-platform.read-only",
"https://www.googleapis.com/auth/logging.admin",
"https://www.googleapis.com/auth/logging.read",
"https://www.googleapis.com/auth/logging.write",
}
}

View file

@ -1,10 +1,10 @@
// Copyright 2016, Google Inc. All rights reserved.
// Copyright 2018 Google LLC
//
// 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
// https://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,
@ -17,12 +17,10 @@
package logging
import (
"fmt"
"math"
"runtime"
"strings"
"time"
"cloud.google.com/go/internal/version"
gax "github.com/googleapis/gax-go"
"golang.org/x/net/context"
"google.golang.org/api/iterator"
@ -35,29 +33,19 @@ import (
"google.golang.org/grpc/metadata"
)
var (
loggingParentPathTemplate = gax.MustCompilePathTemplate("projects/{project}")
loggingLogPathTemplate = gax.MustCompilePathTemplate("projects/{project}/logs/{log}")
)
// CallOptions contains the retry settings for each method of Client.
type CallOptions struct {
DeleteLog []gax.CallOption
WriteLogEntries []gax.CallOption
ListLogEntries []gax.CallOption
ListMonitoredResourceDescriptors []gax.CallOption
ListLogs []gax.CallOption
}
func defaultClientOptions() []option.ClientOption {
return []option.ClientOption{
option.WithEndpoint("logging.googleapis.com:443"),
option.WithScopes(
"https://www.googleapis.com/auth/cloud-platform",
"https://www.googleapis.com/auth/cloud-platform.read-only",
"https://www.googleapis.com/auth/logging.admin",
"https://www.googleapis.com/auth/logging.read",
"https://www.googleapis.com/auth/logging.write",
),
option.WithScopes(DefaultAuthScopes()...),
}
}
@ -67,6 +55,7 @@ func defaultCallOptions() *CallOptions {
gax.WithRetry(func() gax.Retryer {
return gax.OnCodes([]codes.Code{
codes.DeadlineExceeded,
codes.Internal,
codes.Unavailable,
}, gax.Backoff{
Initial: 100 * time.Millisecond,
@ -79,6 +68,7 @@ func defaultCallOptions() *CallOptions {
gax.WithRetry(func() gax.Retryer {
return gax.OnCodes([]codes.Code{
codes.DeadlineExceeded,
codes.Internal,
codes.Unavailable,
}, gax.Backoff{
Initial: 100 * time.Millisecond,
@ -93,6 +83,7 @@ func defaultCallOptions() *CallOptions {
WriteLogEntries: retry[[2]string{"default", "non_idempotent"}],
ListLogEntries: retry[[2]string{"list", "idempotent"}],
ListMonitoredResourceDescriptors: retry[[2]string{"default", "idempotent"}],
ListLogs: retry[[2]string{"default", "idempotent"}],
}
}
@ -107,8 +98,8 @@ type Client struct {
// The call options for this service.
CallOptions *CallOptions
// The metadata to be sent with each request.
metadata metadata.MD
// The x-goog-* metadata to be sent with each request.
xGoogMetadata metadata.MD
}
// NewClient creates a new logging service v2 client.
@ -125,7 +116,7 @@ func NewClient(ctx context.Context, opts ...option.ClientOption) (*Client, error
client: loggingpb.NewLoggingServiceV2Client(conn),
}
c.SetGoogleClientInfo("gax", gax.Version)
c.SetGoogleClientInfo()
return c, nil
}
@ -143,71 +134,55 @@ func (c *Client) Close() error {
// SetGoogleClientInfo sets the name and version of the application in
// the `x-goog-api-client` header passed on each request. Intended for
// use by Google-written clients.
func (c *Client) SetGoogleClientInfo(name, version string) {
goVersion := strings.Replace(runtime.Version(), " ", "_", -1)
v := fmt.Sprintf("%s/%s %s gax/%s go/%s", name, version, gapicNameVersion, gax.Version, goVersion)
c.metadata = metadata.Pairs("x-goog-api-client", v)
}
// LoggingParentPath returns the path for the parent resource.
func LoggingParentPath(project string) string {
path, err := loggingParentPathTemplate.Render(map[string]string{
"project": project,
})
if err != nil {
panic(err)
}
return path
}
// LoggingLogPath returns the path for the log resource.
func LoggingLogPath(project, log string) string {
path, err := loggingLogPathTemplate.Render(map[string]string{
"project": project,
"log": log,
})
if err != nil {
panic(err)
}
return path
func (c *Client) SetGoogleClientInfo(keyval ...string) {
kv := append([]string{"gl-go", version.Go()}, keyval...)
kv = append(kv, "gapic", version.Repo, "gax", gax.Version, "grpc", grpc.Version)
c.xGoogMetadata = metadata.Pairs("x-goog-api-client", gax.XGoogHeader(kv...))
}
// DeleteLog deletes all the log entries in a log.
// The log reappears if it receives new entries.
func (c *Client) DeleteLog(ctx context.Context, req *loggingpb.DeleteLogRequest) error {
md, _ := metadata.FromContext(ctx)
ctx = metadata.NewContext(ctx, metadata.Join(md, c.metadata))
err := gax.Invoke(ctx, func(ctx context.Context) error {
// Log entries written shortly before the delete operation might not be
// deleted.
func (c *Client) DeleteLog(ctx context.Context, req *loggingpb.DeleteLogRequest, opts ...gax.CallOption) error {
ctx = insertMetadata(ctx, c.xGoogMetadata)
opts = append(c.CallOptions.DeleteLog[0:len(c.CallOptions.DeleteLog):len(c.CallOptions.DeleteLog)], opts...)
err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error {
var err error
_, err = c.client.DeleteLog(ctx, req)
_, err = c.client.DeleteLog(ctx, req, settings.GRPC...)
return err
}, c.CallOptions.DeleteLog...)
}, opts...)
return err
}
// WriteLogEntries writes log entries to Stackdriver Logging. All log entries are
// written by this method.
func (c *Client) WriteLogEntries(ctx context.Context, req *loggingpb.WriteLogEntriesRequest) (*loggingpb.WriteLogEntriesResponse, error) {
md, _ := metadata.FromContext(ctx)
ctx = metadata.NewContext(ctx, metadata.Join(md, c.metadata))
// WriteLogEntries ## Log entry resources
//
// Writes log entries to Stackdriver Logging. This API method is the
// only way to send log entries to Stackdriver Logging. This method
// is used, directly or indirectly, by the Stackdriver Logging agent
// (fluentd) and all logging libraries configured to use Stackdriver
// Logging.
func (c *Client) WriteLogEntries(ctx context.Context, req *loggingpb.WriteLogEntriesRequest, opts ...gax.CallOption) (*loggingpb.WriteLogEntriesResponse, error) {
ctx = insertMetadata(ctx, c.xGoogMetadata)
opts = append(c.CallOptions.WriteLogEntries[0:len(c.CallOptions.WriteLogEntries):len(c.CallOptions.WriteLogEntries)], opts...)
var resp *loggingpb.WriteLogEntriesResponse
err := gax.Invoke(ctx, func(ctx context.Context) error {
err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error {
var err error
resp, err = c.client.WriteLogEntries(ctx, req)
resp, err = c.client.WriteLogEntries(ctx, req, settings.GRPC...)
return err
}, c.CallOptions.WriteLogEntries...)
}, opts...)
if err != nil {
return nil, err
}
return resp, nil
}
// ListLogEntries lists log entries. Use this method to retrieve log entries from Cloud
// Logging. For ways to export log entries, see
// [Exporting Logs](/logging/docs/export).
func (c *Client) ListLogEntries(ctx context.Context, req *loggingpb.ListLogEntriesRequest) *LogEntryIterator {
md, _ := metadata.FromContext(ctx)
ctx = metadata.NewContext(ctx, metadata.Join(md, c.metadata))
// ListLogEntries lists log entries. Use this method to retrieve log entries from
// Stackdriver Logging. For ways to export log entries, see
// Exporting Logs (at /logging/docs/export).
func (c *Client) ListLogEntries(ctx context.Context, req *loggingpb.ListLogEntriesRequest, opts ...gax.CallOption) *LogEntryIterator {
ctx = insertMetadata(ctx, c.xGoogMetadata)
opts = append(c.CallOptions.ListLogEntries[0:len(c.CallOptions.ListLogEntries):len(c.CallOptions.ListLogEntries)], opts...)
it := &LogEntryIterator{}
it.InternalFetch = func(pageSize int, pageToken string) ([]*loggingpb.LogEntry, string, error) {
var resp *loggingpb.ListLogEntriesResponse
@ -217,11 +192,11 @@ func (c *Client) ListLogEntries(ctx context.Context, req *loggingpb.ListLogEntri
} else {
req.PageSize = int32(pageSize)
}
err := gax.Invoke(ctx, func(ctx context.Context) error {
err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error {
var err error
resp, err = c.client.ListLogEntries(ctx, req)
resp, err = c.client.ListLogEntries(ctx, req, settings.GRPC...)
return err
}, c.CallOptions.ListLogEntries...)
}, opts...)
if err != nil {
return nil, "", err
}
@ -239,10 +214,11 @@ func (c *Client) ListLogEntries(ctx context.Context, req *loggingpb.ListLogEntri
return it
}
// ListMonitoredResourceDescriptors lists the monitored resource descriptors used by Stackdriver Logging.
func (c *Client) ListMonitoredResourceDescriptors(ctx context.Context, req *loggingpb.ListMonitoredResourceDescriptorsRequest) *MonitoredResourceDescriptorIterator {
md, _ := metadata.FromContext(ctx)
ctx = metadata.NewContext(ctx, metadata.Join(md, c.metadata))
// ListMonitoredResourceDescriptors lists the descriptors for monitored resource types used by Stackdriver
// Logging.
func (c *Client) ListMonitoredResourceDescriptors(ctx context.Context, req *loggingpb.ListMonitoredResourceDescriptorsRequest, opts ...gax.CallOption) *MonitoredResourceDescriptorIterator {
ctx = insertMetadata(ctx, c.xGoogMetadata)
opts = append(c.CallOptions.ListMonitoredResourceDescriptors[0:len(c.CallOptions.ListMonitoredResourceDescriptors):len(c.CallOptions.ListMonitoredResourceDescriptors)], opts...)
it := &MonitoredResourceDescriptorIterator{}
it.InternalFetch = func(pageSize int, pageToken string) ([]*monitoredrespb.MonitoredResourceDescriptor, string, error) {
var resp *loggingpb.ListMonitoredResourceDescriptorsResponse
@ -252,11 +228,11 @@ func (c *Client) ListMonitoredResourceDescriptors(ctx context.Context, req *logg
} else {
req.PageSize = int32(pageSize)
}
err := gax.Invoke(ctx, func(ctx context.Context) error {
err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error {
var err error
resp, err = c.client.ListMonitoredResourceDescriptors(ctx, req)
resp, err = c.client.ListMonitoredResourceDescriptors(ctx, req, settings.GRPC...)
return err
}, c.CallOptions.ListMonitoredResourceDescriptors...)
}, opts...)
if err != nil {
return nil, "", err
}
@ -274,6 +250,42 @@ func (c *Client) ListMonitoredResourceDescriptors(ctx context.Context, req *logg
return it
}
// ListLogs lists the logs in projects, organizations, folders, or billing accounts.
// Only logs that have entries are listed.
func (c *Client) ListLogs(ctx context.Context, req *loggingpb.ListLogsRequest, opts ...gax.CallOption) *StringIterator {
ctx = insertMetadata(ctx, c.xGoogMetadata)
opts = append(c.CallOptions.ListLogs[0:len(c.CallOptions.ListLogs):len(c.CallOptions.ListLogs)], opts...)
it := &StringIterator{}
it.InternalFetch = func(pageSize int, pageToken string) ([]string, string, error) {
var resp *loggingpb.ListLogsResponse
req.PageToken = pageToken
if pageSize > math.MaxInt32 {
req.PageSize = math.MaxInt32
} else {
req.PageSize = int32(pageSize)
}
err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error {
var err error
resp, err = c.client.ListLogs(ctx, req, settings.GRPC...)
return err
}, opts...)
if err != nil {
return nil, "", err
}
return resp.LogNames, resp.NextPageToken, nil
}
fetch := func(pageSize int, pageToken string) (string, error) {
items, nextPageToken, err := it.InternalFetch(pageSize, pageToken)
if err != nil {
return "", err
}
it.items = append(it.items, items...)
return nextPageToken, nil
}
it.pageInfo, it.nextFunc = iterator.NewPageInfo(fetch, it.bufLen, it.takeBuf)
return it
}
// LogEntryIterator manages a stream of *loggingpb.LogEntry.
type LogEntryIterator struct {
items []*loggingpb.LogEntry
@ -357,3 +369,45 @@ func (it *MonitoredResourceDescriptorIterator) takeBuf() interface{} {
it.items = nil
return b
}
// StringIterator manages a stream of string.
type StringIterator struct {
items []string
pageInfo *iterator.PageInfo
nextFunc func() error
// InternalFetch is for use by the Google Cloud Libraries only.
// It is not part of the stable interface of this package.
//
// InternalFetch returns results from a single call to the underlying RPC.
// The number of results is no greater than pageSize.
// If there are no more results, nextPageToken is empty and err is nil.
InternalFetch func(pageSize int, pageToken string) (results []string, nextPageToken string, err error)
}
// PageInfo supports pagination. See the google.golang.org/api/iterator package for details.
func (it *StringIterator) PageInfo() *iterator.PageInfo {
return it.pageInfo
}
// Next returns the next result. Its second return value is iterator.Done if there are no more
// results. Once Next returns Done, all subsequent calls will return Done.
func (it *StringIterator) Next() (string, error) {
var item string
if err := it.nextFunc(); err != nil {
return item, err
}
item = it.items[0]
it.items = it.items[1:]
return item, nil
}
func (it *StringIterator) bufLen() int {
return len(it.items)
}
func (it *StringIterator) takeBuf() interface{} {
b := it.items
it.items = nil
return b
}

View file

@ -1,10 +1,10 @@
// Copyright 2016, Google Inc. All rights reserved.
// Copyright 2018 Google LLC
//
// 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
// https://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,
@ -17,12 +17,10 @@
package logging
import (
"fmt"
"math"
"runtime"
"strings"
"time"
"cloud.google.com/go/internal/version"
gax "github.com/googleapis/gax-go"
"golang.org/x/net/context"
"google.golang.org/api/iterator"
@ -34,11 +32,6 @@ import (
"google.golang.org/grpc/metadata"
)
var (
metricsParentPathTemplate = gax.MustCompilePathTemplate("projects/{project}")
metricsMetricPathTemplate = gax.MustCompilePathTemplate("projects/{project}/metrics/{metric}")
)
// MetricsCallOptions contains the retry settings for each method of MetricsClient.
type MetricsCallOptions struct {
ListLogMetrics []gax.CallOption
@ -51,13 +44,7 @@ type MetricsCallOptions struct {
func defaultMetricsClientOptions() []option.ClientOption {
return []option.ClientOption{
option.WithEndpoint("logging.googleapis.com:443"),
option.WithScopes(
"https://www.googleapis.com/auth/cloud-platform",
"https://www.googleapis.com/auth/cloud-platform.read-only",
"https://www.googleapis.com/auth/logging.admin",
"https://www.googleapis.com/auth/logging.read",
"https://www.googleapis.com/auth/logging.write",
),
option.WithScopes(DefaultAuthScopes()...),
}
}
@ -67,6 +54,7 @@ func defaultMetricsCallOptions() *MetricsCallOptions {
gax.WithRetry(func() gax.Retryer {
return gax.OnCodes([]codes.Code{
codes.DeadlineExceeded,
codes.Internal,
codes.Unavailable,
}, gax.Backoff{
Initial: 100 * time.Millisecond,
@ -96,8 +84,8 @@ type MetricsClient struct {
// The call options for this service.
CallOptions *MetricsCallOptions
// The metadata to be sent with each request.
metadata metadata.MD
// The x-goog-* metadata to be sent with each request.
xGoogMetadata metadata.MD
}
// NewMetricsClient creates a new metrics service v2 client.
@ -114,7 +102,7 @@ func NewMetricsClient(ctx context.Context, opts ...option.ClientOption) (*Metric
metricsClient: loggingpb.NewMetricsServiceV2Client(conn),
}
c.SetGoogleClientInfo("gax", gax.Version)
c.SetGoogleClientInfo()
return c, nil
}
@ -132,39 +120,16 @@ func (c *MetricsClient) Close() error {
// SetGoogleClientInfo sets the name and version of the application in
// the `x-goog-api-client` header passed on each request. Intended for
// use by Google-written clients.
func (c *MetricsClient) SetGoogleClientInfo(name, version string) {
goVersion := strings.Replace(runtime.Version(), " ", "_", -1)
v := fmt.Sprintf("%s/%s %s gax/%s go/%s", name, version, gapicNameVersion, gax.Version, goVersion)
c.metadata = metadata.Pairs("x-goog-api-client", v)
}
// MetricsParentPath returns the path for the parent resource.
func MetricsParentPath(project string) string {
path, err := metricsParentPathTemplate.Render(map[string]string{
"project": project,
})
if err != nil {
panic(err)
}
return path
}
// MetricsMetricPath returns the path for the metric resource.
func MetricsMetricPath(project, metric string) string {
path, err := metricsMetricPathTemplate.Render(map[string]string{
"project": project,
"metric": metric,
})
if err != nil {
panic(err)
}
return path
func (c *MetricsClient) SetGoogleClientInfo(keyval ...string) {
kv := append([]string{"gl-go", version.Go()}, keyval...)
kv = append(kv, "gapic", version.Repo, "gax", gax.Version, "grpc", grpc.Version)
c.xGoogMetadata = metadata.Pairs("x-goog-api-client", gax.XGoogHeader(kv...))
}
// ListLogMetrics lists logs-based metrics.
func (c *MetricsClient) ListLogMetrics(ctx context.Context, req *loggingpb.ListLogMetricsRequest) *LogMetricIterator {
md, _ := metadata.FromContext(ctx)
ctx = metadata.NewContext(ctx, metadata.Join(md, c.metadata))
func (c *MetricsClient) ListLogMetrics(ctx context.Context, req *loggingpb.ListLogMetricsRequest, opts ...gax.CallOption) *LogMetricIterator {
ctx = insertMetadata(ctx, c.xGoogMetadata)
opts = append(c.CallOptions.ListLogMetrics[0:len(c.CallOptions.ListLogMetrics):len(c.CallOptions.ListLogMetrics)], opts...)
it := &LogMetricIterator{}
it.InternalFetch = func(pageSize int, pageToken string) ([]*loggingpb.LogMetric, string, error) {
var resp *loggingpb.ListLogMetricsResponse
@ -174,11 +139,11 @@ func (c *MetricsClient) ListLogMetrics(ctx context.Context, req *loggingpb.ListL
} else {
req.PageSize = int32(pageSize)
}
err := gax.Invoke(ctx, func(ctx context.Context) error {
err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error {
var err error
resp, err = c.metricsClient.ListLogMetrics(ctx, req)
resp, err = c.metricsClient.ListLogMetrics(ctx, req, settings.GRPC...)
return err
}, c.CallOptions.ListLogMetrics...)
}, opts...)
if err != nil {
return nil, "", err
}
@ -197,15 +162,15 @@ func (c *MetricsClient) ListLogMetrics(ctx context.Context, req *loggingpb.ListL
}
// GetLogMetric gets a logs-based metric.
func (c *MetricsClient) GetLogMetric(ctx context.Context, req *loggingpb.GetLogMetricRequest) (*loggingpb.LogMetric, error) {
md, _ := metadata.FromContext(ctx)
ctx = metadata.NewContext(ctx, metadata.Join(md, c.metadata))
func (c *MetricsClient) GetLogMetric(ctx context.Context, req *loggingpb.GetLogMetricRequest, opts ...gax.CallOption) (*loggingpb.LogMetric, error) {
ctx = insertMetadata(ctx, c.xGoogMetadata)
opts = append(c.CallOptions.GetLogMetric[0:len(c.CallOptions.GetLogMetric):len(c.CallOptions.GetLogMetric)], opts...)
var resp *loggingpb.LogMetric
err := gax.Invoke(ctx, func(ctx context.Context) error {
err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error {
var err error
resp, err = c.metricsClient.GetLogMetric(ctx, req)
resp, err = c.metricsClient.GetLogMetric(ctx, req, settings.GRPC...)
return err
}, c.CallOptions.GetLogMetric...)
}, opts...)
if err != nil {
return nil, err
}
@ -213,15 +178,15 @@ func (c *MetricsClient) GetLogMetric(ctx context.Context, req *loggingpb.GetLogM
}
// CreateLogMetric creates a logs-based metric.
func (c *MetricsClient) CreateLogMetric(ctx context.Context, req *loggingpb.CreateLogMetricRequest) (*loggingpb.LogMetric, error) {
md, _ := metadata.FromContext(ctx)
ctx = metadata.NewContext(ctx, metadata.Join(md, c.metadata))
func (c *MetricsClient) CreateLogMetric(ctx context.Context, req *loggingpb.CreateLogMetricRequest, opts ...gax.CallOption) (*loggingpb.LogMetric, error) {
ctx = insertMetadata(ctx, c.xGoogMetadata)
opts = append(c.CallOptions.CreateLogMetric[0:len(c.CallOptions.CreateLogMetric):len(c.CallOptions.CreateLogMetric)], opts...)
var resp *loggingpb.LogMetric
err := gax.Invoke(ctx, func(ctx context.Context) error {
err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error {
var err error
resp, err = c.metricsClient.CreateLogMetric(ctx, req)
resp, err = c.metricsClient.CreateLogMetric(ctx, req, settings.GRPC...)
return err
}, c.CallOptions.CreateLogMetric...)
}, opts...)
if err != nil {
return nil, err
}
@ -229,15 +194,15 @@ func (c *MetricsClient) CreateLogMetric(ctx context.Context, req *loggingpb.Crea
}
// UpdateLogMetric creates or updates a logs-based metric.
func (c *MetricsClient) UpdateLogMetric(ctx context.Context, req *loggingpb.UpdateLogMetricRequest) (*loggingpb.LogMetric, error) {
md, _ := metadata.FromContext(ctx)
ctx = metadata.NewContext(ctx, metadata.Join(md, c.metadata))
func (c *MetricsClient) UpdateLogMetric(ctx context.Context, req *loggingpb.UpdateLogMetricRequest, opts ...gax.CallOption) (*loggingpb.LogMetric, error) {
ctx = insertMetadata(ctx, c.xGoogMetadata)
opts = append(c.CallOptions.UpdateLogMetric[0:len(c.CallOptions.UpdateLogMetric):len(c.CallOptions.UpdateLogMetric)], opts...)
var resp *loggingpb.LogMetric
err := gax.Invoke(ctx, func(ctx context.Context) error {
err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error {
var err error
resp, err = c.metricsClient.UpdateLogMetric(ctx, req)
resp, err = c.metricsClient.UpdateLogMetric(ctx, req, settings.GRPC...)
return err
}, c.CallOptions.UpdateLogMetric...)
}, opts...)
if err != nil {
return nil, err
}
@ -245,14 +210,14 @@ func (c *MetricsClient) UpdateLogMetric(ctx context.Context, req *loggingpb.Upda
}
// DeleteLogMetric deletes a logs-based metric.
func (c *MetricsClient) DeleteLogMetric(ctx context.Context, req *loggingpb.DeleteLogMetricRequest) error {
md, _ := metadata.FromContext(ctx)
ctx = metadata.NewContext(ctx, metadata.Join(md, c.metadata))
err := gax.Invoke(ctx, func(ctx context.Context) error {
func (c *MetricsClient) DeleteLogMetric(ctx context.Context, req *loggingpb.DeleteLogMetricRequest, opts ...gax.CallOption) error {
ctx = insertMetadata(ctx, c.xGoogMetadata)
opts = append(c.CallOptions.DeleteLogMetric[0:len(c.CallOptions.DeleteLogMetric):len(c.CallOptions.DeleteLogMetric)], opts...)
err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error {
var err error
_, err = c.metricsClient.DeleteLogMetric(ctx, req)
_, err = c.metricsClient.DeleteLogMetric(ctx, req, settings.GRPC...)
return err
}, c.CallOptions.DeleteLogMetric...)
}, opts...)
return err
}

107
vendor/cloud.google.com/go/logging/apiv2/path_funcs.go generated vendored Normal file
View file

@ -0,0 +1,107 @@
// Copyright 2018 Google LLC
//
// 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
//
// https://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 logging
// ConfigProjectPath returns the path for the project resource.
//
// Deprecated: Use
// fmt.Sprintf("projects/%s", project)
// instead.
func ConfigProjectPath(project string) string {
return "" +
"projects/" +
project +
""
}
// ConfigSinkPath returns the path for the sink resource.
//
// Deprecated: Use
// fmt.Sprintf("projects/%s/sinks/%s", project, sink)
// instead.
func ConfigSinkPath(project, sink string) string {
return "" +
"projects/" +
project +
"/sinks/" +
sink +
""
}
// ConfigExclusionPath returns the path for the exclusion resource.
//
// Deprecated: Use
// fmt.Sprintf("projects/%s/exclusions/%s", project, exclusion)
// instead.
func ConfigExclusionPath(project, exclusion string) string {
return "" +
"projects/" +
project +
"/exclusions/" +
exclusion +
""
}
// ProjectPath returns the path for the project resource.
//
// Deprecated: Use
// fmt.Sprintf("projects/%s", project)
// instead.
func ProjectPath(project string) string {
return "" +
"projects/" +
project +
""
}
// LogPath returns the path for the log resource.
//
// Deprecated: Use
// fmt.Sprintf("projects/%s/logs/%s", project, log)
// instead.
func LogPath(project, log string) string {
return "" +
"projects/" +
project +
"/logs/" +
log +
""
}
// MetricsProjectPath returns the path for the project resource.
//
// Deprecated: Use
// fmt.Sprintf("projects/%s", project)
// instead.
func MetricsProjectPath(project string) string {
return "" +
"projects/" +
project +
""
}
// MetricsMetricPath returns the path for the metric resource.
//
// Deprecated: Use
// fmt.Sprintf("projects/%s/metrics/%s", project, metric)
// instead.
func MetricsMetricPath(project, metric string) string {
return "" +
"projects/" +
project +
"/metrics/" +
metric +
""
}

View file

@ -20,7 +20,8 @@ see package cloud.google.com/go/logging/logadmin.
This client uses Logging API v2.
See https://cloud.google.com/logging/docs/api/v2/ for an introduction to the API.
This package is experimental and subject to API changes.
Note: This package is in beta. Some backwards-incompatible changes may occur.
Creating a Client
@ -37,7 +38,7 @@ Use a Client to interact with the Stackdriver Logging API.
Basic Usage
For most use-cases, you'll want to add log entries to a buffer to be periodically
For most use cases, you'll want to add log entries to a buffer to be periodically
flushed (automatically and asynchronously) to the Stackdriver Logging service.
// Initialize a logger
@ -62,11 +63,28 @@ Synchronous Logging
For critical errors, you may want to send your log entries immediately.
LogSync is slow and will block until the log entry has been sent, so it is
not recommended for basic use.
not recommended for normal use.
lg.LogSync(ctx, logging.Entry{Payload: "ALERT! Something critical happened!"})
Payloads
An entry payload can be a string, as in the examples above. It can also be any value
that can be marshaled to a JSON object, like a map[string]interface{} or a struct:
type MyEntry struct {
Name string
Count int
}
lg.Log(logging.Entry{Payload: MyEntry{Name: "Bob", Count: 3}})
If you have a []byte of JSON, wrap it in json.RawMessage:
j := []byte(`{"Name": "Bob", "Count": 3}`)
lg.Log(logging.Entry{Payload: json.RawMessage(j)})
The Standard Logger Interface
You may want use a standard log.Logger in your program.
@ -85,5 +103,15 @@ An Entry may have one of a number of severity levels associated with it.
Severity: logging.Critical,
}
Viewing Logs
You can view Stackdriver logs for projects at
https://console.cloud.google.com/logs/viewer. Use the dropdown at the top left. When
running from a Google Cloud Platform VM, select "GCE VM Instance". Otherwise, select
"Google Project" and then the project ID. Logs for organizations, folders and billing
accounts can be viewed on the command line with the "gcloud logging read" command.
*/
package logging // import "cloud.google.com/go/logging"

View file

@ -28,3 +28,12 @@ func LogPath(parent, logID string) string {
logID = strings.Replace(logID, "/", "%2F", -1)
return fmt.Sprintf("%s/logs/%s", parent, logID)
}
func LogIDFromPath(parent, path string) string {
start := len(parent) + len("/logs/")
if len(path) < start {
return ""
}
logID := path[start:]
return strings.Replace(logID, "%2F", "/", -1)
}

View file

@ -36,6 +36,8 @@ import (
"sync"
"time"
"cloud.google.com/go/compute/metadata"
"cloud.google.com/go/internal/version"
vkit "cloud.google.com/go/logging/apiv2"
"cloud.google.com/go/logging/internal"
"github.com/golang/protobuf/proto"
@ -77,6 +79,12 @@ const (
// DefaultBufferedByteLimit is the default value for the BufferedByteLimit LoggerOption.
DefaultBufferedByteLimit = 1 << 30 // 1GiB
// defaultWriteTimeout is the timeout for the underlying write API calls. As
// write API calls are not idempotent, they are not retried on timeout. This
// timeout is to allow clients to degrade gracefully if underlying logging
// service is temporarily impaired for some reason.
defaultWriteTimeout = 10 * time.Minute
)
// For testing:
@ -84,16 +92,24 @@ var now = time.Now
// ErrOverflow signals that the number of buffered entries for a Logger
// exceeds its BufferLimit.
var ErrOverflow = errors.New("logging: log entry overflowed buffer limits")
var ErrOverflow = bundler.ErrOverflow
// ErrOversizedEntry signals that an entry's size exceeds the maximum number of
// bytes that will be sent in a single call to the logging service.
var ErrOversizedEntry = bundler.ErrOversizedItem
// Client is a Logging client. A Client is associated with a single Cloud project.
type Client struct {
client *vkit.Client // client for the logging service
projectID string
errc chan error // should be buffered to minimize dropped errors
donec chan struct{} // closed on Client.Close to close Logger bundlers
loggers sync.WaitGroup // so we can wait for loggers to close
closed bool
client *vkit.Client // client for the logging service
parent string // e.g. "projects/proj-id"
errc chan error // should be buffered to minimize dropped errors
donec chan struct{} // closed on Client.Close to close Logger bundlers
loggers sync.WaitGroup // so we can wait for loggers to close
closed bool
mu sync.Mutex
nErrs int // number of errors we saw
lastErr error // last error we saw
// OnError is called when an error occurs in a call to Log or Flush. The
// error may be due to an invalid Entry, an overflow because BufferLimit
@ -107,15 +123,20 @@ type Client struct {
OnError func(err error)
}
// NewClient returns a new logging client associated with the provided project ID.
// NewClient returns a new logging client associated with the provided parent.
// A parent can take any of the following forms:
// projects/PROJECT_ID
// folders/FOLDER_ID
// billingAccounts/ACCOUNT_ID
// organizations/ORG_ID
// for backwards compatibility, a string with no '/' is also allowed and is interpreted
// as a project ID.
//
// By default NewClient uses WriteScope. To use a different scope, call
// NewClient using a WithScopes option (see https://godoc.org/google.golang.org/api/option#WithScopes).
func NewClient(ctx context.Context, projectID string, opts ...option.ClientOption) (*Client, error) {
// Check for '/' in project ID to reserve the ability to support various owning resources,
// in the form "{Collection}/{Name}", for instance "organizations/my-org".
if strings.ContainsRune(projectID, '/') {
return nil, errors.New("logging: project ID contains '/'")
func NewClient(ctx context.Context, parent string, opts ...option.ClientOption) (*Client, error) {
if !strings.ContainsRune(parent, '/') {
parent = "projects/" + parent
}
opts = append([]option.ClientOption{
option.WithEndpoint(internal.ProdAddr),
@ -125,13 +146,13 @@ func NewClient(ctx context.Context, projectID string, opts ...option.ClientOptio
if err != nil {
return nil, err
}
c.SetGoogleClientInfo("logging", internal.Version)
c.SetGoogleClientInfo("gccl", version.Repo)
client := &Client{
client: c,
projectID: projectID,
errc: make(chan error, defaultErrorCapacity), // create a small buffer for errors
donec: make(chan struct{}),
OnError: func(e error) { log.Printf("logging client: %v", e) },
client: c,
parent: parent,
errc: make(chan error, defaultErrorCapacity), // create a small buffer for errors
donec: make(chan struct{}),
OnError: func(e error) { log.Printf("logging client: %v", e) },
}
// Call the user's function synchronously, to make life easier for them.
go func() {
@ -143,18 +164,13 @@ func NewClient(ctx context.Context, projectID string, opts ...option.ClientOptio
if fn := client.OnError; fn != nil {
fn(err)
} else {
log.Printf("logging (project ID %q): %v", projectID, err)
log.Printf("logging (parent %q): %v", parent, err)
}
}
}()
return client, nil
}
// parent returns the string used in many RPCs to denote the parent resource of the log.
func (c *Client) parent() string {
return "projects/" + c.projectID
}
var unixZeroTimestamp *tspb.Timestamp
func init() {
@ -170,18 +186,43 @@ func init() {
// log entry "ping" to a log named "ping".
func (c *Client) Ping(ctx context.Context) error {
ent := &logpb.LogEntry{
Payload: &logpb.LogEntry_TextPayload{"ping"},
Payload: &logpb.LogEntry_TextPayload{TextPayload: "ping"},
Timestamp: unixZeroTimestamp, // Identical timestamps and insert IDs are both
InsertId: "ping", // necessary for the service to dedup these entries.
}
_, err := c.client.WriteLogEntries(ctx, &logpb.WriteLogEntriesRequest{
LogName: internal.LogPath(c.parent(), "ping"),
Resource: &mrpb.MonitoredResource{Type: "global"},
LogName: internal.LogPath(c.parent, "ping"),
Resource: monitoredResource(c.parent),
Entries: []*logpb.LogEntry{ent},
})
return err
}
// error puts the error on the client's error channel
// without blocking, and records summary error info.
func (c *Client) error(err error) {
select {
case c.errc <- err:
default:
}
c.mu.Lock()
c.lastErr = err
c.nErrs++
c.mu.Unlock()
}
func (c *Client) extractErrorInfo() error {
var err error
c.mu.Lock()
if c.lastErr != nil {
err = fmt.Errorf("saw %d errors; last: %v", c.nErrs, c.lastErr)
c.nErrs = 0
c.lastErr = nil
}
c.mu.Unlock()
return err
}
// A Logger is used to write log messages to a single log. It can be configured
// with a log ID, common monitored resource, and a set of common labels.
type Logger struct {
@ -193,6 +234,7 @@ type Logger struct {
// Options
commonResource *mrpb.MonitoredResource
commonLabels map[string]string
writeTimeout time.Duration
}
// A LoggerOption is a configuration option for a Logger.
@ -201,14 +243,80 @@ type LoggerOption interface {
}
// CommonResource sets the monitored resource associated with all log entries
// written from a Logger. If not provided, a resource of type "global" is used.
// This value can be overridden by setting an Entry's Resource field.
// written from a Logger. If not provided, the resource is automatically
// detected based on the running environment. This value can be overridden
// per-entry by setting an Entry's Resource field.
func CommonResource(r *mrpb.MonitoredResource) LoggerOption { return commonResource{r} }
type commonResource struct{ *mrpb.MonitoredResource }
func (r commonResource) set(l *Logger) { l.commonResource = r.MonitoredResource }
var detectedResource struct {
pb *mrpb.MonitoredResource
once sync.Once
}
func detectResource() *mrpb.MonitoredResource {
detectedResource.once.Do(func() {
if !metadata.OnGCE() {
return
}
projectID, err := metadata.ProjectID()
if err != nil {
return
}
id, err := metadata.InstanceID()
if err != nil {
return
}
zone, err := metadata.Zone()
if err != nil {
return
}
detectedResource.pb = &mrpb.MonitoredResource{
Type: "gce_instance",
Labels: map[string]string{
"project_id": projectID,
"instance_id": id,
"zone": zone,
},
}
})
return detectedResource.pb
}
var resourceInfo = map[string]struct{ rtype, label string }{
"organizations": {"organization", "organization_id"},
"folders": {"folder", "folder_id"},
"projects": {"project", "project_id"},
"billingAccounts": {"billing_account", "account_id"},
}
func monitoredResource(parent string) *mrpb.MonitoredResource {
parts := strings.SplitN(parent, "/", 2)
if len(parts) != 2 {
return globalResource(parent)
}
info, ok := resourceInfo[parts[0]]
if !ok {
return globalResource(parts[1])
}
return &mrpb.MonitoredResource{
Type: info.rtype,
Labels: map[string]string{info.label: parts[1]},
}
}
func globalResource(projectID string) *mrpb.MonitoredResource {
return &mrpb.MonitoredResource{
Type: "global",
Labels: map[string]string{
"project_id": projectID,
},
}
}
// CommonLabels are labels that apply to all log entries written from a Logger,
// so that you don't have to repeat them in each log entry's Labels field. If
// any of the log entries contains a (key, value) with the same key that is in
@ -220,6 +328,15 @@ type commonLabels map[string]string
func (c commonLabels) set(l *Logger) { l.commonLabels = c }
// ConcurrentWriteLimit determines how many goroutines will send log entries to the
// underlying service. The default is 1. Set ConcurrentWriteLimit to a higher value to
// increase throughput.
func ConcurrentWriteLimit(n int) LoggerOption { return concurrentWriteLimit(n) }
type concurrentWriteLimit int
func (c concurrentWriteLimit) set(l *Logger) { l.bundler.HandlerLimit = int(c) }
// DelayThreshold is the maximum amount of time that an entry should remain
// buffered in memory before a call to the logging service is triggered. Larger
// values of DelayThreshold will generally result in fewer calls to the logging
@ -256,10 +373,10 @@ type entryByteThreshold int
func (e entryByteThreshold) set(l *Logger) { l.bundler.BundleByteThreshold = int(e) }
// EntryByteLimit is the maximum number of bytes of entries that will be sent
// in a single call to the logging service. This option limits the size of a
// single RPC payload, to account for network or service issues with large
// RPCs. If EntryByteLimit is smaller than EntryByteThreshold, the latter has
// no effect.
// in a single call to the logging service. ErrOversizedEntry is returned if an
// entry exceeds EntryByteLimit. This option limits the size of a single RPC
// payload, to account for network or service issues with large RPCs. If
// EntryByteLimit is smaller than EntryByteThreshold, the latter has no effect.
// The default is zero, meaning there is no limit.
func EntryByteLimit(n int) LoggerOption { return entryByteLimit(n) }
@ -287,15 +404,17 @@ func (b bufferedByteLimit) set(l *Logger) { l.bundler.BufferedByteLimit = int(b)
// characters: [A-Za-z0-9]; and punctuation characters: forward-slash,
// underscore, hyphen, and period.
func (c *Client) Logger(logID string, opts ...LoggerOption) *Logger {
r := detectResource()
if r == nil {
r = monitoredResource(c.parent)
}
l := &Logger{
client: c,
logName: internal.LogPath(c.parent(), logID),
commonResource: &mrpb.MonitoredResource{Type: "global"},
logName: internal.LogPath(c.parent, logID),
commonResource: r,
}
// TODO(jba): determine the right context for the bundle handler.
ctx := context.TODO()
l.bundler = bundler.NewBundler(&logpb.LogEntry{}, func(entries interface{}) {
l.writeLogEntries(ctx, entries.([]*logpb.LogEntry))
l.writeLogEntries(entries.([]*logpb.LogEntry))
})
l.bundler.DelayThreshold = DefaultDelayThreshold
l.bundler.BundleCountThreshold = DefaultEntryCountThreshold
@ -304,16 +423,18 @@ func (c *Client) Logger(logID string, opts ...LoggerOption) *Logger {
for _, opt := range opts {
opt.set(l)
}
l.stdLoggers = map[Severity]*log.Logger{}
for s := range severityName {
l.stdLoggers[s] = log.New(severityWriter{l, s}, "", 0)
}
c.loggers.Add(1)
// Start a goroutine that cleans up the bundler, its channel
// and the writer goroutines when the client is closed.
go func() {
defer c.loggers.Done()
<-c.donec
l.bundler.Close()
l.bundler.Flush()
}()
return l
}
@ -331,7 +452,7 @@ func (w severityWriter) Write(p []byte) (n int, err error) {
return len(p), nil
}
// Close closes the client.
// Close waits for all opened loggers to be flushed and closes the client.
func (c *Client) Close() error {
if c.closed {
return nil
@ -340,9 +461,12 @@ func (c *Client) Close() error {
c.loggers.Wait() // wait for all bundlers to flush and close
// Now there can be no more errors.
close(c.errc) // terminate error goroutine
// Return only the first error. Since all clients share an underlying connection,
// Closes after the first always report a "connection is closing" error.
err := c.client.Close()
// Prefer errors arising from logging to the error returned from Close.
err := c.extractErrorInfo()
err2 := c.client.Close()
if err == nil {
err = err2
}
c.closed = true
return err
}
@ -417,9 +541,8 @@ type Entry struct {
// The zero value is Default.
Severity Severity
// Payload must be either a string or something that
// marshals via the encoding/json package to a JSON object
// (and not any other type of JSON value).
// Payload must be either a string, or something that marshals via the
// encoding/json package to a JSON object (and not any other type of JSON value).
Payload interface{}
// Labels optionally specifies key/value labels for the log entry.
@ -448,10 +571,13 @@ type Entry struct {
// reading entries. It is an error to set it when writing entries.
LogName string
// Resource is the monitored resource associated with the entry. It is set
// by the client when reading entries. It is an error to set it when
// writing entries.
// Resource is the monitored resource associated with the entry.
Resource *mrpb.MonitoredResource
// Trace is the resource name of the trace associated with the log entry,
// if any. If it contains a relative resource name, the name is assumed to
// be relative to //tracing.googleapis.com.
Trace string
}
// HTTPRequest contains an http.Request as well as additional
@ -476,6 +602,10 @@ type HTTPRequest struct {
// received until the response was sent.
Latency time.Duration
// LocalIP is the IP address (IPv4 or IPv6) of the origin server that the request
// was sent to.
LocalIP string
// RemoteIP is the IP address (IPv4 or IPv6) of the client that issued the
// HTTP request. Examples: "192.168.1.1", "FE80::0202:B3FF:FE1E:8329".
RemoteIP string
@ -499,19 +629,23 @@ func fromHTTPRequest(r *HTTPRequest) *logtypepb.HttpRequest {
}
u := *r.Request.URL
u.Fragment = ""
return &logtypepb.HttpRequest{
pb := &logtypepb.HttpRequest{
RequestMethod: r.Request.Method,
RequestUrl: u.String(),
RequestSize: r.RequestSize,
Status: int32(r.Status),
ResponseSize: r.ResponseSize,
Latency: ptypes.DurationProto(r.Latency),
UserAgent: r.Request.UserAgent(),
ServerIp: r.LocalIP,
RemoteIp: r.RemoteIP, // TODO(jba): attempt to parse http.Request.RemoteAddr?
Referer: r.Request.Referer(),
CacheHit: r.CacheHit,
CacheValidatedWithOriginServer: r.CacheValidatedWithOriginServer,
}
if r.Latency != 0 {
pb.Latency = ptypes.DurationProto(r.Latency)
}
return pb
}
// toProtoStruct converts v, which must marshal into a JSON object,
@ -521,13 +655,19 @@ func toProtoStruct(v interface{}) (*structpb.Struct, error) {
if s, ok := v.(*structpb.Struct); ok {
return s, nil
}
// v is a Go struct that supports JSON marshalling. We want a Struct
// v is a Go value that supports JSON marshalling. We want a Struct
// protobuf. Some day we may have a more direct way to get there, but right
// now the only way is to marshal the Go struct to JSON, unmarshal into a
// now the only way is to marshal the Go value to JSON, unmarshal into a
// map, and then build the Struct proto from the map.
jb, err := json.Marshal(v)
if err != nil {
return nil, fmt.Errorf("logging: json.Marshal: %v", err)
var jb []byte
var err error
if raw, ok := v.(json.RawMessage); ok { // needed for Go 1.7 and below
jb = []byte(raw)
} else {
jb, err = json.Marshal(v)
if err != nil {
return nil, fmt.Errorf("logging: json.Marshal: %v", err)
}
}
var m map[string]interface{}
err = json.Unmarshal(jb, &m)
@ -548,21 +688,21 @@ func jsonMapToProtoStruct(m map[string]interface{}) *structpb.Struct {
func jsonValueToStructValue(v interface{}) *structpb.Value {
switch x := v.(type) {
case bool:
return &structpb.Value{Kind: &structpb.Value_BoolValue{x}}
return &structpb.Value{Kind: &structpb.Value_BoolValue{BoolValue: x}}
case float64:
return &structpb.Value{Kind: &structpb.Value_NumberValue{x}}
return &structpb.Value{Kind: &structpb.Value_NumberValue{NumberValue: x}}
case string:
return &structpb.Value{Kind: &structpb.Value_StringValue{x}}
return &structpb.Value{Kind: &structpb.Value_StringValue{StringValue: x}}
case nil:
return &structpb.Value{Kind: &structpb.Value_NullValue{}}
case map[string]interface{}:
return &structpb.Value{Kind: &structpb.Value_StructValue{jsonMapToProtoStruct(x)}}
return &structpb.Value{Kind: &structpb.Value_StructValue{StructValue: jsonMapToProtoStruct(x)}}
case []interface{}:
var vals []*structpb.Value
for _, e := range x {
vals = append(vals, jsonValueToStructValue(e))
}
return &structpb.Value{Kind: &structpb.Value_ListValue{&structpb.ListValue{vals}}}
return &structpb.Value{Kind: &structpb.Value_ListValue{ListValue: &structpb.ListValue{Values: vals}}}
default:
panic(fmt.Sprintf("bad type %T for JSON value", v))
}
@ -590,38 +730,37 @@ func (l *Logger) LogSync(ctx context.Context, e Entry) error {
func (l *Logger) Log(e Entry) {
ent, err := toLogEntry(e)
if err != nil {
l.error(err)
l.client.error(err)
return
}
if err := l.bundler.Add(ent, proto.Size(ent)); err != nil {
l.error(err)
l.client.error(err)
}
}
// Flush blocks until all currently buffered log entries are sent.
func (l *Logger) Flush() {
//
// If any errors occurred since the last call to Flush from any Logger, or the
// creation of the client if this is the first call, then Flush returns a non-nil
// error with summary information about the errors. This information is unlikely to
// be actionable. For more accurate error reporting, set Client.OnError.
func (l *Logger) Flush() error {
l.bundler.Flush()
return l.client.extractErrorInfo()
}
func (l *Logger) writeLogEntries(ctx context.Context, entries []*logpb.LogEntry) {
func (l *Logger) writeLogEntries(entries []*logpb.LogEntry) {
req := &logpb.WriteLogEntriesRequest{
LogName: l.logName,
Resource: l.commonResource,
Labels: l.commonLabels,
Entries: entries,
}
ctx, cancel := context.WithTimeout(context.Background(), defaultWriteTimeout)
defer cancel()
_, err := l.client.client.WriteLogEntries(ctx, req)
if err != nil {
l.error(err)
}
}
// error puts the error on the client's error channel
// without blocking.
func (l *Logger) error(err error) {
select {
case l.client.errc <- err:
default:
l.client.error(err)
}
}
@ -658,17 +797,18 @@ func toLogEntry(e Entry) (*logpb.LogEntry, error) {
HttpRequest: fromHTTPRequest(e.HTTPRequest),
Operation: e.Operation,
Labels: e.Labels,
Trace: e.Trace,
Resource: e.Resource,
}
switch p := e.Payload.(type) {
case string:
ent.Payload = &logpb.LogEntry_TextPayload{p}
ent.Payload = &logpb.LogEntry_TextPayload{TextPayload: p}
default:
s, err := toProtoStruct(p)
if err != nil {
return nil, err
}
ent.Payload = &logpb.LogEntry_JsonPayload{s}
ent.Payload = &logpb.LogEntry_JsonPayload{JsonPayload: s}
}
return ent, nil
}

View file

@ -16,7 +16,6 @@ import (
//sys createIoCompletionPort(file syscall.Handle, port syscall.Handle, key uintptr, threadCount uint32) (newport syscall.Handle, err error) = CreateIoCompletionPort
//sys getQueuedCompletionStatus(port syscall.Handle, bytes *uint32, key *uintptr, o **ioOperation, timeout uint32) (err error) = GetQueuedCompletionStatus
//sys setFileCompletionNotificationModes(h syscall.Handle, flags uint8) (err error) = SetFileCompletionNotificationModes
//sys timeBeginPeriod(period uint32) (n int32) = winmm.timeBeginPeriod
type atomicBool int32
@ -153,8 +152,6 @@ func (f *win32File) prepareIo() (*ioOperation, error) {
// ioCompletionProcessor processes completed async IOs forever
func ioCompletionProcessor(h syscall.Handle) {
// Set the timer resolution to 1. This fixes a performance regression in golang 1.6.
timeBeginPeriod(1)
for {
var bytes uint32
var key uintptr

View file

@ -38,14 +38,12 @@ func errnoErr(e syscall.Errno) error {
var (
modkernel32 = windows.NewLazySystemDLL("kernel32.dll")
modwinmm = windows.NewLazySystemDLL("winmm.dll")
modadvapi32 = windows.NewLazySystemDLL("advapi32.dll")
procCancelIoEx = modkernel32.NewProc("CancelIoEx")
procCreateIoCompletionPort = modkernel32.NewProc("CreateIoCompletionPort")
procGetQueuedCompletionStatus = modkernel32.NewProc("GetQueuedCompletionStatus")
procSetFileCompletionNotificationModes = modkernel32.NewProc("SetFileCompletionNotificationModes")
proctimeBeginPeriod = modwinmm.NewProc("timeBeginPeriod")
procConnectNamedPipe = modkernel32.NewProc("ConnectNamedPipe")
procCreateNamedPipeW = modkernel32.NewProc("CreateNamedPipeW")
procCreateFileW = modkernel32.NewProc("CreateFileW")
@ -122,12 +120,6 @@ func setFileCompletionNotificationModes(h syscall.Handle, flags uint8) (err erro
return
}
func timeBeginPeriod(period uint32) (n int32) {
r0, _, _ := syscall.Syscall(proctimeBeginPeriod.Addr(), 1, uintptr(period), 0, 0)
n = int32(r0)
return
}
func connectNamedPipe(pipe syscall.Handle, o *syscall.Overlapped) (err error) {
r1, _, e1 := syscall.Syscall(procConnectNamedPipe.Addr(), 2, uintptr(pipe), uintptr(unsafe.Pointer(o)), 0)
if r1 == 0 {

View file

@ -1,3 +1,19 @@
/*
Copyright The containerd Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package console
import (

View file

@ -1,5 +1,21 @@
// +build linux
/*
Copyright The containerd Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package console
import (

View file

@ -1,4 +1,20 @@
// +build darwin freebsd linux solaris
// +build darwin freebsd linux openbsd solaris
/*
Copyright The containerd Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package console

View file

@ -1,3 +1,19 @@
/*
Copyright The containerd Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package console
import (

View file

@ -1,3 +1,19 @@
/*
Copyright The containerd Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package console
import (

View file

@ -1,3 +1,19 @@
/*
Copyright The containerd Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package console
import (

View file

@ -1,3 +1,19 @@
/*
Copyright The containerd Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package console
import (

51
vendor/github.com/containerd/console/tc_openbsd_cgo.go generated vendored Normal file
View file

@ -0,0 +1,51 @@
// +build openbsd,cgo
/*
Copyright The containerd Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package console
import (
"os"
"golang.org/x/sys/unix"
)
//#include <stdlib.h>
import "C"
const (
cmdTcGet = unix.TIOCGETA
cmdTcSet = unix.TIOCSETA
)
// ptsname retrieves the name of the first available pts for the given master.
func ptsname(f *os.File) (string, error) {
ptspath, err := C.ptsname(C.int(f.Fd()))
if err != nil {
return "", err
}
return C.GoString(ptspath), nil
}
// unlockpt unlocks the slave pseudoterminal device corresponding to the master pseudoterminal referred to by f.
// unlockpt should be called before opening the slave side of a pty.
func unlockpt(f *os.File) error {
if _, err := C.grantpt(C.int(f.Fd())); err != nil {
return err
}
return nil
}

View file

@ -0,0 +1,47 @@
// +build openbsd,!cgo
/*
Copyright The containerd Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
//
// Implementing the functions below requires cgo support. Non-cgo stubs
// versions are defined below to enable cross-compilation of source code
// that depends on these functions, but the resultant cross-compiled
// binaries cannot actually be used. If the stub function(s) below are
// actually invoked they will display an error message and cause the
// calling process to exit.
//
package console
import (
"os"
"golang.org/x/sys/unix"
)
const (
cmdTcGet = unix.TIOCGETA
cmdTcSet = unix.TIOCSETA
)
func ptsname(f *os.File) (string, error) {
panic("ptsname() support requires cgo.")
}
func unlockpt(f *os.File) error {
panic("unlockpt() support requires cgo.")
}

View file

@ -1,5 +1,21 @@
// +build solaris,cgo
/*
Copyright The containerd Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package console
import (

View file

@ -1,5 +1,21 @@
// +build solaris,!cgo
/*
Copyright The containerd Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
//
// Implementing the functions below requires cgo support. Non-cgo stubs
// versions are defined below to enable cross-compilation of source code

View file

@ -1,4 +1,20 @@
// +build darwin freebsd linux solaris
// +build darwin freebsd linux openbsd solaris
/*
Copyright The containerd Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package console

View file

@ -176,7 +176,7 @@
END OF TERMS AND CONDITIONS
Copyright 2013-2016 Docker, Inc.
Copyright The containerd Authors
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.

View file

@ -1,395 +0,0 @@
Attribution 4.0 International
=======================================================================
Creative Commons Corporation ("Creative Commons") is not a law firm and
does not provide legal services or legal advice. Distribution of
Creative Commons public licenses does not create a lawyer-client or
other relationship. Creative Commons makes its licenses and related
information available on an "as-is" basis. Creative Commons gives no
warranties regarding its licenses, any material licensed under their
terms and conditions, or any related information. Creative Commons
disclaims all liability for damages resulting from their use to the
fullest extent possible.
Using Creative Commons Public Licenses
Creative Commons public licenses provide a standard set of terms and
conditions that creators and other rights holders may use to share
original works of authorship and other material subject to copyright
and certain other rights specified in the public license below. The
following considerations are for informational purposes only, are not
exhaustive, and do not form part of our licenses.
Considerations for licensors: Our public licenses are
intended for use by those authorized to give the public
permission to use material in ways otherwise restricted by
copyright and certain other rights. Our licenses are
irrevocable. Licensors should read and understand the terms
and conditions of the license they choose before applying it.
Licensors should also secure all rights necessary before
applying our licenses so that the public can reuse the
material as expected. Licensors should clearly mark any
material not subject to the license. This includes other CC-
licensed material, or material used under an exception or
limitation to copyright. More considerations for licensors:
wiki.creativecommons.org/Considerations_for_licensors
Considerations for the public: By using one of our public
licenses, a licensor grants the public permission to use the
licensed material under specified terms and conditions. If
the licensor's permission is not necessary for any reason--for
example, because of any applicable exception or limitation to
copyright--then that use is not regulated by the license. Our
licenses grant only permissions under copyright and certain
other rights that a licensor has authority to grant. Use of
the licensed material may still be restricted for other
reasons, including because others have copyright or other
rights in the material. A licensor may make special requests,
such as asking that all changes be marked or described.
Although not required by our licenses, you are encouraged to
respect those requests where reasonable. More_considerations
for the public:
wiki.creativecommons.org/Considerations_for_licensees
=======================================================================
Creative Commons Attribution 4.0 International Public License
By exercising the Licensed Rights (defined below), You accept and agree
to be bound by the terms and conditions of this Creative Commons
Attribution 4.0 International Public License ("Public License"). To the
extent this Public License may be interpreted as a contract, You are
granted the Licensed Rights in consideration of Your acceptance of
these terms and conditions, and the Licensor grants You such rights in
consideration of benefits the Licensor receives from making the
Licensed Material available under these terms and conditions.
Section 1 -- Definitions.
a. Adapted Material means material subject to Copyright and Similar
Rights that is derived from or based upon the Licensed Material
and in which the Licensed Material is translated, altered,
arranged, transformed, or otherwise modified in a manner requiring
permission under the Copyright and Similar Rights held by the
Licensor. For purposes of this Public License, where the Licensed
Material is a musical work, performance, or sound recording,
Adapted Material is always produced where the Licensed Material is
synched in timed relation with a moving image.
b. Adapter's License means the license You apply to Your Copyright
and Similar Rights in Your contributions to Adapted Material in
accordance with the terms and conditions of this Public License.
c. Copyright and Similar Rights means copyright and/or similar rights
closely related to copyright including, without limitation,
performance, broadcast, sound recording, and Sui Generis Database
Rights, without regard to how the rights are labeled or
categorized. For purposes of this Public License, the rights
specified in Section 2(b)(1)-(2) are not Copyright and Similar
Rights.
d. Effective Technological Measures means those measures that, in the
absence of proper authority, may not be circumvented under laws
fulfilling obligations under Article 11 of the WIPO Copyright
Treaty adopted on December 20, 1996, and/or similar international
agreements.
e. Exceptions and Limitations means fair use, fair dealing, and/or
any other exception or limitation to Copyright and Similar Rights
that applies to Your use of the Licensed Material.
f. Licensed Material means the artistic or literary work, database,
or other material to which the Licensor applied this Public
License.
g. Licensed Rights means the rights granted to You subject to the
terms and conditions of this Public License, which are limited to
all Copyright and Similar Rights that apply to Your use of the
Licensed Material and that the Licensor has authority to license.
h. Licensor means the individual(s) or entity(ies) granting rights
under this Public License.
i. Share means to provide material to the public by any means or
process that requires permission under the Licensed Rights, such
as reproduction, public display, public performance, distribution,
dissemination, communication, or importation, and to make material
available to the public including in ways that members of the
public may access the material from a place and at a time
individually chosen by them.
j. Sui Generis Database Rights means rights other than copyright
resulting from Directive 96/9/EC of the European Parliament and of
the Council of 11 March 1996 on the legal protection of databases,
as amended and/or succeeded, as well as other essentially
equivalent rights anywhere in the world.
k. You means the individual or entity exercising the Licensed Rights
under this Public License. Your has a corresponding meaning.
Section 2 -- Scope.
a. License grant.
1. Subject to the terms and conditions of this Public License,
the Licensor hereby grants You a worldwide, royalty-free,
non-sublicensable, non-exclusive, irrevocable license to
exercise the Licensed Rights in the Licensed Material to:
a. reproduce and Share the Licensed Material, in whole or
in part; and
b. produce, reproduce, and Share Adapted Material.
2. Exceptions and Limitations. For the avoidance of doubt, where
Exceptions and Limitations apply to Your use, this Public
License does not apply, and You do not need to comply with
its terms and conditions.
3. Term. The term of this Public License is specified in Section
6(a).
4. Media and formats; technical modifications allowed. The
Licensor authorizes You to exercise the Licensed Rights in
all media and formats whether now known or hereafter created,
and to make technical modifications necessary to do so. The
Licensor waives and/or agrees not to assert any right or
authority to forbid You from making technical modifications
necessary to exercise the Licensed Rights, including
technical modifications necessary to circumvent Effective
Technological Measures. For purposes of this Public License,
simply making modifications authorized by this Section 2(a)
(4) never produces Adapted Material.
5. Downstream recipients.
a. Offer from the Licensor -- Licensed Material. Every
recipient of the Licensed Material automatically
receives an offer from the Licensor to exercise the
Licensed Rights under the terms and conditions of this
Public License.
b. No downstream restrictions. You may not offer or impose
any additional or different terms or conditions on, or
apply any Effective Technological Measures to, the
Licensed Material if doing so restricts exercise of the
Licensed Rights by any recipient of the Licensed
Material.
6. No endorsement. Nothing in this Public License constitutes or
may be construed as permission to assert or imply that You
are, or that Your use of the Licensed Material is, connected
with, or sponsored, endorsed, or granted official status by,
the Licensor or others designated to receive attribution as
provided in Section 3(a)(1)(A)(i).
b. Other rights.
1. Moral rights, such as the right of integrity, are not
licensed under this Public License, nor are publicity,
privacy, and/or other similar personality rights; however, to
the extent possible, the Licensor waives and/or agrees not to
assert any such rights held by the Licensor to the limited
extent necessary to allow You to exercise the Licensed
Rights, but not otherwise.
2. Patent and trademark rights are not licensed under this
Public License.
3. To the extent possible, the Licensor waives any right to
collect royalties from You for the exercise of the Licensed
Rights, whether directly or through a collecting society
under any voluntary or waivable statutory or compulsory
licensing scheme. In all other cases the Licensor expressly
reserves any right to collect such royalties.
Section 3 -- License Conditions.
Your exercise of the Licensed Rights is expressly made subject to the
following conditions.
a. Attribution.
1. If You Share the Licensed Material (including in modified
form), You must:
a. retain the following if it is supplied by the Licensor
with the Licensed Material:
i. identification of the creator(s) of the Licensed
Material and any others designated to receive
attribution, in any reasonable manner requested by
the Licensor (including by pseudonym if
designated);
ii. a copyright notice;
iii. a notice that refers to this Public License;
iv. a notice that refers to the disclaimer of
warranties;
v. a URI or hyperlink to the Licensed Material to the
extent reasonably practicable;
b. indicate if You modified the Licensed Material and
retain an indication of any previous modifications; and
c. indicate the Licensed Material is licensed under this
Public License, and include the text of, or the URI or
hyperlink to, this Public License.
2. You may satisfy the conditions in Section 3(a)(1) in any
reasonable manner based on the medium, means, and context in
which You Share the Licensed Material. For example, it may be
reasonable to satisfy the conditions by providing a URI or
hyperlink to a resource that includes the required
information.
3. If requested by the Licensor, You must remove any of the
information required by Section 3(a)(1)(A) to the extent
reasonably practicable.
4. If You Share Adapted Material You produce, the Adapter's
License You apply must not prevent recipients of the Adapted
Material from complying with this Public License.
Section 4 -- Sui Generis Database Rights.
Where the Licensed Rights include Sui Generis Database Rights that
apply to Your use of the Licensed Material:
a. for the avoidance of doubt, Section 2(a)(1) grants You the right
to extract, reuse, reproduce, and Share all or a substantial
portion of the contents of the database;
b. if You include all or a substantial portion of the database
contents in a database in which You have Sui Generis Database
Rights, then the database in which You have Sui Generis Database
Rights (but not its individual contents) is Adapted Material; and
c. You must comply with the conditions in Section 3(a) if You Share
all or a substantial portion of the contents of the database.
For the avoidance of doubt, this Section 4 supplements and does not
replace Your obligations under this Public License where the Licensed
Rights include other Copyright and Similar Rights.
Section 5 -- Disclaimer of Warranties and Limitation of Liability.
a. UNLESS OTHERWISE SEPARATELY UNDERTAKEN BY THE LICENSOR, TO THE
EXTENT POSSIBLE, THE LICENSOR OFFERS THE LICENSED MATERIAL AS-IS
AND AS-AVAILABLE, AND MAKES NO REPRESENTATIONS OR WARRANTIES OF
ANY KIND CONCERNING THE LICENSED MATERIAL, WHETHER EXPRESS,
IMPLIED, STATUTORY, OR OTHER. THIS INCLUDES, WITHOUT LIMITATION,
WARRANTIES OF TITLE, MERCHANTABILITY, FITNESS FOR A PARTICULAR
PURPOSE, NON-INFRINGEMENT, ABSENCE OF LATENT OR OTHER DEFECTS,
ACCURACY, OR THE PRESENCE OR ABSENCE OF ERRORS, WHETHER OR NOT
KNOWN OR DISCOVERABLE. WHERE DISCLAIMERS OF WARRANTIES ARE NOT
ALLOWED IN FULL OR IN PART, THIS DISCLAIMER MAY NOT APPLY TO YOU.
b. TO THE EXTENT POSSIBLE, IN NO EVENT WILL THE LICENSOR BE LIABLE
TO YOU ON ANY LEGAL THEORY (INCLUDING, WITHOUT LIMITATION,
NEGLIGENCE) OR OTHERWISE FOR ANY DIRECT, SPECIAL, INDIRECT,
INCIDENTAL, CONSEQUENTIAL, PUNITIVE, EXEMPLARY, OR OTHER LOSSES,
COSTS, EXPENSES, OR DAMAGES ARISING OUT OF THIS PUBLIC LICENSE OR
USE OF THE LICENSED MATERIAL, EVEN IF THE LICENSOR HAS BEEN
ADVISED OF THE POSSIBILITY OF SUCH LOSSES, COSTS, EXPENSES, OR
DAMAGES. WHERE A LIMITATION OF LIABILITY IS NOT ALLOWED IN FULL OR
IN PART, THIS LIMITATION MAY NOT APPLY TO YOU.
c. The disclaimer of warranties and limitation of liability provided
above shall be interpreted in a manner that, to the extent
possible, most closely approximates an absolute disclaimer and
waiver of all liability.
Section 6 -- Term and Termination.
a. This Public License applies for the term of the Copyright and
Similar Rights licensed here. However, if You fail to comply with
this Public License, then Your rights under this Public License
terminate automatically.
b. Where Your right to use the Licensed Material has terminated under
Section 6(a), it reinstates:
1. automatically as of the date the violation is cured, provided
it is cured within 30 days of Your discovery of the
violation; or
2. upon express reinstatement by the Licensor.
For the avoidance of doubt, this Section 6(b) does not affect any
right the Licensor may have to seek remedies for Your violations
of this Public License.
c. For the avoidance of doubt, the Licensor may also offer the
Licensed Material under separate terms or conditions or stop
distributing the Licensed Material at any time; however, doing so
will not terminate this Public License.
d. Sections 1, 5, 6, 7, and 8 survive termination of this Public
License.
Section 7 -- Other Terms and Conditions.
a. The Licensor shall not be bound by any additional or different
terms or conditions communicated by You unless expressly agreed.
b. Any arrangements, understandings, or agreements regarding the
Licensed Material not stated herein are separate from and
independent of the terms and conditions of this Public License.
Section 8 -- Interpretation.
a. For the avoidance of doubt, this Public License does not, and
shall not be interpreted to, reduce, limit, restrict, or impose
conditions on any use of the Licensed Material that could lawfully
be made without permission under this Public License.
b. To the extent possible, if any provision of this Public License is
deemed unenforceable, it shall be automatically reformed to the
minimum extent necessary to make it enforceable. If the provision
cannot be reformed, it shall be severed from this Public License
without affecting the enforceability of the remaining terms and
conditions.
c. No term or condition of this Public License will be waived and no
failure to comply consented to unless expressly agreed to by the
Licensor.
d. Nothing in this Public License constitutes or may be interpreted
as a limitation upon, or waiver of, any privileges and immunities
that apply to the Licensor or You, including from the legal
processes of any jurisdiction or authority.
=======================================================================
Creative Commons is not a party to its public
licenses. Notwithstanding, Creative Commons may elect to apply one of
its public licenses to material it publishes and in those instances
will be considered the “Licensor.” The text of the Creative Commons
public licenses is dedicated to the public domain under the CC0 Public
Domain Dedication. Except for the limited purpose of indicating that
material is shared under a Creative Commons public license or as
otherwise permitted by the Creative Commons policies published at
creativecommons.org/policies, Creative Commons does not authorize the
use of the trademark "Creative Commons" or any other trademark or logo
of Creative Commons without its prior written consent including,
without limitation, in connection with any unauthorized modifications
to any of its public licenses or any other arrangements,
understandings, or agreements concerning use of licensed material. For
the avoidance of doubt, this paragraph does not form part of the
public licenses.
Creative Commons may be contacted at creativecommons.org.

View file

@ -1,4 +1,4 @@
![banner](/docs/images/containerd-dark.png?raw=true)
![banner](/docs/static/img/containerd-dark.png?raw=true)
[![GoDoc](https://godoc.org/github.com/containerd/containerd?status.svg)](https://godoc.org/github.com/containerd/containerd)
[![Build Status](https://travis-ci.org/containerd/containerd.svg?branch=master)](https://travis-ci.org/containerd/containerd)
@ -211,6 +211,5 @@ __If you are reporting a security issue, please reach out discreetly at security
The containerd codebase is released under the [Apache 2.0 license](LICENSE.code).
The README.md file, and files in the "docs" folder are licensed under the
Creative Commons Attribution 4.0 International License under the terms and
conditions set forth in the file "[LICENSE.docs](LICENSE.docs)". You may obtain a duplicate
copy of the same license, titled CC-BY-4.0, at http://creativecommons.org/licenses/by/4.0/.
Creative Commons Attribution 4.0 International License. You may obtain a
copy of the license, titled CC-BY-4.0, at http://creativecommons.org/licenses/by/4.0/.

View file

@ -48,11 +48,11 @@ import google_protobuf "github.com/gogo/protobuf/types"
// skipping weak import gogoproto "github.com/gogo/protobuf/gogoproto"
// skipping weak import containerd_plugin "github.com/containerd/containerd/protobuf/plugin"
import github_com_containerd_typeurl "github.com/containerd/typeurl"
import typeurl "github.com/containerd/typeurl"
import strings "strings"
import reflect "reflect"
import github_com_gogo_protobuf_sortkeys "github.com/gogo/protobuf/sortkeys"
import sortkeys "github.com/gogo/protobuf/sortkeys"
import io "io"
@ -153,7 +153,7 @@ func (m *ContainerCreate_Runtime) Field(fieldpath []string) (string, bool) {
case "name":
return string(m.Name), len(m.Name) > 0
case "options":
decoded, err := github_com_containerd_typeurl.UnmarshalAny(m.Options)
decoded, err := typeurl.UnmarshalAny(m.Options)
if err != nil {
return "", false
}
@ -478,7 +478,7 @@ func (this *ContainerUpdate) String() string {
for k, _ := range this.Labels {
keysForLabels = append(keysForLabels, k)
}
github_com_gogo_protobuf_sortkeys.Strings(keysForLabels)
sortkeys.Strings(keysForLabels)
mapStringForLabels := "map[string]string{"
for _, k := range keysForLabels {
mapStringForLabels += fmt.Sprintf("%v: %v,", k, this.Labels[k])

View file

@ -11,7 +11,7 @@ import math "math"
import strings "strings"
import reflect "reflect"
import github_com_gogo_protobuf_sortkeys "github.com/gogo/protobuf/sortkeys"
import sortkeys "github.com/gogo/protobuf/sortkeys"
import io "io"
@ -291,7 +291,7 @@ func (this *ImageCreate) String() string {
for k, _ := range this.Labels {
keysForLabels = append(keysForLabels, k)
}
github_com_gogo_protobuf_sortkeys.Strings(keysForLabels)
sortkeys.Strings(keysForLabels)
mapStringForLabels := "map[string]string{"
for _, k := range keysForLabels {
mapStringForLabels += fmt.Sprintf("%v: %v,", k, this.Labels[k])
@ -312,7 +312,7 @@ func (this *ImageUpdate) String() string {
for k, _ := range this.Labels {
keysForLabels = append(keysForLabels, k)
}
github_com_gogo_protobuf_sortkeys.Strings(keysForLabels)
sortkeys.Strings(keysForLabels)
mapStringForLabels := "map[string]string{"
for _, k := range keysForLabels {
mapStringForLabels += fmt.Sprintf("%v: %v,", k, this.Labels[k])

View file

@ -12,7 +12,7 @@ import math "math"
import strings "strings"
import reflect "reflect"
import github_com_gogo_protobuf_sortkeys "github.com/gogo/protobuf/sortkeys"
import sortkeys "github.com/gogo/protobuf/sortkeys"
import io "io"
@ -292,7 +292,7 @@ func (this *NamespaceCreate) String() string {
for k, _ := range this.Labels {
keysForLabels = append(keysForLabels, k)
}
github_com_gogo_protobuf_sortkeys.Strings(keysForLabels)
sortkeys.Strings(keysForLabels)
mapStringForLabels := "map[string]string{"
for _, k := range keysForLabels {
mapStringForLabels += fmt.Sprintf("%v: %v,", k, this.Labels[k])
@ -313,7 +313,7 @@ func (this *NamespaceUpdate) String() string {
for k, _ := range this.Labels {
keysForLabels = append(keysForLabels, k)
}
github_com_gogo_protobuf_sortkeys.Strings(keysForLabels)
sortkeys.Strings(keysForLabels)
mapStringForLabels := "map[string]string{"
for _, k := range keysForLabels {
mapStringForLabels += fmt.Sprintf("%v: %v,", k, this.Labels[k])

View file

@ -15,7 +15,7 @@ import containerd_types "github.com/containerd/containerd/api/types"
import time "time"
import github_com_gogo_protobuf_types "github.com/gogo/protobuf/types"
import types "github.com/gogo/protobuf/types"
import strings "strings"
import reflect "reflect"
@ -468,8 +468,8 @@ func (m *TaskDelete) MarshalTo(dAtA []byte) (int, error) {
}
dAtA[i] = 0x22
i++
i = encodeVarintTask(dAtA, i, uint64(github_com_gogo_protobuf_types.SizeOfStdTime(m.ExitedAt)))
n2, err := github_com_gogo_protobuf_types.StdTimeMarshalTo(m.ExitedAt, dAtA[i:])
i = encodeVarintTask(dAtA, i, uint64(types.SizeOfStdTime(m.ExitedAt)))
n2, err := types.StdTimeMarshalTo(m.ExitedAt, dAtA[i:])
if err != nil {
return 0, err
}
@ -562,8 +562,8 @@ func (m *TaskExit) MarshalTo(dAtA []byte) (int, error) {
}
dAtA[i] = 0x2a
i++
i = encodeVarintTask(dAtA, i, uint64(github_com_gogo_protobuf_types.SizeOfStdTime(m.ExitedAt)))
n3, err := github_com_gogo_protobuf_types.StdTimeMarshalTo(m.ExitedAt, dAtA[i:])
i = encodeVarintTask(dAtA, i, uint64(types.SizeOfStdTime(m.ExitedAt)))
n3, err := types.StdTimeMarshalTo(m.ExitedAt, dAtA[i:])
if err != nil {
return 0, err
}
@ -804,7 +804,7 @@ func (m *TaskDelete) Size() (n int) {
if m.ExitStatus != 0 {
n += 1 + sovTask(uint64(m.ExitStatus))
}
l = github_com_gogo_protobuf_types.SizeOfStdTime(m.ExitedAt)
l = types.SizeOfStdTime(m.ExitedAt)
n += 1 + l + sovTask(uint64(l))
return n
}
@ -847,7 +847,7 @@ func (m *TaskExit) Size() (n int) {
if m.ExitStatus != 0 {
n += 1 + sovTask(uint64(m.ExitStatus))
}
l = github_com_gogo_protobuf_types.SizeOfStdTime(m.ExitedAt)
l = types.SizeOfStdTime(m.ExitedAt)
n += 1 + l + sovTask(uint64(l))
return n
}
@ -1518,7 +1518,7 @@ func (m *TaskDelete) Unmarshal(dAtA []byte) error {
if postIndex > l {
return io.ErrUnexpectedEOF
}
if err := github_com_gogo_protobuf_types.StdTimeUnmarshal(&m.ExitedAt, dAtA[iNdEx:postIndex]); err != nil {
if err := types.StdTimeUnmarshal(&m.ExitedAt, dAtA[iNdEx:postIndex]); err != nil {
return err
}
iNdEx = postIndex
@ -1851,7 +1851,7 @@ func (m *TaskExit) Unmarshal(dAtA []byte) error {
if postIndex > l {
return io.ErrUnexpectedEOF
}
if err := github_com_gogo_protobuf_types.StdTimeUnmarshal(&m.ExitedAt, dAtA[iNdEx:postIndex]); err != nil {
if err := types.StdTimeUnmarshal(&m.ExitedAt, dAtA[iNdEx:postIndex]); err != nil {
return err
}
iNdEx = postIndex

View file

@ -33,16 +33,14 @@ import _ "github.com/gogo/protobuf/types"
import time "time"
import (
context "golang.org/x/net/context"
grpc "google.golang.org/grpc"
)
import context "golang.org/x/net/context"
import grpc "google.golang.org/grpc"
import github_com_gogo_protobuf_types "github.com/gogo/protobuf/types"
import types "github.com/gogo/protobuf/types"
import strings "strings"
import reflect "reflect"
import github_com_gogo_protobuf_sortkeys "github.com/gogo/protobuf/sortkeys"
import sortkeys "github.com/gogo/protobuf/sortkeys"
import io "io"
@ -516,16 +514,16 @@ func (m *Container) MarshalTo(dAtA []byte) (int, error) {
}
dAtA[i] = 0x42
i++
i = encodeVarintContainers(dAtA, i, uint64(github_com_gogo_protobuf_types.SizeOfStdTime(m.CreatedAt)))
n3, err := github_com_gogo_protobuf_types.StdTimeMarshalTo(m.CreatedAt, dAtA[i:])
i = encodeVarintContainers(dAtA, i, uint64(types.SizeOfStdTime(m.CreatedAt)))
n3, err := types.StdTimeMarshalTo(m.CreatedAt, dAtA[i:])
if err != nil {
return 0, err
}
i += n3
dAtA[i] = 0x4a
i++
i = encodeVarintContainers(dAtA, i, uint64(github_com_gogo_protobuf_types.SizeOfStdTime(m.UpdatedAt)))
n4, err := github_com_gogo_protobuf_types.StdTimeMarshalTo(m.UpdatedAt, dAtA[i:])
i = encodeVarintContainers(dAtA, i, uint64(types.SizeOfStdTime(m.UpdatedAt)))
n4, err := types.StdTimeMarshalTo(m.UpdatedAt, dAtA[i:])
if err != nil {
return 0, err
}
@ -888,9 +886,9 @@ func (m *Container) Size() (n int) {
if l > 0 {
n += 1 + l + sovContainers(uint64(l))
}
l = github_com_gogo_protobuf_types.SizeOfStdTime(m.CreatedAt)
l = types.SizeOfStdTime(m.CreatedAt)
n += 1 + l + sovContainers(uint64(l))
l = github_com_gogo_protobuf_types.SizeOfStdTime(m.UpdatedAt)
l = types.SizeOfStdTime(m.UpdatedAt)
n += 1 + l + sovContainers(uint64(l))
if len(m.Extensions) > 0 {
for k, v := range m.Extensions {
@ -1027,7 +1025,7 @@ func (this *Container) String() string {
for k, _ := range this.Labels {
keysForLabels = append(keysForLabels, k)
}
github_com_gogo_protobuf_sortkeys.Strings(keysForLabels)
sortkeys.Strings(keysForLabels)
mapStringForLabels := "map[string]string{"
for _, k := range keysForLabels {
mapStringForLabels += fmt.Sprintf("%v: %v,", k, this.Labels[k])
@ -1037,7 +1035,7 @@ func (this *Container) String() string {
for k, _ := range this.Extensions {
keysForExtensions = append(keysForExtensions, k)
}
github_com_gogo_protobuf_sortkeys.Strings(keysForExtensions)
sortkeys.Strings(keysForExtensions)
mapStringForExtensions := "map[string]google_protobuf1.Any{"
for _, k := range keysForExtensions {
mapStringForExtensions += fmt.Sprintf("%v: %v,", k, this.Extensions[k])
@ -1523,7 +1521,7 @@ func (m *Container) Unmarshal(dAtA []byte) error {
if postIndex > l {
return io.ErrUnexpectedEOF
}
if err := github_com_gogo_protobuf_types.StdTimeUnmarshal(&m.CreatedAt, dAtA[iNdEx:postIndex]); err != nil {
if err := types.StdTimeUnmarshal(&m.CreatedAt, dAtA[iNdEx:postIndex]); err != nil {
return err
}
iNdEx = postIndex
@ -1553,7 +1551,7 @@ func (m *Container) Unmarshal(dAtA []byte) error {
if postIndex > l {
return io.ErrUnexpectedEOF
}
if err := github_com_gogo_protobuf_types.StdTimeUnmarshal(&m.UpdatedAt, dAtA[iNdEx:postIndex]); err != nil {
if err := types.StdTimeUnmarshal(&m.UpdatedAt, dAtA[iNdEx:postIndex]); err != nil {
return err
}
iNdEx = postIndex

View file

@ -41,16 +41,14 @@ import google_protobuf3 "github.com/gogo/protobuf/types"
import github_com_opencontainers_go_digest "github.com/opencontainers/go-digest"
import time "time"
import (
context "golang.org/x/net/context"
grpc "google.golang.org/grpc"
)
import context "golang.org/x/net/context"
import grpc "google.golang.org/grpc"
import github_com_gogo_protobuf_types "github.com/gogo/protobuf/types"
import types "github.com/gogo/protobuf/types"
import strings "strings"
import reflect "reflect"
import github_com_gogo_protobuf_sortkeys "github.com/gogo/protobuf/sortkeys"
import sortkeys "github.com/gogo/protobuf/sortkeys"
import io "io"
@ -936,16 +934,16 @@ func (m *Info) MarshalTo(dAtA []byte) (int, error) {
}
dAtA[i] = 0x1a
i++
i = encodeVarintContent(dAtA, i, uint64(github_com_gogo_protobuf_types.SizeOfStdTime(m.CreatedAt)))
n1, err := github_com_gogo_protobuf_types.StdTimeMarshalTo(m.CreatedAt, dAtA[i:])
i = encodeVarintContent(dAtA, i, uint64(types.SizeOfStdTime(m.CreatedAt)))
n1, err := types.StdTimeMarshalTo(m.CreatedAt, dAtA[i:])
if err != nil {
return 0, err
}
i += n1
dAtA[i] = 0x22
i++
i = encodeVarintContent(dAtA, i, uint64(github_com_gogo_protobuf_types.SizeOfStdTime(m.UpdatedAt)))
n2, err := github_com_gogo_protobuf_types.StdTimeMarshalTo(m.UpdatedAt, dAtA[i:])
i = encodeVarintContent(dAtA, i, uint64(types.SizeOfStdTime(m.UpdatedAt)))
n2, err := types.StdTimeMarshalTo(m.UpdatedAt, dAtA[i:])
if err != nil {
return 0, err
}
@ -1249,16 +1247,16 @@ func (m *Status) MarshalTo(dAtA []byte) (int, error) {
_ = l
dAtA[i] = 0xa
i++
i = encodeVarintContent(dAtA, i, uint64(github_com_gogo_protobuf_types.SizeOfStdTime(m.StartedAt)))
n7, err := github_com_gogo_protobuf_types.StdTimeMarshalTo(m.StartedAt, dAtA[i:])
i = encodeVarintContent(dAtA, i, uint64(types.SizeOfStdTime(m.StartedAt)))
n7, err := types.StdTimeMarshalTo(m.StartedAt, dAtA[i:])
if err != nil {
return 0, err
}
i += n7
dAtA[i] = 0x12
i++
i = encodeVarintContent(dAtA, i, uint64(github_com_gogo_protobuf_types.SizeOfStdTime(m.UpdatedAt)))
n8, err := github_com_gogo_protobuf_types.StdTimeMarshalTo(m.UpdatedAt, dAtA[i:])
i = encodeVarintContent(dAtA, i, uint64(types.SizeOfStdTime(m.UpdatedAt)))
n8, err := types.StdTimeMarshalTo(m.UpdatedAt, dAtA[i:])
if err != nil {
return 0, err
}
@ -1493,16 +1491,16 @@ func (m *WriteContentResponse) MarshalTo(dAtA []byte) (int, error) {
}
dAtA[i] = 0x12
i++
i = encodeVarintContent(dAtA, i, uint64(github_com_gogo_protobuf_types.SizeOfStdTime(m.StartedAt)))
n10, err := github_com_gogo_protobuf_types.StdTimeMarshalTo(m.StartedAt, dAtA[i:])
i = encodeVarintContent(dAtA, i, uint64(types.SizeOfStdTime(m.StartedAt)))
n10, err := types.StdTimeMarshalTo(m.StartedAt, dAtA[i:])
if err != nil {
return 0, err
}
i += n10
dAtA[i] = 0x1a
i++
i = encodeVarintContent(dAtA, i, uint64(github_com_gogo_protobuf_types.SizeOfStdTime(m.UpdatedAt)))
n11, err := github_com_gogo_protobuf_types.StdTimeMarshalTo(m.UpdatedAt, dAtA[i:])
i = encodeVarintContent(dAtA, i, uint64(types.SizeOfStdTime(m.UpdatedAt)))
n11, err := types.StdTimeMarshalTo(m.UpdatedAt, dAtA[i:])
if err != nil {
return 0, err
}
@ -1569,9 +1567,9 @@ func (m *Info) Size() (n int) {
if m.Size_ != 0 {
n += 1 + sovContent(uint64(m.Size_))
}
l = github_com_gogo_protobuf_types.SizeOfStdTime(m.CreatedAt)
l = types.SizeOfStdTime(m.CreatedAt)
n += 1 + l + sovContent(uint64(l))
l = github_com_gogo_protobuf_types.SizeOfStdTime(m.UpdatedAt)
l = types.SizeOfStdTime(m.UpdatedAt)
n += 1 + l + sovContent(uint64(l))
if len(m.Labels) > 0 {
for k, v := range m.Labels {
@ -1688,9 +1686,9 @@ func (m *ReadContentResponse) Size() (n int) {
func (m *Status) Size() (n int) {
var l int
_ = l
l = github_com_gogo_protobuf_types.SizeOfStdTime(m.StartedAt)
l = types.SizeOfStdTime(m.StartedAt)
n += 1 + l + sovContent(uint64(l))
l = github_com_gogo_protobuf_types.SizeOfStdTime(m.UpdatedAt)
l = types.SizeOfStdTime(m.UpdatedAt)
n += 1 + l + sovContent(uint64(l))
l = len(m.Ref)
if l > 0 {
@ -1794,9 +1792,9 @@ func (m *WriteContentResponse) Size() (n int) {
if m.Action != 0 {
n += 1 + sovContent(uint64(m.Action))
}
l = github_com_gogo_protobuf_types.SizeOfStdTime(m.StartedAt)
l = types.SizeOfStdTime(m.StartedAt)
n += 1 + l + sovContent(uint64(l))
l = github_com_gogo_protobuf_types.SizeOfStdTime(m.UpdatedAt)
l = types.SizeOfStdTime(m.UpdatedAt)
n += 1 + l + sovContent(uint64(l))
if m.Offset != 0 {
n += 1 + sovContent(uint64(m.Offset))
@ -1842,7 +1840,7 @@ func (this *Info) String() string {
for k, _ := range this.Labels {
keysForLabels = append(keysForLabels, k)
}
github_com_gogo_protobuf_sortkeys.Strings(keysForLabels)
sortkeys.Strings(keysForLabels)
mapStringForLabels := "map[string]string{"
for _, k := range keysForLabels {
mapStringForLabels += fmt.Sprintf("%v: %v,", k, this.Labels[k])
@ -2015,7 +2013,7 @@ func (this *WriteContentRequest) String() string {
for k, _ := range this.Labels {
keysForLabels = append(keysForLabels, k)
}
github_com_gogo_protobuf_sortkeys.Strings(keysForLabels)
sortkeys.Strings(keysForLabels)
mapStringForLabels := "map[string]string{"
for _, k := range keysForLabels {
mapStringForLabels += fmt.Sprintf("%v: %v,", k, this.Labels[k])
@ -2169,7 +2167,7 @@ func (m *Info) Unmarshal(dAtA []byte) error {
if postIndex > l {
return io.ErrUnexpectedEOF
}
if err := github_com_gogo_protobuf_types.StdTimeUnmarshal(&m.CreatedAt, dAtA[iNdEx:postIndex]); err != nil {
if err := types.StdTimeUnmarshal(&m.CreatedAt, dAtA[iNdEx:postIndex]); err != nil {
return err
}
iNdEx = postIndex
@ -2199,7 +2197,7 @@ func (m *Info) Unmarshal(dAtA []byte) error {
if postIndex > l {
return io.ErrUnexpectedEOF
}
if err := github_com_gogo_protobuf_types.StdTimeUnmarshal(&m.UpdatedAt, dAtA[iNdEx:postIndex]); err != nil {
if err := types.StdTimeUnmarshal(&m.UpdatedAt, dAtA[iNdEx:postIndex]); err != nil {
return err
}
iNdEx = postIndex
@ -3205,7 +3203,7 @@ func (m *Status) Unmarshal(dAtA []byte) error {
if postIndex > l {
return io.ErrUnexpectedEOF
}
if err := github_com_gogo_protobuf_types.StdTimeUnmarshal(&m.StartedAt, dAtA[iNdEx:postIndex]); err != nil {
if err := types.StdTimeUnmarshal(&m.StartedAt, dAtA[iNdEx:postIndex]); err != nil {
return err
}
iNdEx = postIndex
@ -3235,7 +3233,7 @@ func (m *Status) Unmarshal(dAtA []byte) error {
if postIndex > l {
return io.ErrUnexpectedEOF
}
if err := github_com_gogo_protobuf_types.StdTimeUnmarshal(&m.UpdatedAt, dAtA[iNdEx:postIndex]); err != nil {
if err := types.StdTimeUnmarshal(&m.UpdatedAt, dAtA[iNdEx:postIndex]); err != nil {
return err
}
iNdEx = postIndex
@ -4066,7 +4064,7 @@ func (m *WriteContentResponse) Unmarshal(dAtA []byte) error {
if postIndex > l {
return io.ErrUnexpectedEOF
}
if err := github_com_gogo_protobuf_types.StdTimeUnmarshal(&m.StartedAt, dAtA[iNdEx:postIndex]); err != nil {
if err := types.StdTimeUnmarshal(&m.StartedAt, dAtA[iNdEx:postIndex]); err != nil {
return err
}
iNdEx = postIndex
@ -4096,7 +4094,7 @@ func (m *WriteContentResponse) Unmarshal(dAtA []byte) error {
if postIndex > l {
return io.ErrUnexpectedEOF
}
if err := github_com_gogo_protobuf_types.StdTimeUnmarshal(&m.UpdatedAt, dAtA[iNdEx:postIndex]); err != nil {
if err := types.StdTimeUnmarshal(&m.UpdatedAt, dAtA[iNdEx:postIndex]); err != nil {
return err
}
iNdEx = postIndex

View file

@ -23,14 +23,12 @@ import math "math"
import containerd_types "github.com/containerd/containerd/api/types"
import containerd_types1 "github.com/containerd/containerd/api/types"
import (
context "golang.org/x/net/context"
grpc "google.golang.org/grpc"
)
import context "golang.org/x/net/context"
import grpc "google.golang.org/grpc"
import strings "strings"
import reflect "reflect"
import github_com_gogo_protobuf_sortkeys "github.com/gogo/protobuf/sortkeys"
import sortkeys "github.com/gogo/protobuf/sortkeys"
import io "io"
@ -507,7 +505,7 @@ func (this *DiffRequest) String() string {
for k, _ := range this.Labels {
keysForLabels = append(keysForLabels, k)
}
github_com_gogo_protobuf_sortkeys.Strings(keysForLabels)
sortkeys.Strings(keysForLabels)
mapStringForLabels := "map[string]string{"
for _, k := range keysForLabels {
mapStringForLabels += fmt.Sprintf("%v: %v,", k, this.Labels[k])

View file

@ -27,14 +27,12 @@ import _ "github.com/gogo/protobuf/types"
import time "time"
import github_com_containerd_typeurl "github.com/containerd/typeurl"
import typeurl "github.com/containerd/typeurl"
import (
context "golang.org/x/net/context"
grpc "google.golang.org/grpc"
)
import context "golang.org/x/net/context"
import grpc "google.golang.org/grpc"
import github_com_gogo_protobuf_types "github.com/gogo/protobuf/types"
import types "github.com/gogo/protobuf/types"
import strings "strings"
import reflect "reflect"
@ -110,7 +108,7 @@ func (m *Envelope) Field(fieldpath []string) (string, bool) {
case "topic":
return string(m.Topic), len(m.Topic) > 0
case "event":
decoded, err := github_com_containerd_typeurl.UnmarshalAny(m.Event)
decoded, err := typeurl.UnmarshalAny(m.Event)
if err != nil {
return "", false
}
@ -434,8 +432,8 @@ func (m *Envelope) MarshalTo(dAtA []byte) (int, error) {
_ = l
dAtA[i] = 0xa
i++
i = encodeVarintEvents(dAtA, i, uint64(github_com_gogo_protobuf_types.SizeOfStdTime(m.Timestamp)))
n3, err := github_com_gogo_protobuf_types.StdTimeMarshalTo(m.Timestamp, dAtA[i:])
i = encodeVarintEvents(dAtA, i, uint64(types.SizeOfStdTime(m.Timestamp)))
n3, err := types.StdTimeMarshalTo(m.Timestamp, dAtA[i:])
if err != nil {
return 0, err
}
@ -513,7 +511,7 @@ func (m *SubscribeRequest) Size() (n int) {
func (m *Envelope) Size() (n int) {
var l int
_ = l
l = github_com_gogo_protobuf_types.SizeOfStdTime(m.Timestamp)
l = types.SizeOfStdTime(m.Timestamp)
n += 1 + l + sovEvents(uint64(l))
l = len(m.Namespace)
if l > 0 {
@ -924,7 +922,7 @@ func (m *Envelope) Unmarshal(dAtA []byte) error {
if postIndex > l {
return io.ErrUnexpectedEOF
}
if err := github_com_gogo_protobuf_types.StdTimeUnmarshal(&m.Timestamp, dAtA[iNdEx:postIndex]); err != nil {
if err := types.StdTimeUnmarshal(&m.Timestamp, dAtA[iNdEx:postIndex]); err != nil {
return err
}
iNdEx = postIndex

View file

@ -33,16 +33,14 @@ import containerd_types "github.com/containerd/containerd/api/types"
import time "time"
import (
context "golang.org/x/net/context"
grpc "google.golang.org/grpc"
)
import context "golang.org/x/net/context"
import grpc "google.golang.org/grpc"
import github_com_gogo_protobuf_types "github.com/gogo/protobuf/types"
import types "github.com/gogo/protobuf/types"
import strings "strings"
import reflect "reflect"
import github_com_gogo_protobuf_sortkeys "github.com/gogo/protobuf/sortkeys"
import sortkeys "github.com/gogo/protobuf/sortkeys"
import io "io"
@ -455,16 +453,16 @@ func (m *Image) MarshalTo(dAtA []byte) (int, error) {
i += n1
dAtA[i] = 0x3a
i++
i = encodeVarintImages(dAtA, i, uint64(github_com_gogo_protobuf_types.SizeOfStdTime(m.CreatedAt)))
n2, err := github_com_gogo_protobuf_types.StdTimeMarshalTo(m.CreatedAt, dAtA[i:])
i = encodeVarintImages(dAtA, i, uint64(types.SizeOfStdTime(m.CreatedAt)))
n2, err := types.StdTimeMarshalTo(m.CreatedAt, dAtA[i:])
if err != nil {
return 0, err
}
i += n2
dAtA[i] = 0x42
i++
i = encodeVarintImages(dAtA, i, uint64(github_com_gogo_protobuf_types.SizeOfStdTime(m.UpdatedAt)))
n3, err := github_com_gogo_protobuf_types.StdTimeMarshalTo(m.UpdatedAt, dAtA[i:])
i = encodeVarintImages(dAtA, i, uint64(types.SizeOfStdTime(m.UpdatedAt)))
n3, err := types.StdTimeMarshalTo(m.UpdatedAt, dAtA[i:])
if err != nil {
return 0, err
}
@ -761,9 +759,9 @@ func (m *Image) Size() (n int) {
}
l = m.Target.Size()
n += 1 + l + sovImages(uint64(l))
l = github_com_gogo_protobuf_types.SizeOfStdTime(m.CreatedAt)
l = types.SizeOfStdTime(m.CreatedAt)
n += 1 + l + sovImages(uint64(l))
l = github_com_gogo_protobuf_types.SizeOfStdTime(m.UpdatedAt)
l = types.SizeOfStdTime(m.UpdatedAt)
n += 1 + l + sovImages(uint64(l))
return n
}
@ -882,7 +880,7 @@ func (this *Image) String() string {
for k, _ := range this.Labels {
keysForLabels = append(keysForLabels, k)
}
github_com_gogo_protobuf_sortkeys.Strings(keysForLabels)
sortkeys.Strings(keysForLabels)
mapStringForLabels := "map[string]string{"
for _, k := range keysForLabels {
mapStringForLabels += fmt.Sprintf("%v: %v,", k, this.Labels[k])
@ -1230,7 +1228,7 @@ func (m *Image) Unmarshal(dAtA []byte) error {
if postIndex > l {
return io.ErrUnexpectedEOF
}
if err := github_com_gogo_protobuf_types.StdTimeUnmarshal(&m.CreatedAt, dAtA[iNdEx:postIndex]); err != nil {
if err := types.StdTimeUnmarshal(&m.CreatedAt, dAtA[iNdEx:postIndex]); err != nil {
return err
}
iNdEx = postIndex
@ -1260,7 +1258,7 @@ func (m *Image) Unmarshal(dAtA []byte) error {
if postIndex > l {
return io.ErrUnexpectedEOF
}
if err := github_com_gogo_protobuf_types.StdTimeUnmarshal(&m.UpdatedAt, dAtA[iNdEx:postIndex]); err != nil {
if err := types.StdTimeUnmarshal(&m.UpdatedAt, dAtA[iNdEx:postIndex]); err != nil {
return err
}
iNdEx = postIndex

View file

@ -18,18 +18,16 @@ import proto "github.com/gogo/protobuf/proto"
import fmt "fmt"
import math "math"
import containerd_types "github.com/containerd/containerd/api/types"
import google_rpc "github.com/containerd/containerd/protobuf/google/rpc"
import google_rpc "github.com/gogo/googleapis/google/rpc"
// skipping weak import gogoproto "github.com/gogo/protobuf/gogoproto"
import (
context "golang.org/x/net/context"
grpc "google.golang.org/grpc"
)
import context "golang.org/x/net/context"
import grpc "google.golang.org/grpc"
import strings "strings"
import reflect "reflect"
import github_com_gogo_protobuf_sortkeys "github.com/gogo/protobuf/sortkeys"
import sortkeys "github.com/gogo/protobuf/sortkeys"
import io "io"
@ -460,7 +458,7 @@ func (this *Plugin) String() string {
for k, _ := range this.Exports {
keysForExports = append(keysForExports, k)
}
github_com_gogo_protobuf_sortkeys.Strings(keysForExports)
sortkeys.Strings(keysForExports)
mapStringForExports := "map[string]string{"
for _, k := range keysForExports {
mapStringForExports += fmt.Sprintf("%v: %v,", k, this.Exports[k])

View file

@ -27,16 +27,14 @@ import _ "github.com/gogo/protobuf/types"
import time "time"
import (
context "golang.org/x/net/context"
grpc "google.golang.org/grpc"
)
import context "golang.org/x/net/context"
import grpc "google.golang.org/grpc"
import github_com_gogo_protobuf_types "github.com/gogo/protobuf/types"
import types "github.com/gogo/protobuf/types"
import strings "strings"
import reflect "reflect"
import github_com_gogo_protobuf_sortkeys "github.com/gogo/protobuf/sortkeys"
import sortkeys "github.com/gogo/protobuf/sortkeys"
import io "io"
@ -290,8 +288,8 @@ func (m *Lease) MarshalTo(dAtA []byte) (int, error) {
}
dAtA[i] = 0x12
i++
i = encodeVarintLeases(dAtA, i, uint64(github_com_gogo_protobuf_types.SizeOfStdTime(m.CreatedAt)))
n1, err := github_com_gogo_protobuf_types.StdTimeMarshalTo(m.CreatedAt, dAtA[i:])
i = encodeVarintLeases(dAtA, i, uint64(types.SizeOfStdTime(m.CreatedAt)))
n1, err := types.StdTimeMarshalTo(m.CreatedAt, dAtA[i:])
if err != nil {
return 0, err
}
@ -488,7 +486,7 @@ func (m *Lease) Size() (n int) {
if l > 0 {
n += 1 + l + sovLeases(uint64(l))
}
l = github_com_gogo_protobuf_types.SizeOfStdTime(m.CreatedAt)
l = types.SizeOfStdTime(m.CreatedAt)
n += 1 + l + sovLeases(uint64(l))
if len(m.Labels) > 0 {
for k, v := range m.Labels {
@ -584,7 +582,7 @@ func (this *Lease) String() string {
for k, _ := range this.Labels {
keysForLabels = append(keysForLabels, k)
}
github_com_gogo_protobuf_sortkeys.Strings(keysForLabels)
sortkeys.Strings(keysForLabels)
mapStringForLabels := "map[string]string{"
for _, k := range keysForLabels {
mapStringForLabels += fmt.Sprintf("%v: %v,", k, this.Labels[k])
@ -606,7 +604,7 @@ func (this *CreateRequest) String() string {
for k, _ := range this.Labels {
keysForLabels = append(keysForLabels, k)
}
github_com_gogo_protobuf_sortkeys.Strings(keysForLabels)
sortkeys.Strings(keysForLabels)
mapStringForLabels := "map[string]string{"
for _, k := range keysForLabels {
mapStringForLabels += fmt.Sprintf("%v: %v,", k, this.Labels[k])
@ -751,7 +749,7 @@ func (m *Lease) Unmarshal(dAtA []byte) error {
if postIndex > l {
return io.ErrUnexpectedEOF
}
if err := github_com_gogo_protobuf_types.StdTimeUnmarshal(&m.CreatedAt, dAtA[iNdEx:postIndex]); err != nil {
if err := types.StdTimeUnmarshal(&m.CreatedAt, dAtA[iNdEx:postIndex]); err != nil {
return err
}
iNdEx = postIndex

View file

@ -29,14 +29,12 @@ import math "math"
import google_protobuf1 "github.com/gogo/protobuf/types"
import google_protobuf2 "github.com/gogo/protobuf/types"
import (
context "golang.org/x/net/context"
grpc "google.golang.org/grpc"
)
import context "golang.org/x/net/context"
import grpc "google.golang.org/grpc"
import strings "strings"
import reflect "reflect"
import github_com_gogo_protobuf_sortkeys "github.com/gogo/protobuf/sortkeys"
import sortkeys "github.com/gogo/protobuf/sortkeys"
import io "io"
@ -787,7 +785,7 @@ func (this *Namespace) String() string {
for k, _ := range this.Labels {
keysForLabels = append(keysForLabels, k)
}
github_com_gogo_protobuf_sortkeys.Strings(keysForLabels)
sortkeys.Strings(keysForLabels)
mapStringForLabels := "map[string]string{"
for _, k := range keysForLabels {
mapStringForLabels += fmt.Sprintf("%v: %v,", k, this.Labels[k])

View file

@ -40,16 +40,14 @@ import containerd_types "github.com/containerd/containerd/api/types"
import time "time"
import (
context "golang.org/x/net/context"
grpc "google.golang.org/grpc"
)
import context "golang.org/x/net/context"
import grpc "google.golang.org/grpc"
import github_com_gogo_protobuf_types "github.com/gogo/protobuf/types"
import types "github.com/gogo/protobuf/types"
import strings "strings"
import reflect "reflect"
import github_com_gogo_protobuf_sortkeys "github.com/gogo/protobuf/sortkeys"
import sortkeys "github.com/gogo/protobuf/sortkeys"
import io "io"
@ -1027,16 +1025,16 @@ func (m *Info) MarshalTo(dAtA []byte) (int, error) {
}
dAtA[i] = 0x22
i++
i = encodeVarintSnapshots(dAtA, i, uint64(github_com_gogo_protobuf_types.SizeOfStdTime(m.CreatedAt)))
n1, err := github_com_gogo_protobuf_types.StdTimeMarshalTo(m.CreatedAt, dAtA[i:])
i = encodeVarintSnapshots(dAtA, i, uint64(types.SizeOfStdTime(m.CreatedAt)))
n1, err := types.StdTimeMarshalTo(m.CreatedAt, dAtA[i:])
if err != nil {
return 0, err
}
i += n1
dAtA[i] = 0x2a
i++
i = encodeVarintSnapshots(dAtA, i, uint64(github_com_gogo_protobuf_types.SizeOfStdTime(m.UpdatedAt)))
n2, err := github_com_gogo_protobuf_types.StdTimeMarshalTo(m.UpdatedAt, dAtA[i:])
i = encodeVarintSnapshots(dAtA, i, uint64(types.SizeOfStdTime(m.UpdatedAt)))
n2, err := types.StdTimeMarshalTo(m.UpdatedAt, dAtA[i:])
if err != nil {
return 0, err
}
@ -1446,9 +1444,9 @@ func (m *Info) Size() (n int) {
if m.Kind != 0 {
n += 1 + sovSnapshots(uint64(m.Kind))
}
l = github_com_gogo_protobuf_types.SizeOfStdTime(m.CreatedAt)
l = types.SizeOfStdTime(m.CreatedAt)
n += 1 + l + sovSnapshots(uint64(l))
l = github_com_gogo_protobuf_types.SizeOfStdTime(m.UpdatedAt)
l = types.SizeOfStdTime(m.UpdatedAt)
n += 1 + l + sovSnapshots(uint64(l))
if len(m.Labels) > 0 {
for k, v := range m.Labels {
@ -1562,7 +1560,7 @@ func (this *PrepareSnapshotRequest) String() string {
for k, _ := range this.Labels {
keysForLabels = append(keysForLabels, k)
}
github_com_gogo_protobuf_sortkeys.Strings(keysForLabels)
sortkeys.Strings(keysForLabels)
mapStringForLabels := "map[string]string{"
for _, k := range keysForLabels {
mapStringForLabels += fmt.Sprintf("%v: %v,", k, this.Labels[k])
@ -1595,7 +1593,7 @@ func (this *ViewSnapshotRequest) String() string {
for k, _ := range this.Labels {
keysForLabels = append(keysForLabels, k)
}
github_com_gogo_protobuf_sortkeys.Strings(keysForLabels)
sortkeys.Strings(keysForLabels)
mapStringForLabels := "map[string]string{"
for _, k := range keysForLabels {
mapStringForLabels += fmt.Sprintf("%v: %v,", k, this.Labels[k])
@ -1660,7 +1658,7 @@ func (this *CommitSnapshotRequest) String() string {
for k, _ := range this.Labels {
keysForLabels = append(keysForLabels, k)
}
github_com_gogo_protobuf_sortkeys.Strings(keysForLabels)
sortkeys.Strings(keysForLabels)
mapStringForLabels := "map[string]string{"
for _, k := range keysForLabels {
mapStringForLabels += fmt.Sprintf("%v: %v,", k, this.Labels[k])
@ -1694,7 +1692,7 @@ func (this *Info) String() string {
for k, _ := range this.Labels {
keysForLabels = append(keysForLabels, k)
}
github_com_gogo_protobuf_sortkeys.Strings(keysForLabels)
sortkeys.Strings(keysForLabels)
mapStringForLabels := "map[string]string{"
for _, k := range keysForLabels {
mapStringForLabels += fmt.Sprintf("%v: %v,", k, this.Labels[k])
@ -3257,7 +3255,7 @@ func (m *Info) Unmarshal(dAtA []byte) error {
if postIndex > l {
return io.ErrUnexpectedEOF
}
if err := github_com_gogo_protobuf_types.StdTimeUnmarshal(&m.CreatedAt, dAtA[iNdEx:postIndex]); err != nil {
if err := types.StdTimeUnmarshal(&m.CreatedAt, dAtA[iNdEx:postIndex]); err != nil {
return err
}
iNdEx = postIndex
@ -3287,7 +3285,7 @@ func (m *Info) Unmarshal(dAtA []byte) error {
if postIndex > l {
return io.ErrUnexpectedEOF
}
if err := github_com_gogo_protobuf_types.StdTimeUnmarshal(&m.UpdatedAt, dAtA[iNdEx:postIndex]); err != nil {
if err := types.StdTimeUnmarshal(&m.UpdatedAt, dAtA[iNdEx:postIndex]); err != nil {
return err
}
iNdEx = postIndex

View file

@ -54,12 +54,10 @@ import _ "github.com/gogo/protobuf/types"
import time "time"
import github_com_opencontainers_go_digest "github.com/opencontainers/go-digest"
import (
context "golang.org/x/net/context"
grpc "google.golang.org/grpc"
)
import context "golang.org/x/net/context"
import grpc "google.golang.org/grpc"
import github_com_gogo_protobuf_types "github.com/gogo/protobuf/types"
import types "github.com/gogo/protobuf/types"
import strings "strings"
import reflect "reflect"
@ -1198,8 +1196,8 @@ func (m *DeleteResponse) MarshalTo(dAtA []byte) (int, error) {
}
dAtA[i] = 0x22
i++
i = encodeVarintTasks(dAtA, i, uint64(github_com_gogo_protobuf_types.SizeOfStdTime(m.ExitedAt)))
n3, err := github_com_gogo_protobuf_types.StdTimeMarshalTo(m.ExitedAt, dAtA[i:])
i = encodeVarintTasks(dAtA, i, uint64(types.SizeOfStdTime(m.ExitedAt)))
n3, err := types.StdTimeMarshalTo(m.ExitedAt, dAtA[i:])
if err != nil {
return 0, err
}
@ -1881,8 +1879,8 @@ func (m *WaitResponse) MarshalTo(dAtA []byte) (int, error) {
}
dAtA[i] = 0x12
i++
i = encodeVarintTasks(dAtA, i, uint64(github_com_gogo_protobuf_types.SizeOfStdTime(m.ExitedAt)))
n8, err := github_com_gogo_protobuf_types.StdTimeMarshalTo(m.ExitedAt, dAtA[i:])
i = encodeVarintTasks(dAtA, i, uint64(types.SizeOfStdTime(m.ExitedAt)))
n8, err := types.StdTimeMarshalTo(m.ExitedAt, dAtA[i:])
if err != nil {
return 0, err
}
@ -1997,7 +1995,7 @@ func (m *DeleteResponse) Size() (n int) {
if m.ExitStatus != 0 {
n += 1 + sovTasks(uint64(m.ExitStatus))
}
l = github_com_gogo_protobuf_types.SizeOfStdTime(m.ExitedAt)
l = types.SizeOfStdTime(m.ExitedAt)
n += 1 + l + sovTasks(uint64(l))
return n
}
@ -2288,7 +2286,7 @@ func (m *WaitResponse) Size() (n int) {
if m.ExitStatus != 0 {
n += 1 + sovTasks(uint64(m.ExitStatus))
}
l = github_com_gogo_protobuf_types.SizeOfStdTime(m.ExitedAt)
l = types.SizeOfStdTime(m.ExitedAt)
n += 1 + l + sovTasks(uint64(l))
return n
}
@ -3375,7 +3373,7 @@ func (m *DeleteResponse) Unmarshal(dAtA []byte) error {
if postIndex > l {
return io.ErrUnexpectedEOF
}
if err := github_com_gogo_protobuf_types.StdTimeUnmarshal(&m.ExitedAt, dAtA[iNdEx:postIndex]); err != nil {
if err := types.StdTimeUnmarshal(&m.ExitedAt, dAtA[iNdEx:postIndex]); err != nil {
return err
}
iNdEx = postIndex
@ -5572,7 +5570,7 @@ func (m *WaitResponse) Unmarshal(dAtA []byte) error {
if postIndex > l {
return io.ErrUnexpectedEOF
}
if err := github_com_gogo_protobuf_types.StdTimeUnmarshal(&m.ExitedAt, dAtA[iNdEx:postIndex]); err != nil {
if err := types.StdTimeUnmarshal(&m.ExitedAt, dAtA[iNdEx:postIndex]); err != nil {
return err
}
iNdEx = postIndex

View file

@ -19,10 +19,8 @@ import google_protobuf "github.com/gogo/protobuf/types"
// skipping weak import gogoproto "github.com/gogo/protobuf/gogoproto"
import (
context "golang.org/x/net/context"
grpc "google.golang.org/grpc"
)
import context "golang.org/x/net/context"
import grpc "google.golang.org/grpc"
import strings "strings"
import reflect "reflect"

View file

@ -13,7 +13,7 @@ import _ "github.com/gogo/protobuf/types"
import time "time"
import github_com_gogo_protobuf_types "github.com/gogo/protobuf/types"
import types1 "github.com/gogo/protobuf/types"
import strings "strings"
import reflect "reflect"
@ -56,8 +56,8 @@ func (m *Metric) MarshalTo(dAtA []byte) (int, error) {
_ = l
dAtA[i] = 0xa
i++
i = encodeVarintMetrics(dAtA, i, uint64(github_com_gogo_protobuf_types.SizeOfStdTime(m.Timestamp)))
n1, err := github_com_gogo_protobuf_types.StdTimeMarshalTo(m.Timestamp, dAtA[i:])
i = encodeVarintMetrics(dAtA, i, uint64(types1.SizeOfStdTime(m.Timestamp)))
n1, err := types1.StdTimeMarshalTo(m.Timestamp, dAtA[i:])
if err != nil {
return 0, err
}
@ -93,7 +93,7 @@ func encodeVarintMetrics(dAtA []byte, offset int, v uint64) int {
func (m *Metric) Size() (n int) {
var l int
_ = l
l = github_com_gogo_protobuf_types.SizeOfStdTime(m.Timestamp)
l = types1.SizeOfStdTime(m.Timestamp)
n += 1 + l + sovMetrics(uint64(l))
l = len(m.ID)
if l > 0 {
@ -194,7 +194,7 @@ func (m *Metric) Unmarshal(dAtA []byte) error {
if postIndex > l {
return io.ErrUnexpectedEOF
}
if err := github_com_gogo_protobuf_types.StdTimeUnmarshal(&m.Timestamp, dAtA[iNdEx:postIndex]); err != nil {
if err := types1.StdTimeUnmarshal(&m.Timestamp, dAtA[iNdEx:postIndex]); err != nil {
return err
}
iNdEx = postIndex

View file

@ -23,7 +23,7 @@ import google_protobuf2 "github.com/gogo/protobuf/types"
import time "time"
import github_com_gogo_protobuf_types "github.com/gogo/protobuf/types"
import types "github.com/gogo/protobuf/types"
import strings "strings"
import reflect "reflect"
@ -182,8 +182,8 @@ func (m *Process) MarshalTo(dAtA []byte) (int, error) {
}
dAtA[i] = 0x52
i++
i = encodeVarintTask(dAtA, i, uint64(github_com_gogo_protobuf_types.SizeOfStdTime(m.ExitedAt)))
n1, err := github_com_gogo_protobuf_types.StdTimeMarshalTo(m.ExitedAt, dAtA[i:])
i = encodeVarintTask(dAtA, i, uint64(types.SizeOfStdTime(m.ExitedAt)))
n1, err := types.StdTimeMarshalTo(m.ExitedAt, dAtA[i:])
if err != nil {
return 0, err
}
@ -268,7 +268,7 @@ func (m *Process) Size() (n int) {
if m.ExitStatus != 0 {
n += 1 + sovTask(uint64(m.ExitStatus))
}
l = github_com_gogo_protobuf_types.SizeOfStdTime(m.ExitedAt)
l = types.SizeOfStdTime(m.ExitedAt)
n += 1 + l + sovTask(uint64(l))
return n
}
@ -614,7 +614,7 @@ func (m *Process) Unmarshal(dAtA []byte) error {
if postIndex > l {
return io.ErrUnexpectedEOF
}
if err := github_com_gogo_protobuf_types.StdTimeUnmarshal(&m.ExitedAt, dAtA[iNdEx:postIndex]); err != nil {
if err := types.StdTimeUnmarshal(&m.ExitedAt, dAtA[iNdEx:postIndex]); err != nil {
return err
}
iNdEx = postIndex

View file

@ -23,7 +23,7 @@ import (
"strings"
"time"
"github.com/dmcgowan/go-tar"
"archive/tar"
)
// Forked from https://github.com/golang/go/blob/master/src/archive/tar/strconv.go

View file

@ -17,6 +17,7 @@
package archive
import (
"archive/tar"
"context"
"fmt"
"io"
@ -31,7 +32,6 @@ import (
"github.com/containerd/containerd/log"
"github.com/containerd/continuity/fs"
"github.com/dmcgowan/go-tar"
"github.com/pkg/errors"
)
@ -199,7 +199,7 @@ func applyNaive(ctx context.Context, root string, tr *tar.Reader, options ApplyO
basename := filepath.Base(hdr.Name)
aufsHardlinks[basename] = hdr
if aufsTempdir == "" {
if aufsTempdir, err = ioutil.TempDir("", "dockerplnk"); err != nil {
if aufsTempdir, err = ioutil.TempDir(os.Getenv("XDG_RUNTIME_DIR"), "dockerplnk"); err != nil {
return 0, err
}
defer os.RemoveAll(aufsTempdir)
@ -465,7 +465,10 @@ func (cw *changeWriter) HandleChange(k fs.ChangeKind, p string, f os.FileInfo, e
source = filepath.Join(cw.source, p)
)
if f.Mode()&os.ModeSymlink != 0 {
switch {
case f.Mode()&os.ModeSocket != 0:
return nil // ignore sockets
case f.Mode()&os.ModeSymlink != 0:
if link, err = os.Readlink(source); err != nil {
return err
}

View file

@ -19,13 +19,13 @@
package archive
import (
"archive/tar"
"context"
"os"
"sync"
"syscall"
"github.com/containerd/continuity/sysx"
"github.com/dmcgowan/go-tar"
"github.com/opencontainers/runc/libcontainer/system"
"github.com/pkg/errors"
"golang.org/x/sys/unix"
@ -87,10 +87,6 @@ func mkdir(path string, perm os.FileMode) error {
return os.Chmod(path, perm)
}
func skipFile(*tar.Header) bool {
return false
}
var (
inUserNS bool
nsOnce sync.Once
@ -100,15 +96,22 @@ func setInUserNS() {
inUserNS = system.RunningInUserNS()
}
// handleTarTypeBlockCharFifo is an OS-specific helper function used by
// createTarFile to handle the following types of header: Block; Char; Fifo
func handleTarTypeBlockCharFifo(hdr *tar.Header, path string) error {
nsOnce.Do(setInUserNS)
if inUserNS {
func skipFile(hdr *tar.Header) bool {
switch hdr.Typeflag {
case tar.TypeBlock, tar.TypeChar:
// cannot create a device if running in user namespace
return nil
nsOnce.Do(setInUserNS)
return inUserNS
default:
return false
}
}
// handleTarTypeBlockCharFifo is an OS-specific helper function used by
// createTarFile to handle the following types of header: Block; Char; Fifo.
// This function must not be called for Block and Char when running in userns.
// (skipFile() should return true for them.)
func handleTarTypeBlockCharFifo(hdr *tar.Header, path string) error {
mode := uint32(hdr.Mode & 07777)
switch hdr.Typeflag {
case tar.TypeBlock:

View file

@ -19,6 +19,7 @@
package archive
import (
"archive/tar"
"bufio"
"context"
"encoding/base64"
@ -34,9 +35,7 @@ import (
"github.com/Microsoft/go-winio"
"github.com/Microsoft/hcsshim"
"github.com/containerd/containerd/log"
"github.com/containerd/containerd/sys"
"github.com/dmcgowan/go-tar"
)
const (
@ -180,8 +179,12 @@ func applyWindowsLayer(ctx context.Context, root string, tr *tar.Reader, options
return 0, err
}
defer func() {
if err := w.Close(); err != nil {
log.G(ctx).Errorf("failed to close layer writer: %v", err)
if err2 := w.Close(); err2 != nil {
// This error should not be discarded as a failure here
// could result in an invalid layer on disk
if err == nil {
err = err2
}
}
}()

View file

@ -21,6 +21,7 @@ import (
"fmt"
"io"
"os"
"path/filepath"
"sync"
"github.com/containerd/containerd/defaults"
@ -213,3 +214,44 @@ type DirectIO struct {
}
var _ IO = &DirectIO{}
// LogFile creates a file on disk that logs the task's STDOUT,STDERR.
// If the log file already exists, the logs will be appended to the file.
func LogFile(path string) Creator {
return func(_ string) (IO, error) {
if err := os.MkdirAll(filepath.Dir(path), 0755); err != nil {
return nil, err
}
f, err := os.OpenFile(path, os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0644)
if err != nil {
return nil, err
}
f.Close()
return &logIO{
config: Config{
Stdout: path,
Stderr: path,
},
}, nil
}
}
type logIO struct {
config Config
}
func (l *logIO) Config() Config {
return l.config
}
func (l *logIO) Cancel() {
}
func (l *logIO) Wait() {
}
func (l *logIO) Close() error {
return nil
}

View file

@ -141,8 +141,18 @@ func openFifos(ctx context.Context, fifos *FIFOSet) (pipes, error) {
// NewDirectIO returns an IO implementation that exposes the IO streams as io.ReadCloser
// and io.WriteCloser.
func NewDirectIO(ctx context.Context, fifos *FIFOSet) (*DirectIO, error) {
return newDirectIO(ctx, fifos, false)
}
// NewDirectIOWithTerminal returns an IO implementation that exposes the streams with terminal enabled
func NewDirectIOWithTerminal(ctx context.Context, fifos *FIFOSet) (*DirectIO, error) {
return newDirectIO(ctx, fifos, true)
}
func newDirectIO(ctx context.Context, fifos *FIFOSet, terminal bool) (*DirectIO, error) {
ctx, cancel := context.WithCancel(ctx)
pipes, err := openFifos(ctx, fifos)
fifos.Config.Terminal = terminal
return &DirectIO{
pipes: pipes,
cio: cio{

View file

@ -19,10 +19,10 @@ package containerd
import (
"context"
"fmt"
"io"
"net/http"
"runtime"
"strconv"
"sync"
"time"
containersapi "github.com/containerd/containerd/api/services/containers/v1"
@ -31,22 +31,26 @@ import (
eventsapi "github.com/containerd/containerd/api/services/events/v1"
imagesapi "github.com/containerd/containerd/api/services/images/v1"
introspectionapi "github.com/containerd/containerd/api/services/introspection/v1"
leasesapi "github.com/containerd/containerd/api/services/leases/v1"
namespacesapi "github.com/containerd/containerd/api/services/namespaces/v1"
snapshotsapi "github.com/containerd/containerd/api/services/snapshots/v1"
"github.com/containerd/containerd/api/services/tasks/v1"
versionservice "github.com/containerd/containerd/api/services/version/v1"
"github.com/containerd/containerd/containers"
"github.com/containerd/containerd/content"
"github.com/containerd/containerd/dialer"
contentproxy "github.com/containerd/containerd/content/proxy"
"github.com/containerd/containerd/defaults"
"github.com/containerd/containerd/errdefs"
"github.com/containerd/containerd/events"
"github.com/containerd/containerd/images"
"github.com/containerd/containerd/namespaces"
"github.com/containerd/containerd/platforms"
"github.com/containerd/containerd/pkg/dialer"
"github.com/containerd/containerd/plugin"
"github.com/containerd/containerd/remotes"
"github.com/containerd/containerd/remotes/docker"
"github.com/containerd/containerd/remotes/docker/schema1"
"github.com/containerd/containerd/snapshots"
snproxy "github.com/containerd/containerd/snapshots/proxy"
"github.com/containerd/typeurl"
ptypes "github.com/gogo/protobuf/types"
ocispec "github.com/opencontainers/image-spec/specs-go/v1"
@ -75,54 +79,79 @@ func New(address string, opts ...ClientOpt) (*Client, error) {
return nil, err
}
}
gopts := []grpc.DialOption{
grpc.WithBlock(),
grpc.WithInsecure(),
grpc.WithTimeout(60 * time.Second),
grpc.FailOnNonTempDialError(true),
grpc.WithBackoffMaxDelay(3 * time.Second),
grpc.WithDialer(dialer.Dialer),
c := &Client{
runtime: fmt.Sprintf("%s.%s", plugin.RuntimePlugin, runtime.GOOS),
}
if len(copts.dialOptions) > 0 {
gopts = copts.dialOptions
if copts.services != nil {
c.services = *copts.services
}
if copts.defaultns != "" {
unary, stream := newNSInterceptors(copts.defaultns)
gopts = append(gopts,
grpc.WithUnaryInterceptor(unary),
grpc.WithStreamInterceptor(stream),
)
}
connector := func() (*grpc.ClientConn, error) {
conn, err := grpc.Dial(dialer.DialAddress(address), gopts...)
if err != nil {
return nil, errors.Wrapf(err, "failed to dial %q", address)
if address != "" {
gopts := []grpc.DialOption{
grpc.WithBlock(),
grpc.WithInsecure(),
grpc.FailOnNonTempDialError(true),
grpc.WithBackoffMaxDelay(3 * time.Second),
grpc.WithDialer(dialer.Dialer),
// TODO(stevvooe): We may need to allow configuration of this on the client.
grpc.WithDefaultCallOptions(grpc.MaxCallRecvMsgSize(defaults.DefaultMaxRecvMsgSize)),
grpc.WithDefaultCallOptions(grpc.MaxCallSendMsgSize(defaults.DefaultMaxSendMsgSize)),
}
return conn, nil
if len(copts.dialOptions) > 0 {
gopts = copts.dialOptions
}
if copts.defaultns != "" {
unary, stream := newNSInterceptors(copts.defaultns)
gopts = append(gopts,
grpc.WithUnaryInterceptor(unary),
grpc.WithStreamInterceptor(stream),
)
}
connector := func() (*grpc.ClientConn, error) {
ctx, cancel := context.WithTimeout(context.Background(), 60*time.Second)
defer cancel()
conn, err := grpc.DialContext(ctx, dialer.DialAddress(address), gopts...)
if err != nil {
return nil, errors.Wrapf(err, "failed to dial %q", address)
}
return conn, nil
}
conn, err := connector()
if err != nil {
return nil, err
}
c.conn, c.connector = conn, connector
}
conn, err := connector()
if err != nil {
return nil, err
if copts.services == nil && c.conn == nil {
return nil, errors.New("no grpc connection or services is available")
}
return &Client{
conn: conn,
connector: connector,
runtime: fmt.Sprintf("%s.%s", plugin.RuntimePlugin, runtime.GOOS),
}, nil
return c, nil
}
// NewWithConn returns a new containerd client that is connected to the containerd
// instance provided by the connection
func NewWithConn(conn *grpc.ClientConn, opts ...ClientOpt) (*Client, error) {
return &Client{
var copts clientOpts
for _, o := range opts {
if err := o(&copts); err != nil {
return nil, err
}
}
c := &Client{
conn: conn,
runtime: fmt.Sprintf("%s.%s", plugin.RuntimePlugin, runtime.GOOS),
}, nil
}
if copts.services != nil {
c.services = *copts.services
}
return c, nil
}
// Client is the client to interact with containerd and its various services
// using a uniform interface
type Client struct {
services
connMu sync.Mutex
conn *grpc.ClientConn
runtime string
connector func() (*grpc.ClientConn, error)
@ -133,6 +162,8 @@ func (c *Client) Reconnect() error {
if c.connector == nil {
return errors.New("unable to reconnect to containerd, no connector available")
}
c.connMu.Lock()
defer c.connMu.Unlock()
c.conn.Close()
conn, err := c.connector()
if err != nil {
@ -149,6 +180,12 @@ func (c *Client) Reconnect() error {
// connection. A timeout can be set in the context to ensure it returns
// early.
func (c *Client) IsServing(ctx context.Context) (bool, error) {
c.connMu.Lock()
if c.conn == nil {
c.connMu.Unlock()
return false, errors.New("no grpc connection available")
}
c.connMu.Unlock()
r, err := c.HealthService().Check(ctx, &grpc_health_v1.HealthCheckRequest{}, grpc.FailFast(false))
if err != nil {
return false, err
@ -176,7 +213,7 @@ func (c *Client) NewContainer(ctx context.Context, id string, opts ...NewContain
if err != nil {
return nil, err
}
defer done()
defer done(ctx)
container := containers.Container{
ID: id,
@ -212,6 +249,10 @@ type RemoteContext struct {
// If no resolver is provided, defaults to Docker registry resolver.
Resolver remotes.Resolver
// Platforms defines which platforms to handle when doing the image operation.
// If this field is empty, content for all platforms will be pulled.
Platforms []string
// Unpack is done after an image is pulled to extract into a snapshotter.
// If an image is not unpacked on pull, it can be unpacked any time
// afterwards. Unpacking is required to run an image.
@ -257,12 +298,13 @@ func (c *Client) Pull(ctx context.Context, ref string, opts ...RemoteOpt) (Image
if err != nil {
return nil, err
}
defer done()
defer done(ctx)
name, desc, err := pullCtx.Resolver.Resolve(ctx, ref)
if err != nil {
return nil, errors.Wrapf(err, "failed to resolve reference %q", ref)
}
fetcher, err := pullCtx.Resolver.Fetcher(ctx, name)
if err != nil {
return nil, errors.Wrapf(err, "failed to get fetcher for %q", name)
@ -280,8 +322,8 @@ func (c *Client) Pull(ctx context.Context, ref string, opts ...RemoteOpt) (Image
childrenHandler := images.ChildrenHandler(store)
// Set any children labels for that content
childrenHandler = images.SetChildrenLabels(store, childrenHandler)
// Filter the childen by the platform
childrenHandler = images.FilterPlatform(platforms.Default(), childrenHandler)
// Filter children by platforms
childrenHandler = images.FilterPlatforms(childrenHandler, pullCtx.Platforms...)
handler = images.Handlers(append(pullCtx.BaseHandlers,
remotes.FetchHandler(store, fetcher),
@ -299,38 +341,43 @@ func (c *Client) Pull(ctx context.Context, ref string, opts ...RemoteOpt) (Image
}
}
imgrec := images.Image{
Name: name,
Target: desc,
Labels: pullCtx.Labels,
img := &image{
client: c,
i: images.Image{
Name: name,
Target: desc,
Labels: pullCtx.Labels,
},
}
if pullCtx.Unpack {
if err := img.Unpack(ctx, pullCtx.Snapshotter); err != nil {
return nil, errors.Wrapf(err, "failed to unpack image on snapshotter %s", pullCtx.Snapshotter)
}
}
is := c.ImageService()
if created, err := is.Create(ctx, imgrec); err != nil {
if !errdefs.IsAlreadyExists(err) {
return nil, err
}
for {
if created, err := is.Create(ctx, img.i); err != nil {
if !errdefs.IsAlreadyExists(err) {
return nil, err
}
updated, err := is.Update(ctx, imgrec)
if err != nil {
return nil, err
}
updated, err := is.Update(ctx, img.i)
if err != nil {
// if image was removed, try create again
if errdefs.IsNotFound(err) {
continue
}
return nil, err
}
imgrec = updated
} else {
imgrec = created
}
img := &image{
client: c,
i: imgrec,
}
if pullCtx.Unpack {
if err := img.Unpack(ctx, pullCtx.Snapshotter); err != nil {
errors.Wrapf(err, "failed to unpack image on snapshotter %s", pullCtx.Snapshotter)
img.i = updated
} else {
img.i = created
}
return img, nil
}
return img, nil
}
// Push uploads the provided content to a remote resource
@ -347,7 +394,7 @@ func (c *Client) Push(ctx context.Context, ref string, desc ocispec.Descriptor,
return err
}
return remotes.PushContent(ctx, pusher, desc, c.ContentStore(), pushCtx.BaseHandlers...)
return remotes.PushContent(ctx, pusher, desc, c.ContentStore(), pushCtx.Platforms, pushCtx.BaseHandlers...)
}
// GetImage returns an existing image
@ -385,82 +432,73 @@ func (c *Client) ListImages(ctx context.Context, filters ...string) ([]Image, er
//
// The subscriber can stop receiving events by canceling the provided context.
// The errs channel will be closed and return a nil error.
func (c *Client) Subscribe(ctx context.Context, filters ...string) (ch <-chan *eventsapi.Envelope, errs <-chan error) {
var (
evq = make(chan *eventsapi.Envelope)
errq = make(chan error, 1)
)
errs = errq
ch = evq
session, err := c.EventService().Subscribe(ctx, &eventsapi.SubscribeRequest{
Filters: filters,
})
if err != nil {
errq <- err
close(errq)
return
}
go func() {
defer close(errq)
for {
ev, err := session.Recv()
if err != nil {
errq <- err
return
}
select {
case evq <- ev:
case <-ctx.Done():
return
}
}
}()
return ch, errs
func (c *Client) Subscribe(ctx context.Context, filters ...string) (ch <-chan *events.Envelope, errs <-chan error) {
return c.EventService().Subscribe(ctx, filters...)
}
// Close closes the clients connection to containerd
func (c *Client) Close() error {
return c.conn.Close()
c.connMu.Lock()
defer c.connMu.Unlock()
if c.conn != nil {
return c.conn.Close()
}
return nil
}
// NamespaceService returns the underlying Namespaces Store
func (c *Client) NamespaceService() namespaces.Store {
if c.namespaceStore != nil {
return c.namespaceStore
}
return NewNamespaceStoreFromClient(namespacesapi.NewNamespacesClient(c.conn))
}
// ContainerService returns the underlying container Store
func (c *Client) ContainerService() containers.Store {
if c.containerStore != nil {
return c.containerStore
}
return NewRemoteContainerStore(containersapi.NewContainersClient(c.conn))
}
// ContentStore returns the underlying content Store
func (c *Client) ContentStore() content.Store {
return NewContentStoreFromClient(contentapi.NewContentClient(c.conn))
if c.contentStore != nil {
return c.contentStore
}
return contentproxy.NewContentStore(contentapi.NewContentClient(c.conn))
}
// SnapshotService returns the underlying snapshotter for the provided snapshotter name
func (c *Client) SnapshotService(snapshotterName string) snapshots.Snapshotter {
return NewSnapshotterFromClient(snapshotsapi.NewSnapshotsClient(c.conn), snapshotterName)
if c.snapshotters != nil {
return c.snapshotters[snapshotterName]
}
return snproxy.NewSnapshotter(snapshotsapi.NewSnapshotsClient(c.conn), snapshotterName)
}
// TaskService returns the underlying TasksClient
func (c *Client) TaskService() tasks.TasksClient {
if c.taskService != nil {
return c.taskService
}
return tasks.NewTasksClient(c.conn)
}
// ImageService returns the underlying image Store
func (c *Client) ImageService() images.Store {
if c.imageStore != nil {
return c.imageStore
}
return NewImageStoreFromClient(imagesapi.NewImagesClient(c.conn))
}
// DiffService returns the underlying Differ
func (c *Client) DiffService() DiffService {
if c.diffService != nil {
return c.diffService
}
return NewDiffServiceFromClient(diffapi.NewDiffClient(c.conn))
}
@ -469,14 +507,25 @@ func (c *Client) IntrospectionService() introspectionapi.IntrospectionClient {
return introspectionapi.NewIntrospectionClient(c.conn)
}
// LeasesService returns the underlying Leases Client
func (c *Client) LeasesService() leasesapi.LeasesClient {
if c.leasesService != nil {
return c.leasesService
}
return leasesapi.NewLeasesClient(c.conn)
}
// HealthService returns the underlying GRPC HealthClient
func (c *Client) HealthService() grpc_health_v1.HealthClient {
return grpc_health_v1.NewHealthClient(c.conn)
}
// EventService returns the underlying EventsClient
func (c *Client) EventService() eventsapi.EventsClient {
return eventsapi.NewEventsClient(c.conn)
// EventService returns the underlying event service
func (c *Client) EventService() EventService {
if c.eventService != nil {
return c.eventService
}
return NewEventServiceFromClient(eventsapi.NewEventsClient(c.conn))
}
// VersionService returns the underlying VersionClient
@ -494,6 +543,12 @@ type Version struct {
// Version returns the version of containerd that the client is connected to
func (c *Client) Version(ctx context.Context) (Version, error) {
c.connMu.Lock()
if c.conn == nil {
c.connMu.Unlock()
return Version{}, errors.New("no grpc connection available")
}
c.connMu.Unlock()
response, err := c.VersionService().Version(ctx, &ptypes.Empty{})
if err != nil {
return Version{}, err
@ -503,98 +558,3 @@ func (c *Client) Version(ctx context.Context) (Version, error) {
Revision: response.Revision,
}, nil
}
type importOpts struct {
}
// ImportOpt allows the caller to specify import specific options
type ImportOpt func(c *importOpts) error
func resolveImportOpt(opts ...ImportOpt) (importOpts, error) {
var iopts importOpts
for _, o := range opts {
if err := o(&iopts); err != nil {
return iopts, err
}
}
return iopts, nil
}
// Import imports an image from a Tar stream using reader.
// Caller needs to specify importer. Future version may use oci.v1 as the default.
// Note that unreferrenced blobs may be imported to the content store as well.
func (c *Client) Import(ctx context.Context, importer images.Importer, reader io.Reader, opts ...ImportOpt) ([]Image, error) {
_, err := resolveImportOpt(opts...) // unused now
if err != nil {
return nil, err
}
ctx, done, err := c.WithLease(ctx)
if err != nil {
return nil, err
}
defer done()
imgrecs, err := importer.Import(ctx, c.ContentStore(), reader)
if err != nil {
// is.Update() is not called on error
return nil, err
}
is := c.ImageService()
var images []Image
for _, imgrec := range imgrecs {
if updated, err := is.Update(ctx, imgrec, "target"); err != nil {
if !errdefs.IsNotFound(err) {
return nil, err
}
created, err := is.Create(ctx, imgrec)
if err != nil {
return nil, err
}
imgrec = created
} else {
imgrec = updated
}
images = append(images, &image{
client: c,
i: imgrec,
})
}
return images, nil
}
type exportOpts struct {
}
// ExportOpt allows the caller to specify export-specific options
type ExportOpt func(c *exportOpts) error
func resolveExportOpt(opts ...ExportOpt) (exportOpts, error) {
var eopts exportOpts
for _, o := range opts {
if err := o(&eopts); err != nil {
return eopts, err
}
}
return eopts, nil
}
// Export exports an image to a Tar stream.
// OCI format is used by default.
// It is up to caller to put "org.opencontainers.image.ref.name" annotation to desc.
// TODO(AkihiroSuda): support exporting multiple descriptors at once to a single archive stream.
func (c *Client) Export(ctx context.Context, exporter images.Exporter, desc ocispec.Descriptor, opts ...ExportOpt) (io.ReadCloser, error) {
_, err := resolveExportOpt(opts...) // unused now
if err != nil {
return nil, err
}
pr, pw := io.Pipe()
go func() {
pw.CloseWithError(exporter.Export(ctx, c.ContentStore(), desc, pw))
}()
return pr, nil
}

View file

@ -24,6 +24,7 @@ import (
type clientOpts struct {
defaultns string
services *services
dialOptions []grpc.DialOption
}
@ -49,9 +50,35 @@ func WithDialOpts(opts []grpc.DialOption) ClientOpt {
}
}
// WithServices sets services used by the client.
func WithServices(opts ...ServicesOpt) ClientOpt {
return func(c *clientOpts) error {
c.services = &services{}
for _, o := range opts {
o(c.services)
}
return nil
}
}
// RemoteOpt allows the caller to set distribution options for a remote
type RemoteOpt func(*Client, *RemoteContext) error
// WithPlatform allows the caller to specify a platform to retrieve
// content for
func WithPlatform(platform string) RemoteOpt {
return func(_ *Client, c *RemoteContext) error {
for _, p := range c.Platforms {
if p == platform {
return nil
}
}
c.Platforms = append(c.Platforms, platform)
return nil
}
}
// WithPullUnpack is used to unpack an image after pull. This
// uses the snapshotter, content store, and diff service
// configured for the client.

View file

@ -28,9 +28,9 @@ import (
"github.com/containerd/containerd/cio"
"github.com/containerd/containerd/containers"
"github.com/containerd/containerd/errdefs"
"github.com/containerd/containerd/oci"
"github.com/containerd/typeurl"
prototypes "github.com/gogo/protobuf/types"
specs "github.com/opencontainers/runtime-spec/specs-go"
"github.com/pkg/errors"
)
@ -45,7 +45,7 @@ type Container interface {
// NewTask creates a new task based on the container metadata
NewTask(context.Context, cio.Creator, ...NewTaskOpts) (Task, error)
// Spec returns the OCI runtime specification
Spec(context.Context) (*specs.Spec, error)
Spec(context.Context) (*oci.Spec, error)
// Task returns the current task for the container
//
// If cio.Attach options are passed the client will reattach to the IO for the running
@ -126,12 +126,12 @@ func (c *container) SetLabels(ctx context.Context, labels map[string]string) (ma
}
// Spec returns the current OCI specification for the container
func (c *container) Spec(ctx context.Context) (*specs.Spec, error) {
func (c *container) Spec(ctx context.Context) (*oci.Spec, error) {
r, err := c.get(ctx)
if err != nil {
return nil, err
}
var s specs.Spec
var s oci.Spec
if err := json.Unmarshal(r.Spec.Value, &s); err != nil {
return nil, err
}

View file

@ -26,7 +26,6 @@ import (
"github.com/containerd/typeurl"
"github.com/gogo/protobuf/types"
"github.com/opencontainers/image-spec/identity"
specs "github.com/opencontainers/runtime-spec/specs-go"
"github.com/pkg/errors"
)
@ -196,7 +195,7 @@ func WithNewSpec(opts ...oci.SpecOpts) NewContainerOpts {
}
// WithSpec sets the provided spec on the container
func WithSpec(s *specs.Spec, opts ...oci.SpecOpts) NewContainerOpts {
func WithSpec(s *oci.Spec, opts ...oci.SpecOpts) NewContainerOpts {
return func(ctx context.Context, client *Client, c *containers.Container) error {
for _, o := range opts {
if err := o(ctx, client, c, s); err != nil {

View file

@ -20,7 +20,9 @@ import (
"context"
"io"
"io/ioutil"
"math/rand"
"sync"
"time"
"github.com/containerd/containerd/errdefs"
"github.com/opencontainers/go-digest"
@ -64,7 +66,7 @@ func ReadBlob(ctx context.Context, provider Provider, dgst digest.Digest) ([]byt
//
// Copy is buffered, so no need to wrap reader in buffered io.
func WriteBlob(ctx context.Context, cs Ingester, ref string, r io.Reader, size int64, expected digest.Digest, opts ...Opt) error {
cw, err := cs.Writer(ctx, ref, size, expected)
cw, err := OpenWriter(ctx, cs, ref, size, expected)
if err != nil {
if !errdefs.IsAlreadyExists(err) {
return err
@ -77,8 +79,45 @@ func WriteBlob(ctx context.Context, cs Ingester, ref string, r io.Reader, size i
return Copy(ctx, cw, r, size, expected, opts...)
}
// OpenWriter opens a new writer for the given reference, retrying if the writer
// is locked until the reference is available or returns an error.
func OpenWriter(ctx context.Context, cs Ingester, ref string, size int64, expected digest.Digest) (Writer, error) {
var (
cw Writer
err error
retry = 16
)
for {
cw, err = cs.Writer(ctx, ref, size, expected)
if err != nil {
if !errdefs.IsUnavailable(err) {
return nil, err
}
// TODO: Check status to determine if the writer is active,
// continue waiting while active, otherwise return lock
// error or abort. Requires asserting for an ingest manager
select {
case <-time.After(time.Millisecond * time.Duration(rand.Intn(retry))):
if retry < 2048 {
retry = retry << 1
}
continue
case <-ctx.Done():
// Propagate lock error
return nil, err
}
}
break
}
return cw, err
}
// Copy copies data with the expected digest from the reader into the
// provided content store writer.
// provided content store writer. This copy commits the writer.
//
// This is useful when the digest and size are known beforehand. When
// the size or digest is unknown, these values may be empty.
@ -97,10 +136,7 @@ func Copy(ctx context.Context, cw Writer, r io.Reader, size int64, expected dige
}
}
buf := bufPool.Get().(*[]byte)
defer bufPool.Put(buf)
if _, err := io.CopyBuffer(cw, r, *buf); err != nil {
if _, err := copyWithBuffer(cw, r); err != nil {
return err
}
@ -113,6 +149,18 @@ func Copy(ctx context.Context, cw Writer, r io.Reader, size int64, expected dige
return nil
}
// CopyReaderAt copies to a writer from a given reader at for the given
// number of bytes. This copy does not commit the writer.
func CopyReaderAt(cw Writer, ra ReaderAt, n int64) error {
ws, err := cw.Status()
if err != nil {
return err
}
_, err = copyWithBuffer(cw, io.NewSectionReader(ra, ws.Offset, n))
return err
}
// seekReader attempts to seek the reader to the given offset, either by
// resolving `io.Seeker`, by detecting `io.ReaderAt`, or discarding
// up to the given offset.
@ -140,10 +188,7 @@ func seekReader(r io.Reader, offset, size int64) (io.Reader, error) {
}
// well then, let's just discard up to the offset
buf := bufPool.Get().(*[]byte)
defer bufPool.Put(buf)
n, err := io.CopyBuffer(ioutil.Discard, io.LimitReader(r, offset), *buf)
n, err := copyWithBuffer(ioutil.Discard, io.LimitReader(r, offset))
if err != nil {
return nil, errors.Wrap(err, "failed to discard to offset")
}
@ -153,3 +198,10 @@ func seekReader(r io.Reader, offset, size int64) (io.Reader, error) {
return r, nil
}
func copyWithBuffer(dst io.Writer, src io.Reader) (written int64, err error) {
buf := bufPool.Get().(*[]byte)
written, err = io.CopyBuffer(dst, src, *buf)
bufPool.Put(buf)
return
}

View file

@ -14,7 +14,7 @@
limitations under the License.
*/
package containerd
package proxy
import (
"context"

View file

@ -14,7 +14,7 @@
limitations under the License.
*/
package containerd
package proxy
import (
"context"
@ -27,19 +27,20 @@ import (
digest "github.com/opencontainers/go-digest"
)
type remoteContent struct {
type proxyContentStore struct {
client contentapi.ContentClient
}
// NewContentStoreFromClient returns a new content store
func NewContentStoreFromClient(client contentapi.ContentClient) content.Store {
return &remoteContent{
// NewContentStore returns a new content store which communicates over a GRPC
// connection using the containerd content GRPC API.
func NewContentStore(client contentapi.ContentClient) content.Store {
return &proxyContentStore{
client: client,
}
}
func (rs *remoteContent) Info(ctx context.Context, dgst digest.Digest) (content.Info, error) {
resp, err := rs.client.Info(ctx, &contentapi.InfoRequest{
func (pcs *proxyContentStore) Info(ctx context.Context, dgst digest.Digest) (content.Info, error) {
resp, err := pcs.client.Info(ctx, &contentapi.InfoRequest{
Digest: dgst,
})
if err != nil {
@ -49,8 +50,8 @@ func (rs *remoteContent) Info(ctx context.Context, dgst digest.Digest) (content.
return infoFromGRPC(resp.Info), nil
}
func (rs *remoteContent) Walk(ctx context.Context, fn content.WalkFunc, filters ...string) error {
session, err := rs.client.List(ctx, &contentapi.ListContentRequest{
func (pcs *proxyContentStore) Walk(ctx context.Context, fn content.WalkFunc, filters ...string) error {
session, err := pcs.client.List(ctx, &contentapi.ListContentRequest{
Filters: filters,
})
if err != nil {
@ -77,8 +78,8 @@ func (rs *remoteContent) Walk(ctx context.Context, fn content.WalkFunc, filters
return nil
}
func (rs *remoteContent) Delete(ctx context.Context, dgst digest.Digest) error {
if _, err := rs.client.Delete(ctx, &contentapi.DeleteContentRequest{
func (pcs *proxyContentStore) Delete(ctx context.Context, dgst digest.Digest) error {
if _, err := pcs.client.Delete(ctx, &contentapi.DeleteContentRequest{
Digest: dgst,
}); err != nil {
return errdefs.FromGRPC(err)
@ -87,8 +88,8 @@ func (rs *remoteContent) Delete(ctx context.Context, dgst digest.Digest) error {
return nil
}
func (rs *remoteContent) ReaderAt(ctx context.Context, dgst digest.Digest) (content.ReaderAt, error) {
i, err := rs.Info(ctx, dgst)
func (pcs *proxyContentStore) ReaderAt(ctx context.Context, dgst digest.Digest) (content.ReaderAt, error) {
i, err := pcs.Info(ctx, dgst)
if err != nil {
return nil, err
}
@ -97,12 +98,12 @@ func (rs *remoteContent) ReaderAt(ctx context.Context, dgst digest.Digest) (cont
ctx: ctx,
digest: dgst,
size: i.Size,
client: rs.client,
client: pcs.client,
}, nil
}
func (rs *remoteContent) Status(ctx context.Context, ref string) (content.Status, error) {
resp, err := rs.client.Status(ctx, &contentapi.StatusRequest{
func (pcs *proxyContentStore) Status(ctx context.Context, ref string) (content.Status, error) {
resp, err := pcs.client.Status(ctx, &contentapi.StatusRequest{
Ref: ref,
})
if err != nil {
@ -120,8 +121,8 @@ func (rs *remoteContent) Status(ctx context.Context, ref string) (content.Status
}, nil
}
func (rs *remoteContent) Update(ctx context.Context, info content.Info, fieldpaths ...string) (content.Info, error) {
resp, err := rs.client.Update(ctx, &contentapi.UpdateRequest{
func (pcs *proxyContentStore) Update(ctx context.Context, info content.Info, fieldpaths ...string) (content.Info, error) {
resp, err := pcs.client.Update(ctx, &contentapi.UpdateRequest{
Info: infoToGRPC(info),
UpdateMask: &protobuftypes.FieldMask{
Paths: fieldpaths,
@ -133,8 +134,8 @@ func (rs *remoteContent) Update(ctx context.Context, info content.Info, fieldpat
return infoFromGRPC(resp.Info), nil
}
func (rs *remoteContent) ListStatuses(ctx context.Context, filters ...string) ([]content.Status, error) {
resp, err := rs.client.ListStatuses(ctx, &contentapi.ListStatusesRequest{
func (pcs *proxyContentStore) ListStatuses(ctx context.Context, filters ...string) ([]content.Status, error) {
resp, err := pcs.client.ListStatuses(ctx, &contentapi.ListStatusesRequest{
Filters: filters,
})
if err != nil {
@ -156,8 +157,8 @@ func (rs *remoteContent) ListStatuses(ctx context.Context, filters ...string) ([
return statuses, nil
}
func (rs *remoteContent) Writer(ctx context.Context, ref string, size int64, expected digest.Digest) (content.Writer, error) {
wrclient, offset, err := rs.negotiate(ctx, ref, size, expected)
func (pcs *proxyContentStore) Writer(ctx context.Context, ref string, size int64, expected digest.Digest) (content.Writer, error) {
wrclient, offset, err := pcs.negotiate(ctx, ref, size, expected)
if err != nil {
return nil, errdefs.FromGRPC(err)
}
@ -170,8 +171,8 @@ func (rs *remoteContent) Writer(ctx context.Context, ref string, size int64, exp
}
// Abort implements asynchronous abort. It starts a new write session on the ref l
func (rs *remoteContent) Abort(ctx context.Context, ref string) error {
if _, err := rs.client.Abort(ctx, &contentapi.AbortRequest{
func (pcs *proxyContentStore) Abort(ctx context.Context, ref string) error {
if _, err := pcs.client.Abort(ctx, &contentapi.AbortRequest{
Ref: ref,
}); err != nil {
return errdefs.FromGRPC(err)
@ -180,8 +181,8 @@ func (rs *remoteContent) Abort(ctx context.Context, ref string) error {
return nil
}
func (rs *remoteContent) negotiate(ctx context.Context, ref string, size int64, expected digest.Digest) (contentapi.Content_WriteClient, int64, error) {
wrclient, err := rs.client.Write(ctx)
func (pcs *proxyContentStore) negotiate(ctx context.Context, ref string, size int64, expected digest.Digest) (contentapi.Content_WriteClient, int64, error) {
wrclient, err := pcs.client.Write(ctx)
if err != nil {
return nil, 0, err
}

View file

@ -14,7 +14,7 @@
limitations under the License.
*/
package containerd
package proxy
import (
"context"

View file

@ -14,4 +14,13 @@
limitations under the License.
*/
package rpc
package defaults
const (
// DefaultMaxRecvMsgSize defines the default maximum message size for
// receiving protobufs passed over the GRPC API.
DefaultMaxRecvMsgSize = 16 << 20
// DefaultMaxSendMsgSize defines the default maximum message size for
// sending protobufs passed over the GRPC API.
DefaultMaxSendMsgSize = 16 << 20
)

View file

@ -14,6 +14,6 @@
limitations under the License.
*/
// Package defaults provides several common defaults for interacting wtih
// Package defaults provides several common defaults for interacting with
// containerd. These can be used on the client-side or server-side.
package defaults

View file

@ -22,6 +22,7 @@ import (
diffapi "github.com/containerd/containerd/api/services/diff/v1"
"github.com/containerd/containerd/api/types"
"github.com/containerd/containerd/diff"
"github.com/containerd/containerd/errdefs"
"github.com/containerd/containerd/mount"
ocispec "github.com/opencontainers/image-spec/specs-go/v1"
)
@ -51,7 +52,7 @@ func (r *diffRemote) Apply(ctx context.Context, diff ocispec.Descriptor, mounts
}
resp, err := r.client.Apply(ctx, req)
if err != nil {
return ocispec.Descriptor{}, err
return ocispec.Descriptor{}, errdefs.FromGRPC(err)
}
return toDescriptor(resp.Applied), nil
}
@ -72,7 +73,7 @@ func (r *diffRemote) Compare(ctx context.Context, a, b []mount.Mount, opts ...di
}
resp, err := r.client.Diff(ctx, req)
if err != nil {
return ocispec.Descriptor{}, err
return ocispec.Descriptor{}, errdefs.FromGRPC(err)
}
return toDescriptor(resp.Diff), nil
}

119
vendor/github.com/containerd/containerd/events.go generated vendored Normal file
View file

@ -0,0 +1,119 @@
/*
Copyright The containerd Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package containerd
import (
"context"
eventsapi "github.com/containerd/containerd/api/services/events/v1"
"github.com/containerd/containerd/errdefs"
"github.com/containerd/containerd/events"
"github.com/containerd/typeurl"
)
// EventService handles the publish, forward and subscribe of events.
type EventService interface {
events.Publisher
events.Forwarder
events.Subscriber
}
// NewEventServiceFromClient returns a new event service which communicates
// over a GRPC connection.
func NewEventServiceFromClient(client eventsapi.EventsClient) EventService {
return &eventRemote{
client: client,
}
}
type eventRemote struct {
client eventsapi.EventsClient
}
func (e *eventRemote) Publish(ctx context.Context, topic string, event events.Event) error {
any, err := typeurl.MarshalAny(event)
if err != nil {
return err
}
req := &eventsapi.PublishRequest{
Topic: topic,
Event: any,
}
if _, err := e.client.Publish(ctx, req); err != nil {
return errdefs.FromGRPC(err)
}
return nil
}
func (e *eventRemote) Forward(ctx context.Context, envelope *events.Envelope) error {
req := &eventsapi.ForwardRequest{
Envelope: &eventsapi.Envelope{
Timestamp: envelope.Timestamp,
Namespace: envelope.Namespace,
Topic: envelope.Topic,
Event: envelope.Event,
},
}
if _, err := e.client.Forward(ctx, req); err != nil {
return errdefs.FromGRPC(err)
}
return nil
}
func (e *eventRemote) Subscribe(ctx context.Context, filters ...string) (ch <-chan *events.Envelope, errs <-chan error) {
var (
evq = make(chan *events.Envelope)
errq = make(chan error, 1)
)
errs = errq
ch = evq
session, err := e.client.Subscribe(ctx, &eventsapi.SubscribeRequest{
Filters: filters,
})
if err != nil {
errq <- err
close(errq)
return
}
go func() {
defer close(errq)
for {
ev, err := session.Recv()
if err != nil {
errq <- err
return
}
select {
case evq <- &events.Envelope{
Timestamp: ev.Timestamp,
Namespace: ev.Namespace,
Topic: ev.Topic,
Event: ev.Event,
}:
case <-ctx.Done():
return
}
}
}()
return ch, errs
}

View file

@ -92,7 +92,7 @@ var Always FilterFunc = func(adaptor Adaptor) bool {
return true
}
// Any allows multiple filters to be matched aginst the object
// Any allows multiple filters to be matched against the object
type Any []Filter
// Match returns true if any of the provided filters are true
@ -106,7 +106,7 @@ func (m Any) Match(adaptor Adaptor) bool {
return false
}
// All allows multiple filters to be matched aginst the object
// All allows multiple filters to be matched against the object
type All []Filter
// Match only returns true if all filters match the object

View file

@ -17,8 +17,9 @@
package containerd
import (
"context"
"github.com/containerd/containerd/namespaces"
"golang.org/x/net/context"
"google.golang.org/grpc"
)

View file

@ -25,7 +25,6 @@ import (
"github.com/containerd/containerd/images"
"github.com/containerd/containerd/platforms"
"github.com/containerd/containerd/rootfs"
"github.com/containerd/containerd/snapshots"
digest "github.com/opencontainers/go-digest"
"github.com/opencontainers/image-spec/identity"
ocispec "github.com/opencontainers/image-spec/specs-go/v1"
@ -54,6 +53,14 @@ type Image interface {
var _ = (Image)(&image{})
// NewImage returns a client image object from the metadata image
func NewImage(client *Client, i images.Image) Image {
return &image{
client: client,
i: i,
}
}
type image struct {
client *Client
@ -108,7 +115,7 @@ func (i *image) Unpack(ctx context.Context, snapshotterName string) error {
if err != nil {
return err
}
defer done()
defer done(ctx)
layers, err := i.getLayers(ctx, platforms.Default())
if err != nil {
@ -124,15 +131,25 @@ func (i *image) Unpack(ctx context.Context, snapshotterName string) error {
unpacked bool
)
for _, layer := range layers {
labels := map[string]string{
"containerd.io/uncompressed": layer.Diff.Digest.String(),
}
unpacked, err = rootfs.ApplyLayer(ctx, layer, chain, sn, a, snapshots.WithLabels(labels))
unpacked, err = rootfs.ApplyLayer(ctx, layer, chain, sn, a)
if err != nil {
return err
}
if unpacked {
// Set the uncompressed label after the uncompressed
// digest has been verified through apply.
cinfo := content.Info{
Digest: layer.Blob.Digest,
Labels: map[string]string{
"containerd.io/uncompressed": layer.Diff.Digest.String(),
},
}
if _, err := cs.Update(ctx, cinfo, "labels.containerd.io/uncompressed"); err != nil {
return err
}
}
chain = append(chain, layer.Diff.Digest)
}

View file

@ -182,9 +182,9 @@ func SetChildrenLabels(manager content.Manager, f HandlerFunc) HandlerFunc {
}
}
// FilterPlatform is a handler wrapper which limits the descriptors returned
// by a handler to a single platform.
func FilterPlatform(platform string, f HandlerFunc) HandlerFunc {
// FilterPlatforms is a handler wrapper which limits the descriptors returned
// by a handler to the specified platforms.
func FilterPlatforms(f HandlerFunc, platformList ...string) HandlerFunc {
return func(ctx context.Context, desc ocispec.Descriptor) ([]ocispec.Descriptor, error) {
children, err := f(ctx, desc)
if err != nil {
@ -192,31 +192,25 @@ func FilterPlatform(platform string, f HandlerFunc) HandlerFunc {
}
var descs []ocispec.Descriptor
if platform != "" && isMultiPlatform(desc.MediaType) {
matcher, err := platforms.Parse(platform)
if err != nil {
return nil, err
}
for _, d := range children {
if d.Platform == nil || matcher.Match(*d.Platform) {
descs = append(descs, d)
if len(platformList) == 0 {
descs = children
} else {
for _, platform := range platformList {
p, err := platforms.Parse(platform)
if err != nil {
return nil, err
}
matcher := platforms.NewMatcher(p)
for _, d := range children {
if d.Platform == nil || matcher.Match(*d.Platform) {
descs = append(descs, d)
}
}
}
} else {
descs = children
}
return descs, nil
}
}
func isMultiPlatform(mediaType string) bool {
switch mediaType {
case MediaTypeDockerSchema2ManifestList, ocispec.MediaTypeImageIndex:
return true
default:
return false
}
}

View file

@ -118,7 +118,7 @@ func (image *Image) Size(ctx context.Context, provider content.Provider, platfor
}
size += desc.Size
return nil, nil
}), FilterPlatform(platform, ChildrenHandler(provider))), image.Target)
}), FilterPlatforms(ChildrenHandler(provider), platform)), image.Target)
}
// Manifest resolves a manifest from the image for the given platform.
@ -131,13 +131,13 @@ func Manifest(ctx context.Context, provider content.Provider, image ocispec.Desc
var (
matcher platforms.Matcher
m *ocispec.Manifest
err error
)
if platform != "" {
matcher, err = platforms.Parse(platform)
p, err := platforms.Parse(platform)
if err != nil {
return ocispec.Manifest{}, err
}
matcher = platforms.NewMatcher(p)
}
if err := Walk(ctx, HandlerFunc(func(ctx context.Context, desc ocispec.Descriptor) ([]ocispec.Descriptor, error) {
@ -279,7 +279,7 @@ func Check(ctx context.Context, provider content.Provider, image ocispec.Descrip
// TODO(stevvooe): It is possible that referenced conponents could have
// children, but this is rare. For now, we ignore this and only verify
// that manfiest components are present.
// that manifest components are present.
required = append([]ocispec.Descriptor{mfst.Config}, mfst.Layers...)
for _, desc := range required {

121
vendor/github.com/containerd/containerd/import.go generated vendored Normal file
View file

@ -0,0 +1,121 @@
/*
Copyright The containerd Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package containerd
import (
"context"
"io"
"github.com/containerd/containerd/errdefs"
"github.com/containerd/containerd/images"
ocispec "github.com/opencontainers/image-spec/specs-go/v1"
)
type importOpts struct {
}
// ImportOpt allows the caller to specify import specific options
type ImportOpt func(c *importOpts) error
func resolveImportOpt(opts ...ImportOpt) (importOpts, error) {
var iopts importOpts
for _, o := range opts {
if err := o(&iopts); err != nil {
return iopts, err
}
}
return iopts, nil
}
// Import imports an image from a Tar stream using reader.
// Caller needs to specify importer. Future version may use oci.v1 as the default.
// Note that unreferrenced blobs may be imported to the content store as well.
func (c *Client) Import(ctx context.Context, importer images.Importer, reader io.Reader, opts ...ImportOpt) ([]Image, error) {
_, err := resolveImportOpt(opts...) // unused now
if err != nil {
return nil, err
}
ctx, done, err := c.WithLease(ctx)
if err != nil {
return nil, err
}
defer done(ctx)
imgrecs, err := importer.Import(ctx, c.ContentStore(), reader)
if err != nil {
// is.Update() is not called on error
return nil, err
}
is := c.ImageService()
var images []Image
for _, imgrec := range imgrecs {
if updated, err := is.Update(ctx, imgrec, "target"); err != nil {
if !errdefs.IsNotFound(err) {
return nil, err
}
created, err := is.Create(ctx, imgrec)
if err != nil {
return nil, err
}
imgrec = created
} else {
imgrec = updated
}
images = append(images, &image{
client: c,
i: imgrec,
})
}
return images, nil
}
type exportOpts struct {
}
// ExportOpt allows the caller to specify export-specific options
type ExportOpt func(c *exportOpts) error
func resolveExportOpt(opts ...ExportOpt) (exportOpts, error) {
var eopts exportOpts
for _, o := range opts {
if err := o(&eopts); err != nil {
return eopts, err
}
}
return eopts, nil
}
// Export exports an image to a Tar stream.
// OCI format is used by default.
// It is up to caller to put "org.opencontainers.image.ref.name" annotation to desc.
// TODO(AkihiroSuda): support exporting multiple descriptors at once to a single archive stream.
func (c *Client) Export(ctx context.Context, exporter images.Exporter, desc ocispec.Descriptor, opts ...ExportOpt) (io.ReadCloser, error) {
_, err := resolveExportOpt(opts...) // unused now
if err != nil {
return nil, err
}
pr, pw := io.Pipe()
go func() {
pw.CloseWithError(exporter.Export(ctx, c.ContentStore(), desc, pw))
}()
return pr, nil
}

View file

@ -36,7 +36,7 @@ type Lease struct {
// CreateLease creates a new lease
func (c *Client) CreateLease(ctx context.Context) (Lease, error) {
lapi := leasesapi.NewLeasesClient(c.conn)
lapi := c.LeasesService()
resp, err := lapi.Create(ctx, &leasesapi.CreateRequest{})
if err != nil {
return Lease{}, err
@ -50,7 +50,7 @@ func (c *Client) CreateLease(ctx context.Context) (Lease, error) {
// ListLeases lists active leases
func (c *Client) ListLeases(ctx context.Context) ([]Lease, error) {
lapi := leasesapi.NewLeasesClient(c.conn)
lapi := c.LeasesService()
resp, err := lapi.List(ctx, &leasesapi.ListRequest{})
if err != nil {
return nil, err
@ -68,10 +68,10 @@ func (c *Client) ListLeases(ctx context.Context) ([]Lease, error) {
}
// WithLease attaches a lease on the context
func (c *Client) WithLease(ctx context.Context) (context.Context, func() error, error) {
func (c *Client) WithLease(ctx context.Context) (context.Context, func(context.Context) error, error) {
_, ok := leases.Lease(ctx)
if ok {
return ctx, func() error {
return ctx, func(context.Context) error {
return nil
}, nil
}
@ -82,7 +82,7 @@ func (c *Client) WithLease(ctx context.Context) (context.Context, func() error,
}
ctx = leases.WithLease(ctx, l.ID())
return ctx, func() error {
return ctx, func(ctx context.Context) error {
return l.Delete(ctx)
}, nil
}
@ -100,7 +100,7 @@ func (l Lease) CreatedAt() time.Time {
// Delete deletes the lease, removing the reference to all resources created
// during the lease.
func (l Lease) Delete(ctx context.Context) error {
lapi := leasesapi.NewLeasesClient(l.client.conn)
lapi := l.client.LeasesService()
_, err := lapi.Delete(ctx, &leasesapi.DeleteRequest{
ID: l.id,
})

View file

@ -17,7 +17,8 @@
package leases
import (
"golang.org/x/net/context"
"context"
"google.golang.org/grpc/metadata"
)

View file

@ -85,24 +85,25 @@ type bundle struct {
type ShimOpt func(*bundle, string, *runctypes.RuncOptions) (shim.Config, client.Opt)
// ShimRemote is a ShimOpt for connecting and starting a remote shim
func ShimRemote(shimBinary, daemonAddress, cgroup string, debug bool, exitHandler func()) ShimOpt {
func ShimRemote(c *Config, daemonAddress, cgroup string, exitHandler func()) ShimOpt {
return func(b *bundle, ns string, ropts *runctypes.RuncOptions) (shim.Config, client.Opt) {
return b.shimConfig(ns, ropts),
client.WithStart(shimBinary, b.shimAddress(ns), daemonAddress, cgroup, debug, exitHandler)
config := b.shimConfig(ns, c, ropts)
return config,
client.WithStart(c.Shim, b.shimAddress(ns), daemonAddress, cgroup, c.ShimDebug, exitHandler)
}
}
// ShimLocal is a ShimOpt for using an in process shim implementation
func ShimLocal(exchange *exchange.Exchange) ShimOpt {
func ShimLocal(c *Config, exchange *exchange.Exchange) ShimOpt {
return func(b *bundle, ns string, ropts *runctypes.RuncOptions) (shim.Config, client.Opt) {
return b.shimConfig(ns, ropts), client.WithLocal(exchange)
return b.shimConfig(ns, c, ropts), client.WithLocal(exchange)
}
}
// ShimConnect is a ShimOpt for connecting to an existing remote shim
func ShimConnect(onClose func()) ShimOpt {
func ShimConnect(c *Config, onClose func()) ShimOpt {
return func(b *bundle, ns string, ropts *runctypes.RuncOptions) (shim.Config, client.Opt) {
return b.shimConfig(ns, ropts), client.WithConnect(b.shimAddress(ns), onClose)
return b.shimConfig(ns, c, ropts), client.WithConnect(b.shimAddress(ns), onClose)
}
}
@ -130,16 +131,18 @@ func (b *bundle) shimAddress(namespace string) string {
return filepath.Join(string(filepath.Separator), "containerd-shim", namespace, b.id, "shim.sock")
}
func (b *bundle) shimConfig(namespace string, runcOptions *runctypes.RuncOptions) shim.Config {
func (b *bundle) shimConfig(namespace string, c *Config, runcOptions *runctypes.RuncOptions) shim.Config {
var (
criuPath string
runtimeRoot string
runtimeRoot = c.RuntimeRoot
systemdCgroup bool
)
if runcOptions != nil {
criuPath = runcOptions.CriuPath
systemdCgroup = runcOptions.SystemdCgroup
runtimeRoot = runcOptions.RuntimeRoot
if runcOptions.RuntimeRoot != "" {
runtimeRoot = runcOptions.RuntimeRoot
}
}
return shim.Config{
Path: b.path,

View file

@ -163,7 +163,10 @@ func (e *execProcess) start(ctx context.Context) (err error) {
return e.parent.runtimeError(err, "OCI runtime exec failed")
}
if e.stdio.Stdin != "" {
sc, err := fifo.OpenFifo(ctx, e.stdio.Stdin, syscall.O_WRONLY|syscall.O_NONBLOCK, 0)
fifoCtx, cancel := context.WithTimeout(ctx, 15*time.Second)
defer cancel()
sc, err := fifo.OpenFifo(fifoCtx, e.stdio.Stdin, syscall.O_WRONLY|syscall.O_NONBLOCK, 0)
if err != nil {
return errors.Wrapf(err, "failed to open stdin fifo %s", e.stdio.Stdin)
}
@ -180,7 +183,10 @@ func (e *execProcess) start(ctx context.Context) (err error) {
return errors.Wrap(err, "failed to start console copy")
}
} else if !e.stdio.IsNull() {
if err := copyPipes(ctx, e.io, e.stdio.Stdin, e.stdio.Stdout, e.stdio.Stderr, &e.wg, &copyWaitGroup); err != nil {
fifoCtx, cancel := context.WithTimeout(ctx, 15*time.Second)
defer cancel()
if err := copyPipes(fifoCtx, e.io, e.stdio.Stdin, e.stdio.Stdout, e.stdio.Stderr, &e.wg, &copyWaitGroup); err != nil {
return errors.Wrap(err, "failed to start io pipe copy")
}
}

View file

@ -194,10 +194,23 @@ func (s *createdCheckpointState) Start(ctx context.Context) error {
s.p.mu.Lock()
defer s.p.mu.Unlock()
p := s.p
sio := p.stdio
var (
err error
socket *runc.Socket
)
if sio.Terminal {
if socket, err = runc.NewTempConsoleSocket(); err != nil {
return errors.Wrap(err, "failed to create OCI runtime console socket")
}
defer socket.Close()
s.opts.ConsoleSocket = socket
}
if _, err := s.p.runtime.Restore(ctx, p.id, p.bundle, s.opts); err != nil {
return p.runtimeError(err, "OCI runtime restore failed")
}
sio := p.stdio
if sio.Stdin != "" {
sc, err := fifo.OpenFifo(ctx, sio.Stdin, syscall.O_WRONLY|syscall.O_NONBLOCK, 0)
if err != nil {
@ -207,7 +220,17 @@ func (s *createdCheckpointState) Start(ctx context.Context) error {
p.closers = append(p.closers, sc)
}
var copyWaitGroup sync.WaitGroup
if !sio.IsNull() {
if socket != nil {
console, err := socket.ReceiveMaster()
if err != nil {
return errors.Wrap(err, "failed to retrieve console master")
}
console, err = p.platform.CopyConsole(ctx, console, sio.Stdin, sio.Stdout, sio.Stderr, &p.wg, &copyWaitGroup)
if err != nil {
return errors.Wrap(err, "failed to start console copy")
}
p.console = console
} else if !sio.IsNull() {
if err := copyPipes(ctx, p.io, sio.Stdin, sio.Stdout, sio.Stderr, &p.wg, &copyWaitGroup); err != nil {
return errors.Wrap(err, "failed to start io pipe copy")
}
@ -219,7 +242,6 @@ func (s *createdCheckpointState) Start(ctx context.Context) error {
return errors.Wrap(err, "failed to retrieve OCI runtime container pid")
}
p.pid = pid
return s.transition("running")
}

View file

@ -22,6 +22,7 @@ import (
"context"
"fmt"
"io"
"os"
"sync"
"syscall"
@ -37,44 +38,75 @@ var bufPool = sync.Pool{
}
func copyPipes(ctx context.Context, rio runc.IO, stdin, stdout, stderr string, wg, cwg *sync.WaitGroup) error {
for name, dest := range map[string]func(wc io.WriteCloser, rc io.Closer){
stdout: func(wc io.WriteCloser, rc io.Closer) {
wg.Add(1)
cwg.Add(1)
go func() {
cwg.Done()
p := bufPool.Get().(*[]byte)
defer bufPool.Put(p)
io.CopyBuffer(wc, rio.Stdout(), *p)
wg.Done()
wc.Close()
rc.Close()
}()
},
stderr: func(wc io.WriteCloser, rc io.Closer) {
wg.Add(1)
cwg.Add(1)
go func() {
cwg.Done()
p := bufPool.Get().(*[]byte)
defer bufPool.Put(p)
io.CopyBuffer(wc, rio.Stderr(), *p)
wg.Done()
wc.Close()
rc.Close()
}()
var sameFile io.WriteCloser
for _, i := range []struct {
name string
dest func(wc io.WriteCloser, rc io.Closer)
}{
{
name: stdout,
dest: func(wc io.WriteCloser, rc io.Closer) {
wg.Add(1)
cwg.Add(1)
go func() {
cwg.Done()
p := bufPool.Get().(*[]byte)
defer bufPool.Put(p)
io.CopyBuffer(wc, rio.Stdout(), *p)
wg.Done()
wc.Close()
if rc != nil {
rc.Close()
}
}()
},
}, {
name: stderr,
dest: func(wc io.WriteCloser, rc io.Closer) {
wg.Add(1)
cwg.Add(1)
go func() {
cwg.Done()
p := bufPool.Get().(*[]byte)
defer bufPool.Put(p)
io.CopyBuffer(wc, rio.Stderr(), *p)
wg.Done()
wc.Close()
if rc != nil {
rc.Close()
}
}()
},
},
} {
fw, err := fifo.OpenFifo(ctx, name, syscall.O_WRONLY, 0)
ok, err := isFifo(i.name)
if err != nil {
return fmt.Errorf("containerd-shim: opening %s failed: %s", name, err)
return err
}
fr, err := fifo.OpenFifo(ctx, name, syscall.O_RDONLY, 0)
if err != nil {
return fmt.Errorf("containerd-shim: opening %s failed: %s", name, err)
var (
fw io.WriteCloser
fr io.Closer
)
if ok {
if fw, err = fifo.OpenFifo(ctx, i.name, syscall.O_WRONLY, 0); err != nil {
return fmt.Errorf("containerd-shim: opening %s failed: %s", i.name, err)
}
if fr, err = fifo.OpenFifo(ctx, i.name, syscall.O_RDONLY, 0); err != nil {
return fmt.Errorf("containerd-shim: opening %s failed: %s", i.name, err)
}
} else {
if sameFile != nil {
i.dest(sameFile, nil)
continue
}
if fw, err = os.OpenFile(i.name, syscall.O_WRONLY|syscall.O_APPEND, 0); err != nil {
return fmt.Errorf("containerd-shim: opening %s failed: %s", i.name, err)
}
if stdout == stderr {
sameFile = fw
}
}
dest(fw, fr)
i.dest(fw, fr)
}
if stdin == "" {
rio.Stdin().Close()
@ -96,3 +128,19 @@ func copyPipes(ctx context.Context, rio runc.IO, stdin, stdout, stderr string, w
}()
return nil
}
// isFifo checks if a file is a fifo
// if the file does not exist then it returns false
func isFifo(path string) (bool, error) {
stat, err := os.Stat(path)
if err != nil {
if os.IsNotExist(err) {
return false, nil
}
return false, err
}
if stat.Mode()&os.ModeNamedPipe == os.ModeNamedPipe {
return true, nil
}
return false, nil
}

View file

@ -79,7 +79,7 @@ func init() {
})
}
var _ = (runtime.Runtime)(&Runtime{})
var _ = (runtime.PlatformRuntime)(&Runtime{})
// Config options for the runtime
type Config struct {
@ -186,7 +186,7 @@ func (r *Runtime) Create(ctx context.Context, id string, opts runtime.CreateOpts
}
}()
shimopt := ShimLocal(r.events)
shimopt := ShimLocal(r.config, r.events)
if !r.config.NoShim {
var cgroup string
if opts.Options != nil {
@ -200,7 +200,7 @@ func (r *Runtime) Create(ctx context.Context, id string, opts runtime.CreateOpts
log.G(ctx).WithField("id", id).Info("shim reaped")
t, err := r.tasks.Get(ctx, id)
if err != nil {
// Task was never started or was already sucessfully deleted
// Task was never started or was already successfully deleted
return
}
lc := t.(*Task)
@ -224,7 +224,7 @@ func (r *Runtime) Create(ctx context.Context, id string, opts runtime.CreateOpts
}).Warn("failed to clen up after killed shim")
}
}
shimopt = ShimRemote(r.config.Shim, r.address, cgroup, r.config.ShimDebug, exitHandler)
shimopt = ShimRemote(r.config, r.address, cgroup, exitHandler)
}
s, err := bundle.NewShimClient(ctx, namespace, shimopt, ropts)
@ -396,7 +396,7 @@ func (r *Runtime) loadTasks(ctx context.Context, ns string) ([]*Task, error) {
)
ctx = namespaces.WithNamespace(ctx, ns)
pid, _ := runc.ReadPidFile(filepath.Join(bundle.path, proc.InitPidFile))
s, err := bundle.NewShimClient(ctx, ns, ShimConnect(func() {
s, err := bundle.NewShimClient(ctx, ns, ShimConnect(r.config, func() {
err := r.cleanupAfterDeadShim(ctx, bundle, ns, id, pid)
if err != nil {
log.G(ctx).WithError(err).WithField("bundle", bundle.path).
@ -510,6 +510,7 @@ func (r *Runtime) getRuntime(ctx context.Context, ns, id string) (*runc.Runc, er
LogFormat: runc.JSON,
PdeathSignal: unix.SIGKILL,
Root: filepath.Join(root, ns),
Debug: r.config.ShimDebug,
}, nil
}

View file

@ -145,7 +145,7 @@ func newCommand(binary, daemonAddress string, debug bool, config shim.Config, so
func newSocket(address string) (*net.UnixListener, error) {
if len(address) > 106 {
return nil, errors.Errorf("%q: unix socket path too long (limit 106)", address)
return nil, errors.Errorf("%q: unix socket path too long (> 106)", address)
}
l, err := net.Listen("unix", "\x00"+address)
if err != nil {

View file

@ -16,7 +16,7 @@
limitations under the License.
*/
package reaper
package shim
import (
"os/exec"

View file

@ -34,7 +34,6 @@ import (
shimapi "github.com/containerd/containerd/linux/shim/v1"
"github.com/containerd/containerd/log"
"github.com/containerd/containerd/namespaces"
"github.com/containerd/containerd/reaper"
"github.com/containerd/containerd/runtime"
runc "github.com/containerd/go-runc"
"github.com/containerd/typeurl"
@ -81,7 +80,7 @@ func NewService(config Config, publisher events.Publisher) (*Service, error) {
context: ctx,
processes: make(map[string]proc.Process),
events: make(chan interface{}, 128),
ec: reaper.Default.Subscribe(),
ec: Default.Subscribe(),
}
go s.processExits()
if err := s.initPlatform(); err != nil {

View file

@ -44,13 +44,13 @@ import containerd_v1_types "github.com/containerd/containerd/api/types/task"
import time "time"
import github_com_gogo_protobuf_types "github.com/gogo/protobuf/types"
import types "github.com/gogo/protobuf/types"
import strings "strings"
import reflect "reflect"
import context "context"
import github_com_stevvooe_ttrpc "github.com/stevvooe/ttrpc"
import ttrpc "github.com/stevvooe/ttrpc"
import io "io"
@ -429,8 +429,8 @@ func (m *DeleteResponse) MarshalTo(dAtA []byte) (int, error) {
}
dAtA[i] = 0x1a
i++
i = encodeVarintShim(dAtA, i, uint64(github_com_gogo_protobuf_types.SizeOfStdTime(m.ExitedAt)))
n2, err := github_com_gogo_protobuf_types.StdTimeMarshalTo(m.ExitedAt, dAtA[i:])
i = encodeVarintShim(dAtA, i, uint64(types.SizeOfStdTime(m.ExitedAt)))
n2, err := types.StdTimeMarshalTo(m.ExitedAt, dAtA[i:])
if err != nil {
return 0, err
}
@ -672,8 +672,8 @@ func (m *StateResponse) MarshalTo(dAtA []byte) (int, error) {
}
dAtA[i] = 0x52
i++
i = encodeVarintShim(dAtA, i, uint64(github_com_gogo_protobuf_types.SizeOfStdTime(m.ExitedAt)))
n4, err := github_com_gogo_protobuf_types.StdTimeMarshalTo(m.ExitedAt, dAtA[i:])
i = encodeVarintShim(dAtA, i, uint64(types.SizeOfStdTime(m.ExitedAt)))
n4, err := types.StdTimeMarshalTo(m.ExitedAt, dAtA[i:])
if err != nil {
return 0, err
}
@ -992,8 +992,8 @@ func (m *WaitResponse) MarshalTo(dAtA []byte) (int, error) {
}
dAtA[i] = 0x12
i++
i = encodeVarintShim(dAtA, i, uint64(github_com_gogo_protobuf_types.SizeOfStdTime(m.ExitedAt)))
n7, err := github_com_gogo_protobuf_types.StdTimeMarshalTo(m.ExitedAt, dAtA[i:])
i = encodeVarintShim(dAtA, i, uint64(types.SizeOfStdTime(m.ExitedAt)))
n7, err := types.StdTimeMarshalTo(m.ExitedAt, dAtA[i:])
if err != nil {
return 0, err
}
@ -1079,7 +1079,7 @@ func (m *DeleteResponse) Size() (n int) {
if m.ExitStatus != 0 {
n += 1 + sovShim(uint64(m.ExitStatus))
}
l = github_com_gogo_protobuf_types.SizeOfStdTime(m.ExitedAt)
l = types.SizeOfStdTime(m.ExitedAt)
n += 1 + l + sovShim(uint64(l))
return n
}
@ -1190,7 +1190,7 @@ func (m *StateResponse) Size() (n int) {
if m.ExitStatus != 0 {
n += 1 + sovShim(uint64(m.ExitStatus))
}
l = github_com_gogo_protobuf_types.SizeOfStdTime(m.ExitedAt)
l = types.SizeOfStdTime(m.ExitedAt)
n += 1 + l + sovShim(uint64(l))
return n
}
@ -1318,7 +1318,7 @@ func (m *WaitResponse) Size() (n int) {
if m.ExitStatus != 0 {
n += 1 + sovShim(uint64(m.ExitStatus))
}
l = github_com_gogo_protobuf_types.SizeOfStdTime(m.ExitedAt)
l = types.SizeOfStdTime(m.ExitedAt)
n += 1 + l + sovShim(uint64(l))
return n
}
@ -1597,8 +1597,8 @@ type ShimService interface {
Wait(ctx context.Context, req *WaitRequest) (*WaitResponse, error)
}
func RegisterShimService(srv *github_com_stevvooe_ttrpc.Server, svc ShimService) {
srv.Register("containerd.runtime.linux.shim.v1.Shim", map[string]github_com_stevvooe_ttrpc.Method{
func RegisterShimService(srv *ttrpc.Server, svc ShimService) {
srv.Register("containerd.runtime.linux.shim.v1.Shim", map[string]ttrpc.Method{
"State": func(ctx context.Context, unmarshal func(interface{}) error) (interface{}, error) {
var req StateRequest
if err := unmarshal(&req); err != nil {
@ -1715,10 +1715,10 @@ func RegisterShimService(srv *github_com_stevvooe_ttrpc.Server, svc ShimService)
}
type shimClient struct {
client *github_com_stevvooe_ttrpc.Client
client *ttrpc.Client
}
func NewShimClient(client *github_com_stevvooe_ttrpc.Client) ShimService {
func NewShimClient(client *ttrpc.Client) ShimService {
return &shimClient{
client: client,
}
@ -2379,7 +2379,7 @@ func (m *DeleteResponse) Unmarshal(dAtA []byte) error {
if postIndex > l {
return io.ErrUnexpectedEOF
}
if err := github_com_gogo_protobuf_types.StdTimeUnmarshal(&m.ExitedAt, dAtA[iNdEx:postIndex]); err != nil {
if err := types.StdTimeUnmarshal(&m.ExitedAt, dAtA[iNdEx:postIndex]); err != nil {
return err
}
iNdEx = postIndex
@ -3225,7 +3225,7 @@ func (m *StateResponse) Unmarshal(dAtA []byte) error {
if postIndex > l {
return io.ErrUnexpectedEOF
}
if err := github_com_gogo_protobuf_types.StdTimeUnmarshal(&m.ExitedAt, dAtA[iNdEx:postIndex]); err != nil {
if err := types.StdTimeUnmarshal(&m.ExitedAt, dAtA[iNdEx:postIndex]); err != nil {
return err
}
iNdEx = postIndex
@ -4221,7 +4221,7 @@ func (m *WaitResponse) Unmarshal(dAtA []byte) error {
if postIndex > l {
return io.ErrUnexpectedEOF
}
if err := github_com_gogo_protobuf_types.StdTimeUnmarshal(&m.ExitedAt, dAtA[iNdEx:postIndex]); err != nil {
if err := types.StdTimeUnmarshal(&m.ExitedAt, dAtA[iNdEx:postIndex]); err != nil {
return err
}
iNdEx = postIndex

View file

@ -52,7 +52,7 @@ var (
bucketKeyObjectSnapshots = []byte("snapshots") // stores snapshot references
bucketKeyObjectContent = []byte("content") // stores content references
bucketKeyObjectBlob = []byte("blob") // stores content links
bucketKeyObjectIngest = []byte("ingest") // stores ingest links
bucketKeyObjectIngests = []byte("ingests") // stores ingest objects
bucketKeyObjectLeases = []byte("leases") // stores leases
bucketKeyDigest = []byte("digest")
@ -70,6 +70,10 @@ var (
bucketKeyTarget = []byte("target")
bucketKeyExtensions = []byte("extensions")
bucketKeyCreatedAt = []byte("createdat")
bucketKeyExpected = []byte("expected")
bucketKeyRef = []byte("ref")
deprecatedBucketKeyObjectIngest = []byte("ingest") // stores ingest links, deprecated in v1.2
)
func getBucket(tx *bolt.Tx, keys ...[]byte) *bolt.Bucket {
@ -131,11 +135,7 @@ func getImagesBucket(tx *bolt.Tx, namespace string) *bolt.Bucket {
}
func createContainersBucket(tx *bolt.Tx, namespace string) (*bolt.Bucket, error) {
bkt, err := createBucketIfNotExists(tx, bucketKeyVersion, []byte(namespace), bucketKeyObjectContainers)
if err != nil {
return nil, err
}
return bkt, nil
return createBucketIfNotExists(tx, bucketKeyVersion, []byte(namespace), bucketKeyObjectContainers)
}
func getContainersBucket(tx *bolt.Tx, namespace string) *bolt.Bucket {
@ -178,14 +178,18 @@ func getBlobBucket(tx *bolt.Tx, namespace string, dgst digest.Digest) *bolt.Buck
return getBucket(tx, bucketKeyVersion, []byte(namespace), bucketKeyObjectContent, bucketKeyObjectBlob, []byte(dgst.String()))
}
func createIngestBucket(tx *bolt.Tx, namespace string) (*bolt.Bucket, error) {
bkt, err := createBucketIfNotExists(tx, bucketKeyVersion, []byte(namespace), bucketKeyObjectContent, bucketKeyObjectIngest)
func getIngestsBucket(tx *bolt.Tx, namespace string) *bolt.Bucket {
return getBucket(tx, bucketKeyVersion, []byte(namespace), bucketKeyObjectContent, bucketKeyObjectIngests)
}
func createIngestBucket(tx *bolt.Tx, namespace, ref string) (*bolt.Bucket, error) {
bkt, err := createBucketIfNotExists(tx, bucketKeyVersion, []byte(namespace), bucketKeyObjectContent, bucketKeyObjectIngests, []byte(ref))
if err != nil {
return nil, err
}
return bkt, nil
}
func getIngestBucket(tx *bolt.Tx, namespace string) *bolt.Bucket {
return getBucket(tx, bucketKeyVersion, []byte(namespace), bucketKeyObjectContent, bucketKeyObjectIngest)
func getIngestBucket(tx *bolt.Tx, namespace, ref string) *bolt.Bucket {
return getBucket(tx, bucketKeyVersion, []byte(namespace), bucketKeyObjectContent, bucketKeyObjectIngests, []byte(ref))
}

View file

@ -164,19 +164,11 @@ func (s *containerStore) Update(ctx context.Context, container containers.Contai
if len(fieldpaths) == 0 {
// only allow updates to these field on full replace.
fieldpaths = []string{"labels", "spec", "extensions"}
fieldpaths = []string{"labels", "spec", "extensions", "image", "snapshotkey"}
// Fields that are immutable must cause an error when no field paths
// are provided. This allows these fields to become mutable in the
// future.
if updated.Image != container.Image {
return containers.Container{}, errors.Wrapf(errdefs.ErrInvalidArgument, "container.Image field is immutable")
}
if updated.SnapshotKey != container.SnapshotKey {
return containers.Container{}, errors.Wrapf(errdefs.ErrInvalidArgument, "container.SnapshotKey field is immutable")
}
if updated.Snapshotter != container.Snapshotter {
return containers.Container{}, errors.Wrapf(errdefs.ErrInvalidArgument, "container.Snapshotter field is immutable")
}
@ -215,6 +207,10 @@ func (s *containerStore) Update(ctx context.Context, container containers.Contai
updated.Spec = container.Spec
case "extensions":
updated.Extensions = container.Extensions
case "image":
updated.Image = container.Image
case "snapshotkey":
updated.SnapshotKey = container.SnapshotKey
default:
return containers.Container{}, errors.Wrapf(errdefs.ErrInvalidArgument, "cannot update %q field on %q", path, container.ID)
}

View file

@ -226,14 +226,16 @@ func (cs *contentStore) ListStatuses(ctx context.Context, fs ...string) ([]conte
brefs := map[string]string{}
if err := view(ctx, cs.db, func(tx *bolt.Tx) error {
bkt := getIngestBucket(tx, ns)
bkt := getIngestsBucket(tx, ns)
if bkt == nil {
return nil
}
return bkt.ForEach(func(k, v []byte) error {
// TODO(dmcgowan): match name and potentially labels here
brefs[string(k)] = string(v)
if v == nil {
// TODO(dmcgowan): match name and potentially labels here
brefs[string(k)] = string(bkt.Bucket(k).Get(bucketKeyRef))
}
return nil
})
}); err != nil {
@ -261,11 +263,11 @@ func (cs *contentStore) ListStatuses(ctx context.Context, fs ...string) ([]conte
}
func getRef(tx *bolt.Tx, ns, ref string) string {
bkt := getIngestBucket(tx, ns)
bkt := getIngestBucket(tx, ns, ref)
if bkt == nil {
return ""
}
v := bkt.Get([]byte(ref))
v := bkt.Get(bucketKeyRef)
if len(v) == 0 {
return ""
}
@ -308,19 +310,29 @@ func (cs *contentStore) Abort(ctx context.Context, ref string) error {
defer cs.l.RUnlock()
return update(ctx, cs.db, func(tx *bolt.Tx) error {
bkt := getIngestBucket(tx, ns)
ibkt := getIngestsBucket(tx, ns)
if ibkt == nil {
return errors.Wrapf(errdefs.ErrNotFound, "reference %v", ref)
}
bkt := ibkt.Bucket([]byte(ref))
if bkt == nil {
return errors.Wrapf(errdefs.ErrNotFound, "reference %v", ref)
}
bref := string(bkt.Get([]byte(ref)))
bref := string(bkt.Get(bucketKeyRef))
if bref == "" {
return errors.Wrapf(errdefs.ErrNotFound, "reference %v", ref)
}
if err := bkt.Delete([]byte(ref)); err != nil {
expected := string(bkt.Get(bucketKeyExpected))
if err := ibkt.DeleteBucket([]byte(ref)); err != nil {
return err
}
return cs.Store.Abort(ctx, bref)
// if not shared content, delete active ingest on backend
if expected == "" {
return cs.Store.Abort(ctx, bref)
}
return nil
})
}
@ -337,8 +349,10 @@ func (cs *contentStore) Writer(ctx context.Context, ref string, size int64, expe
var (
w content.Writer
exists bool
bref string
)
if err := update(ctx, cs.db, func(tx *bolt.Tx) error {
var shared bool
if expected != "" {
cbkt := getBlobBucket(tx, ns, expected)
if cbkt != nil {
@ -352,18 +366,24 @@ func (cs *contentStore) Writer(ctx context.Context, ref string, size int64, expe
exists = true
return nil
}
if st, err := cs.Store.Info(ctx, expected); err == nil {
// Ensure the expected size is the same, it is likely
// an error if the size is mismatched but the caller
// must resolve this on commit
if size == 0 || size == st.Size {
shared = true
size = st.Size
}
}
}
bkt, err := createIngestBucket(tx, ns)
bkt, err := createIngestBucket(tx, ns, ref)
if err != nil {
return err
}
var (
bref string
brefb = bkt.Get([]byte(ref))
)
brefb := bkt.Get(bucketKeyRef)
if brefb == nil {
sid, err := bkt.NextSequence()
if err != nil {
@ -371,21 +391,24 @@ func (cs *contentStore) Writer(ctx context.Context, ref string, size int64, expe
}
bref = createKey(sid, ns, ref)
if err := bkt.Put([]byte(ref), []byte(bref)); err != nil {
if err := bkt.Put(bucketKeyRef, []byte(bref)); err != nil {
return err
}
} else {
bref = string(brefb)
}
// Do not use the passed in expected value here since it was
// already checked against the user metadata. If the content
// store has the content, it must still be written before
// linked into the given namespace. It is possible in the future
// to allow content which exists in content store but not
// namespace to be linked here and returned an exist error, but
// this would require more configuration to make secure.
w, err = cs.Store.Writer(ctx, bref, size, "")
if shared {
if err := bkt.Put(bucketKeyExpected, []byte(expected)); err != nil {
return err
}
} else {
// Do not use the passed in expected value here since it was
// already checked against the user metadata. The content must
// be committed in the namespace before it will be seen as
// available in the current namespace.
w, err = cs.Store.Writer(ctx, bref, size, "")
}
return err
}); err != nil {
return nil, err
@ -394,23 +417,99 @@ func (cs *contentStore) Writer(ctx context.Context, ref string, size int64, expe
return nil, errors.Wrapf(errdefs.ErrAlreadyExists, "content %v", expected)
}
// TODO: keep the expected in the writer to use on commit
// when no expected is provided there.
return &namespacedWriter{
Writer: w,
ctx: ctx,
ref: ref,
namespace: ns,
db: cs.db,
provider: cs.Store,
l: &cs.l,
w: w,
bref: bref,
started: time.Now(),
expected: expected,
size: size,
}, nil
}
type namespacedWriter struct {
content.Writer
ctx context.Context
ref string
namespace string
db transactor
l *sync.RWMutex
provider interface {
content.Provider
content.Ingester
}
l *sync.RWMutex
w content.Writer
bref string
started time.Time
expected digest.Digest
size int64
}
func (nw *namespacedWriter) Close() error {
if nw.w != nil {
return nw.w.Close()
}
return nil
}
func (nw *namespacedWriter) Write(p []byte) (int, error) {
// if no writer, first copy and unshare before performing write
if nw.w == nil {
if len(p) == 0 {
return 0, nil
}
if err := nw.createAndCopy(nw.ctx, nw.size); err != nil {
return 0, err
}
}
return nw.w.Write(p)
}
func (nw *namespacedWriter) Digest() digest.Digest {
if nw.w != nil {
return nw.w.Digest()
}
return nw.expected
}
func (nw *namespacedWriter) Truncate(size int64) error {
if nw.w != nil {
return nw.w.Truncate(size)
}
return nw.createAndCopy(nw.ctx, size)
}
func (nw *namespacedWriter) createAndCopy(ctx context.Context, size int64) error {
w, err := nw.provider.Writer(ctx, nw.bref, nw.size, "")
if err != nil {
return err
}
if size > 0 {
ra, err := nw.provider.ReaderAt(ctx, nw.expected)
if err != nil {
return err
}
defer ra.Close()
if err := content.CopyReaderAt(w, ra, size); err != nil {
nw.w.Close()
nw.w = nil
return err
}
}
nw.w = w
return nil
}
func (nw *namespacedWriter) Commit(ctx context.Context, size int64, expected digest.Digest, opts ...content.Opt) error {
@ -418,9 +517,9 @@ func (nw *namespacedWriter) Commit(ctx context.Context, size int64, expected dig
defer nw.l.RUnlock()
return update(ctx, nw.db, func(tx *bolt.Tx) error {
bkt := getIngestBucket(tx, nw.namespace)
bkt := getIngestsBucket(tx, nw.namespace)
if bkt != nil {
if err := bkt.Delete([]byte(nw.ref)); err != nil {
if err := bkt.DeleteBucket([]byte(nw.ref)); err != nil && err != bolt.ErrBucketNotFound {
return err
}
}
@ -443,24 +542,38 @@ func (nw *namespacedWriter) commit(ctx context.Context, tx *bolt.Tx, size int64,
return "", err
}
status, err := nw.Writer.Status()
if err != nil {
return "", err
}
if size != 0 && size != status.Offset {
return "", errors.Errorf("%q failed size validation: %v != %v", nw.ref, status.Offset, size)
}
size = status.Offset
actual := nw.Writer.Digest()
if err := nw.Writer.Commit(ctx, size, expected); err != nil {
if !errdefs.IsAlreadyExists(err) {
return "", err
var actual digest.Digest
if nw.w == nil {
if size != 0 && size != nw.size {
return "", errors.Errorf("%q failed size validation: %v != %v", nw.ref, nw.size, size)
}
if expected != "" && expected != nw.expected {
return "", errors.Errorf("%q unexpected digest", nw.ref)
}
size = nw.size
actual = nw.expected
if getBlobBucket(tx, nw.namespace, actual) != nil {
return "", errors.Wrapf(errdefs.ErrAlreadyExists, "content %v", actual)
}
} else {
status, err := nw.w.Status()
if err != nil {
return "", err
}
if size != 0 && size != status.Offset {
return "", errors.Errorf("%q failed size validation: %v != %v", nw.ref, status.Offset, size)
}
size = status.Offset
actual = nw.w.Digest()
if err := nw.w.Commit(ctx, size, expected); err != nil {
if !errdefs.IsAlreadyExists(err) {
return "", err
}
if getBlobBucket(tx, nw.namespace, actual) != nil {
return "", errors.Wrapf(errdefs.ErrAlreadyExists, "content %v", actual)
}
}
}
bkt, err := createBlobBucket(tx, nw.namespace, actual)
@ -484,12 +597,20 @@ func (nw *namespacedWriter) commit(ctx context.Context, tx *bolt.Tx, size int64,
return actual, bkt.Put(bucketKeySize, sizeEncoded)
}
func (nw *namespacedWriter) Status() (content.Status, error) {
st, err := nw.Writer.Status()
func (nw *namespacedWriter) Status() (st content.Status, err error) {
if nw.w != nil {
st, err = nw.w.Status()
} else {
st.Offset = nw.size
st.Total = nw.size
st.StartedAt = nw.started
st.UpdatedAt = nw.started
st.Expected = nw.expected
}
if err == nil {
st.Ref = nw.ref
}
return st, err
return
}
func (cs *contentStore) ReaderAt(ctx context.Context, dgst digest.Digest) (content.ReaderAt, error) {
@ -590,13 +711,30 @@ func (cs *contentStore) garbageCollect(ctx context.Context) (d time.Duration, er
continue
}
bbkt := cbkt.Bucket(bucketKeyObjectBlob)
if err := bbkt.ForEach(func(ck, cv []byte) error {
if cv == nil {
seen[string(ck)] = struct{}{}
if bbkt != nil {
if err := bbkt.ForEach(func(ck, cv []byte) error {
if cv == nil {
seen[string(ck)] = struct{}{}
}
return nil
}); err != nil {
return err
}
}
ibkt := cbkt.Bucket(bucketKeyObjectIngests)
if ibkt != nil {
if err := ibkt.ForEach(func(ref, v []byte) error {
if v == nil {
expected := ibkt.Bucket(ref).Get(bucketKeyExpected)
if len(expected) > 0 {
seen[string(expected)] = struct{}{}
}
}
return nil
}); err != nil {
return err
}
return nil
}); err != nil {
return err
}
}

View file

@ -43,7 +43,7 @@ const (
// dbVersion represents updates to the schema
// version which are additions and compatible with
// prior version of the same schema.
dbVersion = 1
dbVersion = 2
)
// DB represents a metadata database backed by a bolt
@ -195,6 +195,15 @@ func (m *DB) Snapshotter(name string) snapshots.Snapshotter {
return sn
}
// Snapshotters returns all available snapshotters.
func (m *DB) Snapshotters() map[string]snapshots.Snapshotter {
ss := make(map[string]snapshots.Snapshotter, len(m.ss))
for n, sn := range m.ss {
ss[n] = sn
}
return ss
}
// View runs a readonly transaction on the metadata store.
func (m *DB) View(fn func(*bolt.Tx) error) error {
return m.db.View(fn)

View file

@ -17,6 +17,7 @@
package metadata
import (
"bytes"
"context"
"fmt"
"strings"
@ -345,7 +346,10 @@ func sendSnapshotRefs(ns string, bkt *bolt.Bucket, fn func(gc.Node)) error {
lc := lbkt.Cursor()
for k, v := lc.Seek(labelGCSnapRef); k != nil && strings.HasPrefix(string(k), string(labelGCSnapRef)); k, v = lc.Next() {
snapshotter := string(k[len(labelGCSnapRef):])
snapshotter := k[len(labelGCSnapRef):]
if i := bytes.IndexByte(snapshotter, '/'); i >= 0 {
snapshotter = snapshotter[:i]
}
fn(gcnode(ResourceSnapshot, ns, fmt.Sprintf("%s/%s", snapshotter, v)))
}
}
@ -361,8 +365,8 @@ func sendContentRefs(ns string, bkt *bolt.Bucket, fn func(gc.Node)) error {
labelRef := string(labelGCContentRef)
for k, v := lc.Seek(labelGCContentRef); k != nil && strings.HasPrefix(string(k), labelRef); k, v = lc.Next() {
if ks := string(k); ks != labelRef {
// Allow reference naming, ignore names
if ks[len(labelRef)] != '.' {
// Allow reference naming separated by . or /, ignore names
if ks[len(labelRef)] != '.' && ks[len(labelRef)] != '/' {
continue
}
}

View file

@ -40,6 +40,11 @@ var migrations = []migration{
version: 1,
migrate: addChildLinks,
},
{
schema: "v1",
version: 2,
migrate: migrateIngests,
},
}
// addChildLinks Adds children key to the snapshotters to enforce snapshot
@ -99,3 +104,53 @@ func addChildLinks(tx *bolt.Tx) error {
return nil
}
// migrateIngests moves ingests from the key/value ingest bucket
// to a structured ingest bucket for storing additional state about
// an ingest.
func migrateIngests(tx *bolt.Tx) error {
v1bkt := tx.Bucket(bucketKeyVersion)
if v1bkt == nil {
return nil
}
// iterate through each namespace
v1c := v1bkt.Cursor()
for k, v := v1c.First(); k != nil; k, v = v1c.Next() {
if v != nil {
continue
}
bkt := v1bkt.Bucket(k).Bucket(bucketKeyObjectContent)
if bkt == nil {
continue
}
dbkt := bkt.Bucket(deprecatedBucketKeyObjectIngest)
if dbkt == nil {
continue
}
// Create new ingests bucket
nbkt, err := bkt.CreateBucketIfNotExists(bucketKeyObjectIngests)
if err != nil {
return err
}
if err := dbkt.ForEach(func(ref, bref []byte) error {
ibkt, err := nbkt.CreateBucketIfNotExists(ref)
if err != nil {
return err
}
return ibkt.Put(bucketKeyRef, bref)
}); err != nil {
return err
}
if err := bkt.DeleteBucket(deprecatedBucketKeyObjectIngest); err != nil {
return err
}
}
return nil
}

View file

@ -613,14 +613,23 @@ func validateSnapshot(info *snapshots.Info) error {
return nil
}
type cleaner interface {
Cleanup(ctx context.Context) error
}
func (s *snapshotter) garbageCollect(ctx context.Context) (d time.Duration, err error) {
s.l.Lock()
t1 := time.Now()
defer func() {
s.l.Unlock()
if err == nil {
if c, ok := s.Snapshotter.(cleaner); ok {
err = c.Cleanup(ctx)
}
}
if err == nil {
d = time.Now().Sub(t1)
}
s.l.Unlock()
}()
seen := map[string]struct{}{}

View file

@ -23,27 +23,10 @@ import (
"fmt"
"io"
"os"
"strconv"
"strings"
)
const (
/* 36 35 98:0 /mnt1 /mnt2 rw,noatime master:1 - ext3 /dev/root rw,errors=continue
(1)(2)(3) (4) (5) (6) (7) (8) (9) (10) (11)
(1) mount ID: unique identifier of the mount (may be reused after umount)
(2) parent ID: ID of parent (or of self for the top of the mount tree)
(3) major:minor: value of st_dev for files on filesystem
(4) root: root of the mount within the filesystem
(5) mount point: mount point relative to the process's root
(6) mount options: per mount options
(7) optional fields: zero or more fields of the form "tag[:value]"
(8) separator: marks the end of the optional fields
(9) filesystem type: name of filesystem of the form "type[.subtype]"
(10) mount source: filesystem specific information or "none"
(11) super options: per super block options*/
mountinfoFormat = "%d %d %d:%d %s %s %s %s"
)
// Self retrieves a list of mounts for the current running process.
func Self() ([]Info, error) {
f, err := os.Open("/proc/self/mountinfo")
@ -56,41 +39,83 @@ func Self() ([]Info, error) {
}
func parseInfoFile(r io.Reader) ([]Info, error) {
var (
s = bufio.NewScanner(r)
out = []Info{}
)
s := bufio.NewScanner(r)
out := []Info{}
for s.Scan() {
if err := s.Err(); err != nil {
return nil, err
}
var (
p = Info{}
text = s.Text()
optionalFields string
)
/*
36 35 98:0 /mnt1 /mnt2 rw,noatime master:1 - ext3 /dev/root rw,errors=continue
(1)(2)(3) (4) (5) (6) (7) (8) (9) (10) (11)
(1) mount ID: unique identifier of the mount (may be reused after umount)
(2) parent ID: ID of parent (or of self for the top of the mount tree)
(3) major:minor: value of st_dev for files on filesystem
(4) root: root of the mount within the filesystem
(5) mount point: mount point relative to the process's root
(6) mount options: per mount options
(7) optional fields: zero or more fields of the form "tag[:value]"
(8) separator: marks the end of the optional fields
(9) filesystem type: name of filesystem of the form "type[.subtype]"
(10) mount source: filesystem specific information or "none"
(11) super options: per super block options
*/
if _, err := fmt.Sscanf(text, mountinfoFormat,
&p.ID, &p.Parent, &p.Major, &p.Minor,
&p.Root, &p.Mountpoint, &p.Options, &optionalFields); err != nil {
return nil, fmt.Errorf("Scanning '%s' failed: %s", text, err)
text := s.Text()
fields := strings.Split(text, " ")
numFields := len(fields)
if numFields < 10 {
// should be at least 10 fields
return nil, fmt.Errorf("Parsing '%s' failed: not enough fields (%d)", text, numFields)
}
// Safe as mountinfo encodes mountpoints with spaces as \040.
index := strings.Index(text, " - ")
postSeparatorFields := strings.Fields(text[index+3:])
if len(postSeparatorFields) < 3 {
return nil, fmt.Errorf("Error found less than 3 fields post '-' in %q", text)
p := Info{}
// ignore any numbers parsing errors, as there should not be any
p.ID, _ = strconv.Atoi(fields[0])
p.Parent, _ = strconv.Atoi(fields[1])
mm := strings.Split(fields[2], ":")
if len(mm) != 2 {
return nil, fmt.Errorf("Parsing '%s' failed: unexpected minor:major pair %s", text, mm)
}
p.Major, _ = strconv.Atoi(mm[0])
p.Minor, _ = strconv.Atoi(mm[1])
if optionalFields != "-" {
p.Optional = optionalFields
}
p.Root = fields[3]
p.Mountpoint = fields[4]
p.Options = fields[5]
// one or more optional fields, when a separator (-)
i := 6
for ; i < numFields && fields[i] != "-"; i++ {
switch i {
case 6:
p.Optional = fields[6]
default:
/* NOTE there might be more optional fields before the separator
such as fields[7]...fields[N] (where N < separatorIndex),
although as of Linux kernel 4.15 the only known ones are
mount propagation flags in fields[6]. The correct
behavior is to ignore any unknown optional fields.
*/
}
}
if i == numFields {
return nil, fmt.Errorf("Parsing '%s' failed: missing separator ('-')", text)
}
// There should be 3 fields after the separator...
if i+4 > numFields {
return nil, fmt.Errorf("Parsing '%s' failed: not enough fields after a separator", text)
}
// ... but in Linux <= 3.9 mounting a cifs with spaces in a share name
// (like "//serv/My Documents") _may_ end up having a space in the last field
// of mountinfo (like "unc=//serv/My Documents"). Since kernel 3.10-rc1, cifs
// option unc= is ignored, so a space should not appear. In here we ignore
// those "extra" fields caused by extra spaces.
p.FSType = fields[i+1]
p.Source = fields[i+2]
p.VFSOptions = fields[i+3]
p.FSType = postSeparatorFields[0]
p.Source = postSeparatorFields[1]
p.VFSOptions = strings.Join(postSeparatorFields[2:], " ")
out = append(out, p)
}
return out, nil

View file

@ -1,3 +1,19 @@
/*
Copyright The containerd Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package mount
import (
@ -9,7 +25,7 @@ import (
"github.com/pkg/errors"
)
var tempMountLocation = os.TempDir()
var tempMountLocation = getTempDir()
// WithTempMount mounts the provided mounts to a temp dir, and pass the temp dir to f.
// The mounts are valid during the call to the f.
@ -48,3 +64,10 @@ func WithTempMount(ctx context.Context, mounts []Mount, f func(root string) erro
}
return errors.Wrapf(f(root), "mount callback failed on %s", root)
}
func getTempDir() string {
if xdg := os.Getenv("XDG_RUNTIME_DIR"); xdg != "" {
return xdg
}
return os.TempDir()
}

View file

@ -1,5 +1,21 @@
// +build !windows
/*
Copyright The containerd Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package mount
import (

Some files were not shown because too many files have changed in this diff Show more