add v3 api

Signed-off-by: Jess Frazelle <acidburn@microsoft.com>
This commit is contained in:
Jess Frazelle 2018-06-11 12:48:47 -04:00
parent fc4797acd4
commit 67bc3ef6c3
No known key found for this signature in database
GPG key ID: 18F3685C0022BFF3
510 changed files with 254805 additions and 259 deletions

115
Gopkg.lock generated
View file

@ -34,6 +34,16 @@
packages = ["pathdriver"]
revision = "d3c23511c1bf5851696cba83143d9cbcd666869b"
[[projects]]
branch = "master"
name = "github.com/coreos/clair"
packages = [
"api/v3/clairpb",
"database",
"ext/versionfmt"
]
revision = "e907e4d263a743f7d4923c177e5db37f656a53b4"
[[projects]]
branch = "master"
name = "github.com/docker/cli"
@ -42,7 +52,7 @@
"cli/config/credentials",
"opts"
]
revision = "90f8ce8a5db263842af7bef3726f6c4d6937d85e"
revision = "4cb3c70f36baeade76879694a587358be2a74854"
[[projects]]
branch = "master"
@ -103,13 +113,13 @@
"registry",
"registry/resumable"
]
revision = "fd2f2a919e392b96de74795ae9af2dc5e510bc4c"
revision = "d812dee47e26ad4db1d53102f0c16af01f70cf2c"
[[projects]]
branch = "master"
name = "github.com/docker/docker-ce"
packages = ["components/cli/cli/config"]
revision = "370137f15d67e96f4d4435fc868fb2deec6f1f89"
revision = "ecac08f83bacbf4b72d6a55e0de3e7969919d0a5"
[[projects]]
name = "github.com/docker/docker-credential-helpers"
@ -157,7 +167,17 @@
[[projects]]
name = "github.com/golang/protobuf"
packages = ["proto"]
packages = [
"jsonpb",
"proto",
"protoc-gen-go/descriptor",
"ptypes",
"ptypes/any",
"ptypes/duration",
"ptypes/empty",
"ptypes/struct",
"ptypes/timestamp"
]
revision = "b4deda0973fb4c70b50d226b1af49f3da59f5265"
version = "v1.1.0"
@ -184,6 +204,16 @@
revision = "e3702bed27f0d39777b0b37b664b6280e8ef8fbf"
version = "v1.6.2"
[[projects]]
name = "github.com/grpc-ecosystem/grpc-gateway"
packages = [
"runtime",
"runtime/internal",
"utilities"
]
revision = "92583770e3f01b09a0d3e9bdf64321d8bebd48f2"
version = "v1.4.1"
[[projects]]
name = "github.com/matttproud/golang_protobuf_extensions"
packages = ["pbutil"]
@ -236,7 +266,7 @@
"prometheus",
"prometheus/promhttp"
]
revision = "208fa994be3bd65c0de04f506db92852b581bc4a"
revision = "faf4ec335fe01ae5a6a0eaa34a5a9333bfbd1a30"
[[projects]]
branch = "master"
@ -281,7 +311,7 @@
branch = "master"
name = "golang.org/x/crypto"
packages = ["ssh/terminal"]
revision = "b47b1587369238182299fe4dad77d05b8b461e06"
revision = "8ac0e0d97ce45cd83d1d7243c060cb8461dda5e9"
[[projects]]
branch = "master"
@ -289,8 +319,14 @@
packages = [
"context",
"context/ctxhttp",
"http/httpguts",
"http2",
"http2/hpack",
"idna",
"internal/socks",
"proxy"
"internal/timeseries",
"proxy",
"trace"
]
revision = "1e491301e022f8f977054da4c2d852decd59571f"
@ -301,11 +337,72 @@
"unix",
"windows"
]
revision = "538ab54ba952cc4c7c705fa213fbf7993c97c175"
revision = "bff228c7b664c5fce602223a05fb708fd8654986"
[[projects]]
name = "golang.org/x/text"
packages = [
"collate",
"collate/build",
"internal/colltab",
"internal/gen",
"internal/tag",
"internal/triegen",
"internal/ucd",
"language",
"secure/bidirule",
"transform",
"unicode/bidi",
"unicode/cldr",
"unicode/norm",
"unicode/rangetable"
]
revision = "f21a4dfb5e38f5895301dc265a8def02365cc3d0"
version = "v0.3.0"
[[projects]]
branch = "master"
name = "google.golang.org/genproto"
packages = [
"googleapis/api/annotations",
"googleapis/rpc/status"
]
revision = "32ee49c4dd805befd833990acba36cb75042378c"
[[projects]]
name = "google.golang.org/grpc"
packages = [
".",
"balancer",
"balancer/base",
"balancer/roundrobin",
"channelz",
"codes",
"connectivity",
"credentials",
"encoding",
"encoding/proto",
"grpclb/grpc_lb_v1/messages",
"grpclog",
"internal",
"keepalive",
"metadata",
"naming",
"peer",
"resolver",
"resolver/dns",
"resolver/passthrough",
"stats",
"status",
"tap",
"transport"
]
revision = "7a6a684ca69eb4cae85ad0a484f2e531598c047b"
version = "v1.12.2"
[solve-meta]
analyzer-name = "dep"
analyzer-version = 1
inputs-digest = "5cdf10e821ede3dcf4207f6e2b0e5abe31ac803e81704a82c798b0199c057882"
inputs-digest = "7c1fd839f687a4f2c428d59dc6ec6387743b88aeec7d16d7818b881879f07b81"
solver-name = "gps-cdcl"
solver-version = 1

79
clair/ancestry.go Normal file
View file

@ -0,0 +1,79 @@
package clair
import (
"bytes"
"encoding/json"
"net/http"
"github.com/coreos/clair/api/v3/clairpb"
)
// GetAncestry displays an ancestry and optionally all of its features and vulnerabilities.
func (c *Clair) GetAncestry(name string, features, vulnerabilities bool) (*clairpb.Ancestry, error) {
url := c.url("/v3/ancestry")
c.Logf("clair.ancestry.get url=%s name=%s", url, name)
b, err := json.Marshal(clairpb.GetAncestryRequest{AncestryName: name, WithVulnerabilities: vulnerabilities, WithFeatures: features})
if err != nil {
return nil, err
}
c.Logf("clair.ancestry.get req.Body=%s", string(b))
req, err := http.NewRequest("GET", url, bytes.NewReader(b))
if err != nil {
return nil, err
}
req.Header.Set("Content-Type", "application/json")
resp, err := c.Client.Do(req)
if err != nil {
return nil, err
}
defer resp.Body.Close()
c.Logf("clair.ancestry.get resp.Status=%s", resp.Status)
var aResp clairpb.GetAncestryResponse
if err := json.NewDecoder(resp.Body).Decode(&aResp); err != nil {
return nil, err
}
if aResp.GetStatus() != nil {
c.Logf("clair.ancestry.get ClairStatus=%#v", *aResp.GetStatus())
}
return aResp.GetAncestry(), nil
}
// PostAncestry performs the analysis of all layers from the provided path.
func (c *Clair) PostAncestry(name string, layers []*clairpb.PostAncestryRequest_PostLayer) error {
url := c.url("/v3/ancestry")
c.Logf("clair.ancestry.post url=%s name=%s", url, name)
b, err := json.Marshal(clairpb.PostAncestryRequest{AncestryName: name, Layers: layers})
if err != nil {
return err
}
c.Logf("clair.ancestry.post req.Body=%s", string(b))
resp, err := c.Client.Post(url, "application/json", bytes.NewReader(b))
if err != nil {
return err
}
defer resp.Body.Close()
c.Logf("clair.ancestry.post resp.Status=%s", resp.Status)
var aResp clairpb.PostAncestryResponse
if err := json.NewDecoder(resp.Body).Decode(&aResp); err != nil {
return err
}
if aResp.GetStatus() != nil {
c.Logf("clair.ancestry.post ClairStatus=%#v", *aResp.GetStatus())
}
return nil
}

View file

@ -34,14 +34,15 @@ func (c *Clair) PostLayer(layer *Layer) (*Layer, error) {
return nil, err
}
c.Logf("clair.clair req.Body=%s", string(b))
c.Logf("clair.layers.post req.Body=%s", string(b))
resp, err := c.Client.Post(url, "application/json", bytes.NewReader(b))
if err != nil {
return nil, err
}
defer resp.Body.Close()
c.Logf("clair.clair resp.Status=%s", resp.Status)
c.Logf("clair.layers.post resp.Status=%s", resp.Status)
var respLayer layerEnvelope
if err := json.NewDecoder(resp.Body).Decode(&respLayer); err != nil {

7
vendor/github.com/coreos/clair/.dockerignore generated vendored Normal file
View file

@ -0,0 +1,7 @@
.*
*.md
DCO
LICENSE
NOTICE
docs
cloudconfig

38
vendor/github.com/coreos/clair/.travis.yml generated vendored Normal file
View file

@ -0,0 +1,38 @@
language: go
go:
- "1.10"
sudo: required
install:
- curl https://glide.sh/get | sh
script:
- go test $(glide novendor | grep -v contrib)
dist: trusty
services:
- postgresql
notifications:
email: false
matrix:
include:
- addons:
apt:
packages:
- rpm
postgresql: 9.4
- addons:
apt:
packages:
- rpm
postgresql: 9.5
- addons:
apt:
packages:
- rpm
postgresql: 9.6

36
vendor/github.com/coreos/clair/DCO generated vendored Executable file
View file

@ -0,0 +1,36 @@
Developer Certificate of Origin
Version 1.1
Copyright (C) 2004, 2006 The Linux Foundation and its contributors.
660 York Street, Suite 102,
San Francisco, CA 94110 USA
Everyone is permitted to copy and distribute verbatim copies of this
license document, but changing it is not allowed.
Developer's Certificate of Origin 1.1
By making a contribution to this project, I certify that:
(a) The contribution was created in whole or in part by me and I
have the right to submit it under the open source license
indicated in the file; or
(b) The contribution is based upon previous work that, to the best
of my knowledge, is covered under an appropriate open source
license and I have the right under that license to submit that
work with modifications, whether created in whole or in part
by me, under the same open source license (unless I am
permitted to submit under a different license), as indicated
in the file; or
(c) The contribution was provided directly to me by some other
person who certified (a), (b) or (c) and I have not modified
it.
(d) I understand and agree that this project and the contribution
are public and that a record of the contribution (including all
personal information I submit with it, including my sign-off) is
maintained indefinitely and may be redistributed consistent with
this project or the open source license(s) involved.

29
vendor/github.com/coreos/clair/Dockerfile generated vendored Normal file
View file

@ -0,0 +1,29 @@
# Copyright 2017 clair 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.
FROM golang:1.10-alpine
VOLUME /config
EXPOSE 6060 6061
ADD . /go/src/github.com/coreos/clair/
WORKDIR /go/src/github.com/coreos/clair/
RUN apk add --no-cache git bzr rpm xz dumb-init && \
go install -v github.com/coreos/clair/cmd/clair && \
mv /go/bin/clair /clair && \
rm -rf /go /usr/local/go
ENTRYPOINT ["/usr/bin/dumb-init", "--", "/clair"]

202
vendor/github.com/coreos/clair/LICENSE generated vendored Executable file
View file

@ -0,0 +1,202 @@
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
1. Definitions.
"License" shall mean the terms and conditions for use, reproduction,
and distribution as defined by Sections 1 through 9 of this document.
"Licensor" shall mean the copyright owner or entity authorized by
the copyright owner that is granting the License.
"Legal Entity" shall mean the union of the acting entity and all
other entities that control, are controlled by, or are under common
control with that entity. For the purposes of this definition,
"control" means (i) the power, direct or indirect, to cause the
direction or management of such entity, whether by contract or
otherwise, or (ii) ownership of fifty percent (50%) or more of the
outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity
exercising permissions granted by this License.
"Source" form shall mean the preferred form for making modifications,
including but not limited to software source code, documentation
source, and configuration files.
"Object" form shall mean any form resulting from mechanical
transformation or translation of a Source form, including but
not limited to compiled object code, generated documentation,
and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or
Object form, made available under the License, as indicated by a
copyright notice that is included in or attached to the work
(an example is provided in the Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object
form, that is based on (or derived from) the Work and for which the
editorial revisions, annotations, elaborations, or other modifications
represent, as a whole, an original work of authorship. For the purposes
of this License, Derivative Works shall not include works that remain
separable from, or merely link (or bind by name) to the interfaces of,
the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including
the original version of the Work and any modifications or additions
to that Work or Derivative Works thereof, that is intentionally
submitted to Licensor for inclusion in the Work by the copyright owner
or by an individual or Legal Entity authorized to submit on behalf of
the copyright owner. For the purposes of this definition, "submitted"
means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems,
and issue tracking systems that are managed by, or on behalf of, the
Licensor for the purpose of discussing and improving the Work, but
excluding communication that is conspicuously marked or otherwise
designated in writing by the copyright owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity
on behalf of whom a Contribution has been received by Licensor and
subsequently incorporated within the Work.
2. Grant of Copyright License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the
Work and such Derivative Works in Source or Object form.
3. Grant of Patent License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
(except as stated in this section) patent license to make, have made,
use, offer to sell, sell, import, and otherwise transfer the Work,
where such license applies only to those patent claims licensable
by such Contributor that are necessarily infringed by their
Contribution(s) alone or by combination of their Contribution(s)
with the Work to which such Contribution(s) was submitted. If You
institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work
or a Contribution incorporated within the Work constitutes direct
or contributory patent infringement, then any patent licenses
granted to You under this License for that Work shall terminate
as of the date such litigation is filed.
4. Redistribution. You may reproduce and distribute copies of the
Work or Derivative Works thereof in any medium, with or without
modifications, and in Source or Object form, provided that You
meet the following conditions:
(a) You must give any other recipients of the Work or
Derivative Works a copy of this License; and
(b) You must cause any modified files to carry prominent notices
stating that You changed the files; and
(c) You must retain, in the Source form of any Derivative Works
that You distribute, all copyright, patent, trademark, and
attribution notices from the Source form of the Work,
excluding those notices that do not pertain to any part of
the Derivative Works; and
(d) If the Work includes a "NOTICE" text file as part of its
distribution, then any Derivative Works that You distribute must
include a readable copy of the attribution notices contained
within such NOTICE file, excluding those notices that do not
pertain to any part of the Derivative Works, in at least one
of the following places: within a NOTICE text file distributed
as part of the Derivative Works; within the Source form or
documentation, if provided along with the Derivative Works; or,
within a display generated by the Derivative Works, if and
wherever such third-party notices normally appear. The contents
of the NOTICE file are for informational purposes only and
do not modify the License. You may add Your own attribution
notices within Derivative Works that You distribute, alongside
or as an addendum to the NOTICE text from the Work, provided
that such additional attribution notices cannot be construed
as modifying the License.
You may add Your own copyright statement to Your modifications and
may provide additional or different license terms and conditions
for use, reproduction, or distribution of Your modifications, or
for any such Derivative Works as a whole, provided Your use,
reproduction, and distribution of the Work otherwise complies with
the conditions stated in this License.
5. Submission of Contributions. Unless You explicitly state otherwise,
any Contribution intentionally submitted for inclusion in the Work
by You to the Licensor shall be under the terms and conditions of
this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify
the terms of any separate license agreement you may have executed
with Licensor regarding such Contributions.
6. Trademarks. This License does not grant permission to use the trade
names, trademarks, service marks, or product names of the Licensor,
except as required for reasonable and customary use in describing the
origin of the Work and reproducing the content of the NOTICE file.
7. Disclaimer of Warranty. Unless required by applicable law or
agreed to in writing, Licensor provides the Work (and each
Contributor provides its Contributions) on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied, including, without limitation, any warranties or conditions
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
PARTICULAR PURPOSE. You are solely responsible for determining the
appropriateness of using or redistributing the Work and assume any
risks associated with Your exercise of permissions under this License.
8. Limitation of Liability. In no event and under no legal theory,
whether in tort (including negligence), contract, or otherwise,
unless required by applicable law (such as deliberate and grossly
negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special,
incidental, or consequential damages of any character arising as a
result of this License or out of the use or inability to use the
Work (including but not limited to damages for loss of goodwill,
work stoppage, computer failure or malfunction, or any and all
other commercial damages or losses), even if such Contributor
has been advised of the possibility of such damages.
9. Accepting Warranty or Additional Liability. While redistributing
the Work or Derivative Works thereof, You may choose to offer,
and charge a fee for, acceptance of support, warranty, indemnity,
or other liability obligations and/or rights consistent with this
License. However, in accepting such obligations, You may act only
on Your own behalf and on Your sole responsibility, not on behalf
of any other Contributor, and only if You agree to indemnify,
defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason
of your accepting any such warranty or additional liability.
END OF TERMS AND CONDITIONS
APPENDIX: How to apply the Apache License to your work.
To apply the Apache License to your work, attach the following
boilerplate notice, with the fields enclosed by brackets "{}"
replaced with your own identifying information. (Don't include
the brackets!) The text should be enclosed in the appropriate
comment syntax for the file format. We also recommend that a
file or class name and description of purpose be included on the
same "printed page" as the copyright notice for easier
identification within third-party archives.
Copyright {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.
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.

5
vendor/github.com/coreos/clair/NOTICE generated vendored Executable file
View file

@ -0,0 +1,5 @@
CoreOS Project
Copyright 2015 CoreOS, Inc
This product includes software developed at CoreOS, Inc.
(http://www.coreos.com/).

58
vendor/github.com/coreos/clair/README.md generated vendored Normal file
View file

@ -0,0 +1,58 @@
# Clair
[![Build Status](https://api.travis-ci.org/coreos/clair.svg?branch=master "Build Status")](https://travis-ci.org/coreos/clair)
[![Docker Repository on Quay](https://quay.io/repository/coreos/clair/status "Docker Repository on Quay")](https://quay.io/repository/coreos/clair)
[![Go Report Card](https://goreportcard.com/badge/coreos/clair "Go Report Card")](https://goreportcard.com/report/coreos/clair)
[![GoDoc](https://godoc.org/github.com/coreos/clair?status.svg "GoDoc")](https://godoc.org/github.com/coreos/clair)
[![IRC Channel](https://img.shields.io/badge/freenode-%23clair-blue.svg "IRC Channel")](http://webchat.freenode.net/?channels=clair)
**Note**: The `master` branch may be in an *unstable or even broken state* during development.
Please use [releases] instead of the `master` branch in order to get stable binaries.
![Clair Logo](https://cloud.githubusercontent.com/assets/343539/21630811/c5081e5c-d202-11e6-92eb-919d5999c77a.png)
Clair is an open source project for the [static analysis] of vulnerabilities in application containers (currently including [appc] and [docker]).
1. In regular intervals, Clair ingests vulnerability metadata from a configured set of sources and stores it in the database.
2. Clients use the Clair API to index their container images; this creates a list of _features_ present in the image and stores them in the database.
3. Clients use the Clair API to query the database for vulnerabilities of a particular image; correlating vulnerabilities and features is done for each request, avoiding the need to rescan images.
4. When updates to vulnerability metadata occur, a notification can be sent to alert systems that a change has occured.
Our goal is to enable a more transparent view of the security of container-based infrastructure.
Thus, the project was named `Clair` after the French term which translates to *clear*, *bright*, *transparent*.
[appc]: https://github.com/appc/spec
[docker]: https://github.com/docker/docker/blob/master/image/spec/v1.2.md
[releases]: https://github.com/coreos/clair/releases
[static analysis]: https://en.wikipedia.org/wiki/Static_program_analysis
## Getting Started
* Learn [the terminology] and about the [drivers and data sources] that power Clair
* Watch [presentations] on the high-level goals and design of Clair
* Follow instructions to get Clair [up and running]
* Explore [the API] on SwaggerHub
* Discover third party [integrations] that help integrate Clair with your infrastructure
* Read the rest of the documentation on the [CoreOS website] or in the [Documentation directory]
[the terminology]: /Documentation/terminology.md
[drivers and data sources]: /Documentation/drivers-and-data-sources.md
[presentations]: /Documentation/presentations.md
[up and running]: /Documentation/running-clair.md
[the API]: https://app.swaggerhub.com/apis/coreos/clair/3.0
[integrations]: /Documentation/integrations.md
[CoreOS website]: https://coreos.com/clair/docs/latest/
[Documentation directory]: /Documentation
## Contact
- IRC: #[clair](irc://irc.freenode.org:6667/#clair) on freenode.org
- Bugs: [issues](https://github.com/coreos/clair/issues)
## Contributing
See [CONTRIBUTING](.github/CONTRIBUTING.md) for details on submitting patches and the contribution workflow.
## License
Clair is under the Apache 2.0 license. See the [LICENSE](LICENSE) file for details.

15
vendor/github.com/coreos/clair/ROADMAP.md generated vendored Normal file
View file

@ -0,0 +1,15 @@
# Clair Roadmap
This document defines a high level roadmap for Clair development.
The dates below should not be considered authoritative, but rather indicative of the projected timeline of the project.
The [milestones defined in GitHub](https://github.com/coreos/clair/milestones) represent the most up-to-date and issue-for-issue plans.
The roadmap below outlines new features that will be added to Clair, and while subject to change, define what future stable will look like.
- Support multiple namespaces per image
- This enables language-level package managers (e.g. npm, pip)
- Improve coverage and readability of documentation
- Decouple the project from Postgres
- gRPC API supporting direct uploads of images
- Support operating Clair without internet access

127
vendor/github.com/coreos/clair/api/api.go generated vendored Normal file
View file

@ -0,0 +1,127 @@
// Copyright 2017 clair 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 api
import (
"crypto/tls"
"crypto/x509"
"io/ioutil"
"net"
"net/http"
"time"
log "github.com/sirupsen/logrus"
"github.com/tylerb/graceful"
"github.com/coreos/clair/api/v3"
"github.com/coreos/clair/database"
"github.com/coreos/clair/pkg/stopper"
)
const timeoutResponse = `{"Error":{"Message":"Clair failed to respond within the configured timeout window.","Type":"Timeout"}}`
// Config is the configuration for the API service.
type Config struct {
Addr string
HealthAddr string
Timeout time.Duration
CertFile, KeyFile, CAFile string
}
func Run(cfg *Config, store database.Datastore) {
tlsConfig, err := tlsClientConfig(cfg.CAFile)
if err != nil {
log.WithError(err).Fatal("could not initialize client cert authentication")
}
if tlsConfig != nil {
log.Info("main API configured with client certificate authentication")
}
v3.Run(cfg.Addr, tlsConfig, cfg.CertFile, cfg.KeyFile, store)
}
func RunHealth(cfg *Config, store database.Datastore, st *stopper.Stopper) {
defer st.End()
// Do not run the API service if there is no config.
if cfg == nil {
log.Info("health API service is disabled.")
return
}
log.WithField("addr", cfg.HealthAddr).Info("starting health API")
srv := &graceful.Server{
Timeout: 10 * time.Second, // Interrupt health checks when stopping
NoSignalHandling: true, // We want to use our own Stopper
Server: &http.Server{
Addr: cfg.HealthAddr,
Handler: http.TimeoutHandler(newHealthHandler(store), cfg.Timeout, timeoutResponse),
},
}
listenAndServeWithStopper(srv, st, "", "")
log.Info("health API stopped")
}
// listenAndServeWithStopper wraps graceful.Server's
// ListenAndServe/ListenAndServeTLS and adds the ability to interrupt them with
// the provided stopper.Stopper.
func listenAndServeWithStopper(srv *graceful.Server, st *stopper.Stopper, certFile, keyFile string) {
go func() {
<-st.Chan()
srv.Stop(0)
}()
var err error
if certFile != "" && keyFile != "" {
log.Info("API: TLS Enabled")
err = srv.ListenAndServeTLS(certFile, keyFile)
} else {
err = srv.ListenAndServe()
}
if err != nil {
if opErr, ok := err.(*net.OpError); !ok || (ok && opErr.Op != "accept") {
log.Fatal(err)
}
}
}
// tlsClientConfig initializes a *tls.Config using the given CA. The resulting
// *tls.Config is meant to be used to configure an HTTP server to do client
// certificate authentication.
//
// If no CA is given, a nil *tls.Config is returned; no client certificate will
// be required and verified. In other words, authentication will be disabled.
func tlsClientConfig(caPath string) (*tls.Config, error) {
if caPath == "" {
return nil, nil
}
caCert, err := ioutil.ReadFile(caPath)
if err != nil {
return nil, err
}
caCertPool := x509.NewCertPool()
caCertPool.AppendCertsFromPEM(caCert)
tlsConfig := &tls.Config{
ClientCAs: caCertPool,
ClientAuth: tls.RequireAndVerifyClientCert,
}
return tlsConfig, nil
}

47
vendor/github.com/coreos/clair/api/router.go generated vendored Normal file
View file

@ -0,0 +1,47 @@
// Copyright 2017 clair 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 api
import (
"net/http"
"github.com/julienschmidt/httprouter"
"github.com/coreos/clair/database"
)
// router is an HTTP router that forwards requests to the appropriate sub-router
// depending on the API version specified in the request URI.
type router map[string]*httprouter.Router
func newHealthHandler(store database.Datastore) http.Handler {
router := httprouter.New()
router.GET("/health", healthHandler(store))
return router
}
func healthHandler(store database.Datastore) httprouter.Handle {
return func(w http.ResponseWriter, r *http.Request, p httprouter.Params) {
header := w.Header()
header.Set("Server", "clair")
status := http.StatusInternalServerError
if store.Ping() {
status = http.StatusOK
}
w.WriteHeader(status)
}
}

View file

@ -0,0 +1,7 @@
FROM golang:alpine
RUN apk add --update --no-cache git bash protobuf-dev
RUN go get -u github.com/grpc-ecosystem/grpc-gateway/protoc-gen-grpc-gateway
RUN go get -u github.com/grpc-ecosystem/grpc-gateway/protoc-gen-swagger
RUN go get -u github.com/golang/protobuf/protoc-gen-go

View file

@ -0,0 +1,917 @@
// Code generated by protoc-gen-go. DO NOT EDIT.
// source: api/v3/clairpb/clair.proto
/*
Package clairpb is a generated protocol buffer package.
It is generated from these files:
api/v3/clairpb/clair.proto
It has these top-level messages:
Vulnerability
ClairStatus
Feature
Ancestry
Layer
Notification
IndexedAncestryName
PagedVulnerableAncestries
PostAncestryRequest
PostAncestryResponse
GetAncestryRequest
GetAncestryResponse
GetNotificationRequest
GetNotificationResponse
MarkNotificationAsReadRequest
*/
package clairpb
import proto "github.com/golang/protobuf/proto"
import fmt "fmt"
import math "math"
import _ "google.golang.org/genproto/googleapis/api/annotations"
import google_protobuf1 "github.com/golang/protobuf/ptypes/empty"
import google_protobuf2 "github.com/golang/protobuf/ptypes/timestamp"
import (
context "golang.org/x/net/context"
grpc "google.golang.org/grpc"
)
// Reference imports to suppress errors if they are not otherwise used.
var _ = proto.Marshal
var _ = fmt.Errorf
var _ = math.Inf
// This is a compile-time assertion to ensure that this generated file
// is compatible with the proto package it is being compiled against.
// A compilation error at this line likely means your copy of the
// proto package needs to be updated.
const _ = proto.ProtoPackageIsVersion2 // please upgrade the proto package
type Vulnerability struct {
Name string `protobuf:"bytes,1,opt,name=name" json:"name,omitempty"`
NamespaceName string `protobuf:"bytes,2,opt,name=namespace_name,json=namespaceName" json:"namespace_name,omitempty"`
Description string `protobuf:"bytes,3,opt,name=description" json:"description,omitempty"`
Link string `protobuf:"bytes,4,opt,name=link" json:"link,omitempty"`
Severity string `protobuf:"bytes,5,opt,name=severity" json:"severity,omitempty"`
Metadata string `protobuf:"bytes,6,opt,name=metadata" json:"metadata,omitempty"`
// fixed_by exists when vulnerability is under feature.
FixedBy string `protobuf:"bytes,7,opt,name=fixed_by,json=fixedBy" json:"fixed_by,omitempty"`
// affected_versions exists when vulnerability is under notification.
AffectedVersions []*Feature `protobuf:"bytes,8,rep,name=affected_versions,json=affectedVersions" json:"affected_versions,omitempty"`
}
func (m *Vulnerability) Reset() { *m = Vulnerability{} }
func (m *Vulnerability) String() string { return proto.CompactTextString(m) }
func (*Vulnerability) ProtoMessage() {}
func (*Vulnerability) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{0} }
func (m *Vulnerability) GetName() string {
if m != nil {
return m.Name
}
return ""
}
func (m *Vulnerability) GetNamespaceName() string {
if m != nil {
return m.NamespaceName
}
return ""
}
func (m *Vulnerability) GetDescription() string {
if m != nil {
return m.Description
}
return ""
}
func (m *Vulnerability) GetLink() string {
if m != nil {
return m.Link
}
return ""
}
func (m *Vulnerability) GetSeverity() string {
if m != nil {
return m.Severity
}
return ""
}
func (m *Vulnerability) GetMetadata() string {
if m != nil {
return m.Metadata
}
return ""
}
func (m *Vulnerability) GetFixedBy() string {
if m != nil {
return m.FixedBy
}
return ""
}
func (m *Vulnerability) GetAffectedVersions() []*Feature {
if m != nil {
return m.AffectedVersions
}
return nil
}
type ClairStatus struct {
// listers and detectors are processors implemented in this Clair and used to
// scan ancestries
Listers []string `protobuf:"bytes,1,rep,name=listers" json:"listers,omitempty"`
Detectors []string `protobuf:"bytes,2,rep,name=detectors" json:"detectors,omitempty"`
LastUpdateTime *google_protobuf2.Timestamp `protobuf:"bytes,3,opt,name=last_update_time,json=lastUpdateTime" json:"last_update_time,omitempty"`
}
func (m *ClairStatus) Reset() { *m = ClairStatus{} }
func (m *ClairStatus) String() string { return proto.CompactTextString(m) }
func (*ClairStatus) ProtoMessage() {}
func (*ClairStatus) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{1} }
func (m *ClairStatus) GetListers() []string {
if m != nil {
return m.Listers
}
return nil
}
func (m *ClairStatus) GetDetectors() []string {
if m != nil {
return m.Detectors
}
return nil
}
func (m *ClairStatus) GetLastUpdateTime() *google_protobuf2.Timestamp {
if m != nil {
return m.LastUpdateTime
}
return nil
}
type Feature struct {
Name string `protobuf:"bytes,1,opt,name=name" json:"name,omitempty"`
NamespaceName string `protobuf:"bytes,2,opt,name=namespace_name,json=namespaceName" json:"namespace_name,omitempty"`
Version string `protobuf:"bytes,3,opt,name=version" json:"version,omitempty"`
// version_format is the format used by installer package manager to store
// package versions.
VersionFormat string `protobuf:"bytes,4,opt,name=version_format,json=versionFormat" json:"version_format,omitempty"`
Vulnerabilities []*Vulnerability `protobuf:"bytes,5,rep,name=vulnerabilities" json:"vulnerabilities,omitempty"`
}
func (m *Feature) Reset() { *m = Feature{} }
func (m *Feature) String() string { return proto.CompactTextString(m) }
func (*Feature) ProtoMessage() {}
func (*Feature) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{2} }
func (m *Feature) GetName() string {
if m != nil {
return m.Name
}
return ""
}
func (m *Feature) GetNamespaceName() string {
if m != nil {
return m.NamespaceName
}
return ""
}
func (m *Feature) GetVersion() string {
if m != nil {
return m.Version
}
return ""
}
func (m *Feature) GetVersionFormat() string {
if m != nil {
return m.VersionFormat
}
return ""
}
func (m *Feature) GetVulnerabilities() []*Vulnerability {
if m != nil {
return m.Vulnerabilities
}
return nil
}
type Ancestry struct {
Name string `protobuf:"bytes,1,opt,name=name" json:"name,omitempty"`
Features []*Feature `protobuf:"bytes,2,rep,name=features" json:"features,omitempty"`
Layers []*Layer `protobuf:"bytes,3,rep,name=layers" json:"layers,omitempty"`
// scanned_listers and scanned_detectors are used to scan this ancestry, it
// may be different from listers and detectors in ClairStatus since the
// ancestry could be scanned by previous version of Clair.
ScannedListers []string `protobuf:"bytes,4,rep,name=scanned_listers,json=scannedListers" json:"scanned_listers,omitempty"`
ScannedDetectors []string `protobuf:"bytes,5,rep,name=scanned_detectors,json=scannedDetectors" json:"scanned_detectors,omitempty"`
}
func (m *Ancestry) Reset() { *m = Ancestry{} }
func (m *Ancestry) String() string { return proto.CompactTextString(m) }
func (*Ancestry) ProtoMessage() {}
func (*Ancestry) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{3} }
func (m *Ancestry) GetName() string {
if m != nil {
return m.Name
}
return ""
}
func (m *Ancestry) GetFeatures() []*Feature {
if m != nil {
return m.Features
}
return nil
}
func (m *Ancestry) GetLayers() []*Layer {
if m != nil {
return m.Layers
}
return nil
}
func (m *Ancestry) GetScannedListers() []string {
if m != nil {
return m.ScannedListers
}
return nil
}
func (m *Ancestry) GetScannedDetectors() []string {
if m != nil {
return m.ScannedDetectors
}
return nil
}
type Layer struct {
Hash string `protobuf:"bytes,1,opt,name=hash" json:"hash,omitempty"`
}
func (m *Layer) Reset() { *m = Layer{} }
func (m *Layer) String() string { return proto.CompactTextString(m) }
func (*Layer) ProtoMessage() {}
func (*Layer) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{4} }
func (m *Layer) GetHash() string {
if m != nil {
return m.Hash
}
return ""
}
type Notification struct {
Name string `protobuf:"bytes,1,opt,name=name" json:"name,omitempty"`
Created string `protobuf:"bytes,2,opt,name=created" json:"created,omitempty"`
Notified string `protobuf:"bytes,3,opt,name=notified" json:"notified,omitempty"`
Deleted string `protobuf:"bytes,4,opt,name=deleted" json:"deleted,omitempty"`
Old *PagedVulnerableAncestries `protobuf:"bytes,5,opt,name=old" json:"old,omitempty"`
New *PagedVulnerableAncestries `protobuf:"bytes,6,opt,name=new" json:"new,omitempty"`
}
func (m *Notification) Reset() { *m = Notification{} }
func (m *Notification) String() string { return proto.CompactTextString(m) }
func (*Notification) ProtoMessage() {}
func (*Notification) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{5} }
func (m *Notification) GetName() string {
if m != nil {
return m.Name
}
return ""
}
func (m *Notification) GetCreated() string {
if m != nil {
return m.Created
}
return ""
}
func (m *Notification) GetNotified() string {
if m != nil {
return m.Notified
}
return ""
}
func (m *Notification) GetDeleted() string {
if m != nil {
return m.Deleted
}
return ""
}
func (m *Notification) GetOld() *PagedVulnerableAncestries {
if m != nil {
return m.Old
}
return nil
}
func (m *Notification) GetNew() *PagedVulnerableAncestries {
if m != nil {
return m.New
}
return nil
}
type IndexedAncestryName struct {
// index is unique to name in all streams simultaneously streamed, increasing
// and larger than all indexes in previous page in same stream.
Index int32 `protobuf:"varint,1,opt,name=index" json:"index,omitempty"`
Name string `protobuf:"bytes,2,opt,name=name" json:"name,omitempty"`
}
func (m *IndexedAncestryName) Reset() { *m = IndexedAncestryName{} }
func (m *IndexedAncestryName) String() string { return proto.CompactTextString(m) }
func (*IndexedAncestryName) ProtoMessage() {}
func (*IndexedAncestryName) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{6} }
func (m *IndexedAncestryName) GetIndex() int32 {
if m != nil {
return m.Index
}
return 0
}
func (m *IndexedAncestryName) GetName() string {
if m != nil {
return m.Name
}
return ""
}
type PagedVulnerableAncestries struct {
CurrentPage string `protobuf:"bytes,1,opt,name=current_page,json=currentPage" json:"current_page,omitempty"`
// if next_page is empty, it signals the end of all pages.
NextPage string `protobuf:"bytes,2,opt,name=next_page,json=nextPage" json:"next_page,omitempty"`
Limit int32 `protobuf:"varint,3,opt,name=limit" json:"limit,omitempty"`
Vulnerability *Vulnerability `protobuf:"bytes,4,opt,name=vulnerability" json:"vulnerability,omitempty"`
Ancestries []*IndexedAncestryName `protobuf:"bytes,5,rep,name=ancestries" json:"ancestries,omitempty"`
}
func (m *PagedVulnerableAncestries) Reset() { *m = PagedVulnerableAncestries{} }
func (m *PagedVulnerableAncestries) String() string { return proto.CompactTextString(m) }
func (*PagedVulnerableAncestries) ProtoMessage() {}
func (*PagedVulnerableAncestries) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{7} }
func (m *PagedVulnerableAncestries) GetCurrentPage() string {
if m != nil {
return m.CurrentPage
}
return ""
}
func (m *PagedVulnerableAncestries) GetNextPage() string {
if m != nil {
return m.NextPage
}
return ""
}
func (m *PagedVulnerableAncestries) GetLimit() int32 {
if m != nil {
return m.Limit
}
return 0
}
func (m *PagedVulnerableAncestries) GetVulnerability() *Vulnerability {
if m != nil {
return m.Vulnerability
}
return nil
}
func (m *PagedVulnerableAncestries) GetAncestries() []*IndexedAncestryName {
if m != nil {
return m.Ancestries
}
return nil
}
type PostAncestryRequest struct {
AncestryName string `protobuf:"bytes,1,opt,name=ancestry_name,json=ancestryName" json:"ancestry_name,omitempty"`
Format string `protobuf:"bytes,2,opt,name=format" json:"format,omitempty"`
Layers []*PostAncestryRequest_PostLayer `protobuf:"bytes,3,rep,name=layers" json:"layers,omitempty"`
}
func (m *PostAncestryRequest) Reset() { *m = PostAncestryRequest{} }
func (m *PostAncestryRequest) String() string { return proto.CompactTextString(m) }
func (*PostAncestryRequest) ProtoMessage() {}
func (*PostAncestryRequest) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{8} }
func (m *PostAncestryRequest) GetAncestryName() string {
if m != nil {
return m.AncestryName
}
return ""
}
func (m *PostAncestryRequest) GetFormat() string {
if m != nil {
return m.Format
}
return ""
}
func (m *PostAncestryRequest) GetLayers() []*PostAncestryRequest_PostLayer {
if m != nil {
return m.Layers
}
return nil
}
type PostAncestryRequest_PostLayer struct {
Hash string `protobuf:"bytes,1,opt,name=hash" json:"hash,omitempty"`
Path string `protobuf:"bytes,2,opt,name=path" json:"path,omitempty"`
Headers map[string]string `protobuf:"bytes,3,rep,name=headers" json:"headers,omitempty" protobuf_key:"bytes,1,opt,name=key" protobuf_val:"bytes,2,opt,name=value"`
}
func (m *PostAncestryRequest_PostLayer) Reset() { *m = PostAncestryRequest_PostLayer{} }
func (m *PostAncestryRequest_PostLayer) String() string { return proto.CompactTextString(m) }
func (*PostAncestryRequest_PostLayer) ProtoMessage() {}
func (*PostAncestryRequest_PostLayer) Descriptor() ([]byte, []int) {
return fileDescriptor0, []int{8, 0}
}
func (m *PostAncestryRequest_PostLayer) GetHash() string {
if m != nil {
return m.Hash
}
return ""
}
func (m *PostAncestryRequest_PostLayer) GetPath() string {
if m != nil {
return m.Path
}
return ""
}
func (m *PostAncestryRequest_PostLayer) GetHeaders() map[string]string {
if m != nil {
return m.Headers
}
return nil
}
type PostAncestryResponse struct {
Status *ClairStatus `protobuf:"bytes,1,opt,name=status" json:"status,omitempty"`
}
func (m *PostAncestryResponse) Reset() { *m = PostAncestryResponse{} }
func (m *PostAncestryResponse) String() string { return proto.CompactTextString(m) }
func (*PostAncestryResponse) ProtoMessage() {}
func (*PostAncestryResponse) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{9} }
func (m *PostAncestryResponse) GetStatus() *ClairStatus {
if m != nil {
return m.Status
}
return nil
}
type GetAncestryRequest struct {
AncestryName string `protobuf:"bytes,1,opt,name=ancestry_name,json=ancestryName" json:"ancestry_name,omitempty"`
WithVulnerabilities bool `protobuf:"varint,2,opt,name=with_vulnerabilities,json=withVulnerabilities" json:"with_vulnerabilities,omitempty"`
WithFeatures bool `protobuf:"varint,3,opt,name=with_features,json=withFeatures" json:"with_features,omitempty"`
}
func (m *GetAncestryRequest) Reset() { *m = GetAncestryRequest{} }
func (m *GetAncestryRequest) String() string { return proto.CompactTextString(m) }
func (*GetAncestryRequest) ProtoMessage() {}
func (*GetAncestryRequest) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{10} }
func (m *GetAncestryRequest) GetAncestryName() string {
if m != nil {
return m.AncestryName
}
return ""
}
func (m *GetAncestryRequest) GetWithVulnerabilities() bool {
if m != nil {
return m.WithVulnerabilities
}
return false
}
func (m *GetAncestryRequest) GetWithFeatures() bool {
if m != nil {
return m.WithFeatures
}
return false
}
type GetAncestryResponse struct {
Ancestry *Ancestry `protobuf:"bytes,1,opt,name=ancestry" json:"ancestry,omitempty"`
Status *ClairStatus `protobuf:"bytes,2,opt,name=status" json:"status,omitempty"`
}
func (m *GetAncestryResponse) Reset() { *m = GetAncestryResponse{} }
func (m *GetAncestryResponse) String() string { return proto.CompactTextString(m) }
func (*GetAncestryResponse) ProtoMessage() {}
func (*GetAncestryResponse) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{11} }
func (m *GetAncestryResponse) GetAncestry() *Ancestry {
if m != nil {
return m.Ancestry
}
return nil
}
func (m *GetAncestryResponse) GetStatus() *ClairStatus {
if m != nil {
return m.Status
}
return nil
}
type GetNotificationRequest struct {
// if the vulnerability_page is empty, it implies the first page.
OldVulnerabilityPage string `protobuf:"bytes,1,opt,name=old_vulnerability_page,json=oldVulnerabilityPage" json:"old_vulnerability_page,omitempty"`
NewVulnerabilityPage string `protobuf:"bytes,2,opt,name=new_vulnerability_page,json=newVulnerabilityPage" json:"new_vulnerability_page,omitempty"`
Limit int32 `protobuf:"varint,3,opt,name=limit" json:"limit,omitempty"`
Name string `protobuf:"bytes,4,opt,name=name" json:"name,omitempty"`
}
func (m *GetNotificationRequest) Reset() { *m = GetNotificationRequest{} }
func (m *GetNotificationRequest) String() string { return proto.CompactTextString(m) }
func (*GetNotificationRequest) ProtoMessage() {}
func (*GetNotificationRequest) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{12} }
func (m *GetNotificationRequest) GetOldVulnerabilityPage() string {
if m != nil {
return m.OldVulnerabilityPage
}
return ""
}
func (m *GetNotificationRequest) GetNewVulnerabilityPage() string {
if m != nil {
return m.NewVulnerabilityPage
}
return ""
}
func (m *GetNotificationRequest) GetLimit() int32 {
if m != nil {
return m.Limit
}
return 0
}
func (m *GetNotificationRequest) GetName() string {
if m != nil {
return m.Name
}
return ""
}
type GetNotificationResponse struct {
Notification *Notification `protobuf:"bytes,1,opt,name=notification" json:"notification,omitempty"`
}
func (m *GetNotificationResponse) Reset() { *m = GetNotificationResponse{} }
func (m *GetNotificationResponse) String() string { return proto.CompactTextString(m) }
func (*GetNotificationResponse) ProtoMessage() {}
func (*GetNotificationResponse) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{13} }
func (m *GetNotificationResponse) GetNotification() *Notification {
if m != nil {
return m.Notification
}
return nil
}
type MarkNotificationAsReadRequest struct {
Name string `protobuf:"bytes,1,opt,name=name" json:"name,omitempty"`
}
func (m *MarkNotificationAsReadRequest) Reset() { *m = MarkNotificationAsReadRequest{} }
func (m *MarkNotificationAsReadRequest) String() string { return proto.CompactTextString(m) }
func (*MarkNotificationAsReadRequest) ProtoMessage() {}
func (*MarkNotificationAsReadRequest) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{14} }
func (m *MarkNotificationAsReadRequest) GetName() string {
if m != nil {
return m.Name
}
return ""
}
func init() {
proto.RegisterType((*Vulnerability)(nil), "clairpb.Vulnerability")
proto.RegisterType((*ClairStatus)(nil), "clairpb.ClairStatus")
proto.RegisterType((*Feature)(nil), "clairpb.Feature")
proto.RegisterType((*Ancestry)(nil), "clairpb.Ancestry")
proto.RegisterType((*Layer)(nil), "clairpb.Layer")
proto.RegisterType((*Notification)(nil), "clairpb.Notification")
proto.RegisterType((*IndexedAncestryName)(nil), "clairpb.IndexedAncestryName")
proto.RegisterType((*PagedVulnerableAncestries)(nil), "clairpb.PagedVulnerableAncestries")
proto.RegisterType((*PostAncestryRequest)(nil), "clairpb.PostAncestryRequest")
proto.RegisterType((*PostAncestryRequest_PostLayer)(nil), "clairpb.PostAncestryRequest.PostLayer")
proto.RegisterType((*PostAncestryResponse)(nil), "clairpb.PostAncestryResponse")
proto.RegisterType((*GetAncestryRequest)(nil), "clairpb.GetAncestryRequest")
proto.RegisterType((*GetAncestryResponse)(nil), "clairpb.GetAncestryResponse")
proto.RegisterType((*GetNotificationRequest)(nil), "clairpb.GetNotificationRequest")
proto.RegisterType((*GetNotificationResponse)(nil), "clairpb.GetNotificationResponse")
proto.RegisterType((*MarkNotificationAsReadRequest)(nil), "clairpb.MarkNotificationAsReadRequest")
}
// Reference imports to suppress errors if they are not otherwise used.
var _ context.Context
var _ grpc.ClientConn
// This is a compile-time assertion to ensure that this generated file
// is compatible with the grpc package it is being compiled against.
const _ = grpc.SupportPackageIsVersion4
// Client API for AncestryService service
type AncestryServiceClient interface {
PostAncestry(ctx context.Context, in *PostAncestryRequest, opts ...grpc.CallOption) (*PostAncestryResponse, error)
GetAncestry(ctx context.Context, in *GetAncestryRequest, opts ...grpc.CallOption) (*GetAncestryResponse, error)
}
type ancestryServiceClient struct {
cc *grpc.ClientConn
}
func NewAncestryServiceClient(cc *grpc.ClientConn) AncestryServiceClient {
return &ancestryServiceClient{cc}
}
func (c *ancestryServiceClient) PostAncestry(ctx context.Context, in *PostAncestryRequest, opts ...grpc.CallOption) (*PostAncestryResponse, error) {
out := new(PostAncestryResponse)
err := grpc.Invoke(ctx, "/clairpb.AncestryService/PostAncestry", in, out, c.cc, opts...)
if err != nil {
return nil, err
}
return out, nil
}
func (c *ancestryServiceClient) GetAncestry(ctx context.Context, in *GetAncestryRequest, opts ...grpc.CallOption) (*GetAncestryResponse, error) {
out := new(GetAncestryResponse)
err := grpc.Invoke(ctx, "/clairpb.AncestryService/GetAncestry", in, out, c.cc, opts...)
if err != nil {
return nil, err
}
return out, nil
}
// Server API for AncestryService service
type AncestryServiceServer interface {
PostAncestry(context.Context, *PostAncestryRequest) (*PostAncestryResponse, error)
GetAncestry(context.Context, *GetAncestryRequest) (*GetAncestryResponse, error)
}
func RegisterAncestryServiceServer(s *grpc.Server, srv AncestryServiceServer) {
s.RegisterService(&_AncestryService_serviceDesc, srv)
}
func _AncestryService_PostAncestry_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
in := new(PostAncestryRequest)
if err := dec(in); err != nil {
return nil, err
}
if interceptor == nil {
return srv.(AncestryServiceServer).PostAncestry(ctx, in)
}
info := &grpc.UnaryServerInfo{
Server: srv,
FullMethod: "/clairpb.AncestryService/PostAncestry",
}
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
return srv.(AncestryServiceServer).PostAncestry(ctx, req.(*PostAncestryRequest))
}
return interceptor(ctx, in, info, handler)
}
func _AncestryService_GetAncestry_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
in := new(GetAncestryRequest)
if err := dec(in); err != nil {
return nil, err
}
if interceptor == nil {
return srv.(AncestryServiceServer).GetAncestry(ctx, in)
}
info := &grpc.UnaryServerInfo{
Server: srv,
FullMethod: "/clairpb.AncestryService/GetAncestry",
}
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
return srv.(AncestryServiceServer).GetAncestry(ctx, req.(*GetAncestryRequest))
}
return interceptor(ctx, in, info, handler)
}
var _AncestryService_serviceDesc = grpc.ServiceDesc{
ServiceName: "clairpb.AncestryService",
HandlerType: (*AncestryServiceServer)(nil),
Methods: []grpc.MethodDesc{
{
MethodName: "PostAncestry",
Handler: _AncestryService_PostAncestry_Handler,
},
{
MethodName: "GetAncestry",
Handler: _AncestryService_GetAncestry_Handler,
},
},
Streams: []grpc.StreamDesc{},
Metadata: "api/v3/clairpb/clair.proto",
}
// Client API for NotificationService service
type NotificationServiceClient interface {
GetNotification(ctx context.Context, in *GetNotificationRequest, opts ...grpc.CallOption) (*GetNotificationResponse, error)
MarkNotificationAsRead(ctx context.Context, in *MarkNotificationAsReadRequest, opts ...grpc.CallOption) (*google_protobuf1.Empty, error)
}
type notificationServiceClient struct {
cc *grpc.ClientConn
}
func NewNotificationServiceClient(cc *grpc.ClientConn) NotificationServiceClient {
return &notificationServiceClient{cc}
}
func (c *notificationServiceClient) GetNotification(ctx context.Context, in *GetNotificationRequest, opts ...grpc.CallOption) (*GetNotificationResponse, error) {
out := new(GetNotificationResponse)
err := grpc.Invoke(ctx, "/clairpb.NotificationService/GetNotification", in, out, c.cc, opts...)
if err != nil {
return nil, err
}
return out, nil
}
func (c *notificationServiceClient) MarkNotificationAsRead(ctx context.Context, in *MarkNotificationAsReadRequest, opts ...grpc.CallOption) (*google_protobuf1.Empty, error) {
out := new(google_protobuf1.Empty)
err := grpc.Invoke(ctx, "/clairpb.NotificationService/MarkNotificationAsRead", in, out, c.cc, opts...)
if err != nil {
return nil, err
}
return out, nil
}
// Server API for NotificationService service
type NotificationServiceServer interface {
GetNotification(context.Context, *GetNotificationRequest) (*GetNotificationResponse, error)
MarkNotificationAsRead(context.Context, *MarkNotificationAsReadRequest) (*google_protobuf1.Empty, error)
}
func RegisterNotificationServiceServer(s *grpc.Server, srv NotificationServiceServer) {
s.RegisterService(&_NotificationService_serviceDesc, srv)
}
func _NotificationService_GetNotification_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
in := new(GetNotificationRequest)
if err := dec(in); err != nil {
return nil, err
}
if interceptor == nil {
return srv.(NotificationServiceServer).GetNotification(ctx, in)
}
info := &grpc.UnaryServerInfo{
Server: srv,
FullMethod: "/clairpb.NotificationService/GetNotification",
}
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
return srv.(NotificationServiceServer).GetNotification(ctx, req.(*GetNotificationRequest))
}
return interceptor(ctx, in, info, handler)
}
func _NotificationService_MarkNotificationAsRead_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
in := new(MarkNotificationAsReadRequest)
if err := dec(in); err != nil {
return nil, err
}
if interceptor == nil {
return srv.(NotificationServiceServer).MarkNotificationAsRead(ctx, in)
}
info := &grpc.UnaryServerInfo{
Server: srv,
FullMethod: "/clairpb.NotificationService/MarkNotificationAsRead",
}
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
return srv.(NotificationServiceServer).MarkNotificationAsRead(ctx, req.(*MarkNotificationAsReadRequest))
}
return interceptor(ctx, in, info, handler)
}
var _NotificationService_serviceDesc = grpc.ServiceDesc{
ServiceName: "clairpb.NotificationService",
HandlerType: (*NotificationServiceServer)(nil),
Methods: []grpc.MethodDesc{
{
MethodName: "GetNotification",
Handler: _NotificationService_GetNotification_Handler,
},
{
MethodName: "MarkNotificationAsRead",
Handler: _NotificationService_MarkNotificationAsRead_Handler,
},
},
Streams: []grpc.StreamDesc{},
Metadata: "api/v3/clairpb/clair.proto",
}
func init() { proto.RegisterFile("api/v3/clairpb/clair.proto", fileDescriptor0) }
var fileDescriptor0 = []byte{
// 1162 bytes of a gzipped FileDescriptorProto
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xa4, 0x56, 0x4d, 0x6f, 0xdb, 0x46,
0x13, 0x06, 0x25, 0xcb, 0x92, 0x46, 0xf2, 0xd7, 0x5a, 0x51, 0x68, 0xd9, 0x46, 0x1c, 0xbe, 0x78,
0xd3, 0x20, 0x6d, 0x25, 0x54, 0xf6, 0xa1, 0x35, 0xd2, 0x8f, 0xa4, 0x4e, 0xd2, 0x02, 0x49, 0x10,
0x30, 0xa9, 0x0f, 0xbd, 0x08, 0x6b, 0x72, 0x64, 0x13, 0xa6, 0x48, 0x96, 0xbb, 0x92, 0x2c, 0x04,
0xbd, 0xb4, 0xc7, 0x9e, 0xda, 0xfe, 0x8f, 0xfe, 0x84, 0x5e, 0x0b, 0xf4, 0x9a, 0x7b, 0x81, 0x02,
0xbd, 0xf6, 0x3f, 0x14, 0xbb, 0xdc, 0xa5, 0x48, 0x8b, 0x0e, 0x8c, 0xf6, 0x24, 0xce, 0xcc, 0x33,
0xbb, 0x33, 0xcf, 0x33, 0x3b, 0x10, 0x74, 0x68, 0xe4, 0xf5, 0x26, 0xfb, 0x3d, 0xc7, 0xa7, 0x5e,
0x1c, 0x9d, 0x24, 0xbf, 0xdd, 0x28, 0x0e, 0x79, 0x48, 0xaa, 0xca, 0xd9, 0xd9, 0x39, 0x0d, 0xc3,
0x53, 0x1f, 0x7b, 0x02, 0x4b, 0x83, 0x20, 0xe4, 0x94, 0x7b, 0x61, 0xc0, 0x12, 0x58, 0x67, 0x5b,
0x45, 0xa5, 0x75, 0x32, 0x1e, 0xf6, 0x70, 0x14, 0xf1, 0x99, 0x0a, 0xde, 0xba, 0x1c, 0xe4, 0xde,
0x08, 0x19, 0xa7, 0xa3, 0x28, 0x01, 0x58, 0x3f, 0x95, 0x60, 0xe5, 0x78, 0xec, 0x07, 0x18, 0xd3,
0x13, 0xcf, 0xf7, 0xf8, 0x8c, 0x10, 0x58, 0x0a, 0xe8, 0x08, 0x4d, 0x63, 0xcf, 0xb8, 0x5b, 0xb7,
0xe5, 0x37, 0xf9, 0x3f, 0xac, 0x8a, 0x5f, 0x16, 0x51, 0x07, 0x07, 0x32, 0x5a, 0x92, 0xd1, 0x95,
0xd4, 0xfb, 0x5c, 0xc0, 0xf6, 0xa0, 0xe1, 0x22, 0x73, 0x62, 0x2f, 0x12, 0x05, 0x9a, 0x65, 0x89,
0xc9, 0xba, 0xc4, 0xe1, 0xbe, 0x17, 0x9c, 0x9b, 0x4b, 0xc9, 0xe1, 0xe2, 0x9b, 0x74, 0xa0, 0xc6,
0x70, 0x82, 0xb1, 0xc7, 0x67, 0x66, 0x45, 0xfa, 0x53, 0x5b, 0xc4, 0x46, 0xc8, 0xa9, 0x4b, 0x39,
0x35, 0x97, 0x93, 0x98, 0xb6, 0xc9, 0x16, 0xd4, 0x86, 0xde, 0x05, 0xba, 0x83, 0x93, 0x99, 0x59,
0x95, 0xb1, 0xaa, 0xb4, 0x1f, 0xce, 0xc8, 0xc7, 0xb0, 0x41, 0x87, 0x43, 0x74, 0x38, 0xba, 0x83,
0x09, 0xc6, 0x4c, 0xd0, 0x65, 0xd6, 0xf6, 0xca, 0x77, 0x1b, 0xfd, 0xf5, 0xae, 0xa2, 0xb5, 0xfb,
0x18, 0x29, 0x1f, 0xc7, 0x68, 0xaf, 0x6b, 0xe8, 0xb1, 0x42, 0x5a, 0x3f, 0x18, 0xd0, 0xf8, 0x5c,
0xa0, 0x5e, 0x72, 0xca, 0xc7, 0x8c, 0x98, 0x50, 0xf5, 0x3d, 0xc6, 0x31, 0x66, 0xa6, 0xb1, 0x57,
0x16, 0x17, 0x29, 0x93, 0xec, 0x40, 0xdd, 0x45, 0x8e, 0x0e, 0x0f, 0x63, 0x66, 0x96, 0x64, 0x6c,
0xee, 0x20, 0x47, 0xb0, 0xee, 0x53, 0xc6, 0x07, 0xe3, 0xc8, 0xa5, 0x1c, 0x07, 0x82, 0x7b, 0x49,
0x4a, 0xa3, 0xdf, 0xe9, 0x26, 0xc2, 0x74, 0xb5, 0x30, 0xdd, 0x57, 0x5a, 0x18, 0x7b, 0x55, 0xe4,
0x7c, 0x25, 0x53, 0x84, 0xd3, 0xfa, 0xcd, 0x80, 0xaa, 0xaa, 0xf5, 0xbf, 0x88, 0x63, 0x42, 0x55,
0x51, 0xa1, 0x84, 0xd1, 0xa6, 0x38, 0x40, 0x7d, 0x0e, 0x86, 0x61, 0x3c, 0xa2, 0x5c, 0xc9, 0xb3,
0xa2, 0xbc, 0x8f, 0xa5, 0x93, 0x7c, 0x06, 0x6b, 0x93, 0xcc, 0xa4, 0x78, 0xc8, 0xcc, 0x8a, 0xa4,
0xb4, 0x9d, 0x52, 0x9a, 0x9b, 0x24, 0xfb, 0x32, 0xdc, 0xfa, 0xdd, 0x80, 0xda, 0x83, 0xc0, 0x41,
0xc6, 0xe3, 0xe2, 0x39, 0x7b, 0x0f, 0x6a, 0xc3, 0xa4, 0xd3, 0x84, 0xcd, 0x22, 0xb9, 0x52, 0x04,
0xb9, 0x03, 0xcb, 0x3e, 0x9d, 0x09, 0x55, 0xca, 0x12, 0xbb, 0x9a, 0x62, 0x9f, 0x0a, 0xb7, 0xad,
0xa2, 0xe4, 0x1d, 0x58, 0x63, 0x0e, 0x0d, 0x02, 0x74, 0x07, 0x5a, 0xc6, 0x25, 0x29, 0xd5, 0xaa,
0x72, 0x3f, 0x55, 0x6a, 0xbe, 0x0b, 0x1b, 0x1a, 0x38, 0x57, 0xb5, 0x22, 0xa1, 0xeb, 0x2a, 0x70,
0xa4, 0xfd, 0xd6, 0x36, 0x54, 0xe4, 0x35, 0xa2, 0x91, 0x33, 0xca, 0xce, 0x74, 0x23, 0xe2, 0xdb,
0xfa, 0xc3, 0x80, 0xe6, 0xf3, 0x90, 0x7b, 0x43, 0xcf, 0xa1, 0x7a, 0xf0, 0x17, 0xba, 0x35, 0xa1,
0xea, 0xc4, 0x48, 0x39, 0xba, 0x4a, 0x31, 0x6d, 0x8a, 0xb1, 0x0f, 0x64, 0x36, 0xba, 0x4a, 0xac,
0xd4, 0x16, 0x59, 0x2e, 0xfa, 0x28, 0xb2, 0x12, 0x99, 0xb4, 0x49, 0x0e, 0xa0, 0x1c, 0xfa, 0xae,
0x7c, 0x43, 0x8d, 0xbe, 0x95, 0x92, 0xf1, 0x82, 0x9e, 0xa2, 0xab, 0x95, 0xf1, 0x51, 0x09, 0xe0,
0x21, 0xb3, 0x05, 0x5c, 0x64, 0x05, 0x38, 0x95, 0xaf, 0xeb, 0x9a, 0x59, 0x01, 0x4e, 0xad, 0x4f,
0x61, 0xf3, 0xcb, 0xc0, 0xc5, 0x0b, 0x74, 0xb5, 0xa0, 0x72, 0xc8, 0x5a, 0x50, 0xf1, 0x84, 0x5b,
0xf6, 0x59, 0xb1, 0x13, 0x23, 0x6d, 0xbe, 0x34, 0x6f, 0xde, 0xfa, 0xdb, 0x80, 0xad, 0x2b, 0xef,
0x20, 0xb7, 0xa1, 0xe9, 0x8c, 0xe3, 0x18, 0x03, 0x3e, 0x88, 0xe8, 0xa9, 0xa6, 0xad, 0xa1, 0x7c,
0x22, 0x8f, 0x6c, 0x43, 0x3d, 0xc0, 0x0b, 0x15, 0x2f, 0x29, 0x92, 0xf0, 0x22, 0x09, 0xb6, 0xa0,
0xe2, 0x7b, 0x23, 0x8f, 0x4b, 0xf6, 0x2a, 0x76, 0x62, 0x90, 0xfb, 0xb0, 0x92, 0x1d, 0xc9, 0x99,
0x24, 0xf0, 0xea, 0xf9, 0xcd, 0x83, 0xc9, 0x7d, 0x00, 0x9a, 0x56, 0xa8, 0x46, 0x7f, 0x27, 0x4d,
0x2d, 0x60, 0xc3, 0xce, 0xe0, 0xad, 0x37, 0x25, 0xd8, 0x7c, 0x11, 0x32, 0xae, 0x01, 0x36, 0x7e,
0x33, 0x46, 0xc6, 0xc9, 0xff, 0x60, 0x45, 0xa1, 0x66, 0x83, 0xcc, 0x84, 0x34, 0x69, 0x96, 0xd6,
0x36, 0x2c, 0xab, 0x97, 0x99, 0x34, 0xaa, 0x2c, 0xf2, 0xc9, 0xa5, 0x17, 0x70, 0x67, 0x2e, 0xdf,
0xe2, 0x55, 0xd2, 0x97, 0x7b, 0x19, 0x9d, 0x5f, 0x0d, 0xa8, 0xa7, 0xde, 0xa2, 0x41, 0x16, 0xbe,
0x88, 0xf2, 0x33, 0x2d, 0x9d, 0xf8, 0x26, 0xcf, 0xa0, 0x7a, 0x86, 0xd4, 0x9d, 0x5f, 0xbb, 0x7f,
0xbd, 0x6b, 0xbb, 0x5f, 0x24, 0x59, 0x8f, 0x02, 0x11, 0xd5, 0x67, 0x74, 0x0e, 0xa1, 0x99, 0x0d,
0x90, 0x75, 0x28, 0x9f, 0xe3, 0x4c, 0x55, 0x21, 0x3e, 0x85, 0x9a, 0x13, 0xea, 0x8f, 0xb5, 0xcc,
0x89, 0x71, 0x58, 0xfa, 0xd0, 0xb0, 0x8e, 0xa0, 0x95, 0xbf, 0x92, 0x45, 0x61, 0xc0, 0xc4, 0x22,
0x59, 0x66, 0x72, 0x77, 0xcb, 0x63, 0x1a, 0xfd, 0x56, 0x5a, 0x61, 0x66, 0xaf, 0xdb, 0x0a, 0x63,
0xfd, 0x68, 0x00, 0x79, 0x82, 0xff, 0x4e, 0x9a, 0x0f, 0xa0, 0x35, 0xf5, 0xf8, 0xd9, 0xe0, 0xf2,
0x6a, 0x14, 0xa5, 0xd6, 0xec, 0x4d, 0x11, 0x3b, 0xce, 0x87, 0xc4, 0xb9, 0x32, 0x25, 0x5d, 0x75,
0x65, 0x89, 0x6d, 0x0a, 0xa7, 0xda, 0x72, 0xcc, 0x8a, 0x61, 0x33, 0x57, 0x92, 0x6a, 0xec, 0x7d,
0xa8, 0xe9, 0xeb, 0x55, 0x6b, 0x1b, 0x69, 0x6b, 0x29, 0x38, 0x85, 0x64, 0x78, 0x28, 0x5d, 0x83,
0x87, 0x5f, 0x0c, 0x68, 0x3f, 0x41, 0x9e, 0x5d, 0x5c, 0x9a, 0x8b, 0x03, 0x68, 0x87, 0xbe, 0x9b,
0xeb, 0x72, 0x96, 0x7d, 0x9a, 0xad, 0xd0, 0x77, 0x73, 0xaf, 0x47, 0x3e, 0xc3, 0x03, 0x68, 0x07,
0x38, 0x2d, 0xca, 0x4a, 0x94, 0x6c, 0x05, 0x38, 0x5d, 0xcc, 0x2a, 0x7e, 0xbc, 0x7a, 0x89, 0x2c,
0x65, 0x96, 0xc8, 0x2b, 0xb8, 0xb9, 0x50, 0xaf, 0x22, 0xea, 0x23, 0x68, 0x06, 0x19, 0xbf, 0x22,
0xeb, 0x46, 0xda, 0x7f, 0x2e, 0x29, 0x07, 0xb5, 0xf6, 0x61, 0xf7, 0x19, 0x8d, 0xcf, 0xb3, 0x88,
0x07, 0xcc, 0x46, 0xea, 0x6a, 0x32, 0x0a, 0x96, 0x79, 0xff, 0x4f, 0x03, 0xd6, 0xb4, 0x00, 0x2f,
0x31, 0x9e, 0x78, 0x0e, 0x12, 0x0a, 0xcd, 0xec, 0x74, 0x92, 0x9d, 0xb7, 0xbd, 0x93, 0xce, 0xee,
0x15, 0xd1, 0xa4, 0x21, 0xab, 0xf5, 0xdd, 0x9b, 0xbf, 0x7e, 0x2e, 0xad, 0x5a, 0xf5, 0x9e, 0x56,
0xf7, 0xd0, 0xb8, 0x47, 0xce, 0xa1, 0x91, 0x19, 0x13, 0xb2, 0x9d, 0x9e, 0xb1, 0x38, 0xcf, 0x9d,
0x9d, 0xe2, 0xa0, 0x3a, 0xff, 0xb6, 0x3c, 0x7f, 0x9b, 0x6c, 0xa5, 0xe7, 0xf7, 0x5e, 0xe7, 0xc6,
0xff, 0xdb, 0xfe, 0xf7, 0x25, 0xd8, 0xcc, 0xb2, 0xa2, 0xfb, 0x64, 0xb0, 0x76, 0x49, 0x06, 0x72,
0x2b, 0x7b, 0x57, 0xc1, 0x40, 0x75, 0xf6, 0xae, 0x06, 0xa8, 0x82, 0x76, 0x65, 0x41, 0x37, 0xc9,
0x8d, 0x5e, 0x56, 0x1d, 0xd6, 0x7b, 0x2d, 0x8b, 0x21, 0x53, 0x68, 0x17, 0xab, 0x44, 0xe6, 0x5b,
0xf0, 0xad, 0x32, 0x76, 0xda, 0x0b, 0x7f, 0xc2, 0x1e, 0x89, 0xbf, 0xce, 0xfa, 0xe2, 0x7b, 0xc5,
0x17, 0x3f, 0xac, 0x7f, 0xad, 0xff, 0x99, 0x9f, 0x2c, 0xcb, 0xcc, 0xfd, 0x7f, 0x02, 0x00, 0x00,
0xff, 0xff, 0x51, 0xb7, 0x75, 0x58, 0xc7, 0x0b, 0x00, 0x00,
}

View file

@ -0,0 +1,363 @@
// Code generated by protoc-gen-grpc-gateway. DO NOT EDIT.
// source: api/v3/clairpb/clair.proto
/*
Package clairpb is a reverse proxy.
It translates gRPC into RESTful JSON APIs.
*/
package clairpb
import (
"io"
"net/http"
"github.com/golang/protobuf/proto"
"github.com/grpc-ecosystem/grpc-gateway/runtime"
"github.com/grpc-ecosystem/grpc-gateway/utilities"
"golang.org/x/net/context"
"google.golang.org/grpc"
"google.golang.org/grpc/codes"
"google.golang.org/grpc/grpclog"
"google.golang.org/grpc/status"
)
var _ codes.Code
var _ io.Reader
var _ status.Status
var _ = runtime.String
var _ = utilities.NewDoubleArray
func request_AncestryService_PostAncestry_0(ctx context.Context, marshaler runtime.Marshaler, client AncestryServiceClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {
var protoReq PostAncestryRequest
var metadata runtime.ServerMetadata
if req.ContentLength > 0 {
if err := marshaler.NewDecoder(req.Body).Decode(&protoReq); err != nil {
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err)
}
}
msg, err := client.PostAncestry(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD))
return msg, metadata, err
}
var (
filter_AncestryService_GetAncestry_0 = &utilities.DoubleArray{Encoding: map[string]int{"ancestry_name": 0}, Base: []int{1, 1, 0}, Check: []int{0, 1, 2}}
)
func request_AncestryService_GetAncestry_0(ctx context.Context, marshaler runtime.Marshaler, client AncestryServiceClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {
var protoReq GetAncestryRequest
var metadata runtime.ServerMetadata
var (
val string
ok bool
err error
_ = err
)
val, ok = pathParams["ancestry_name"]
if !ok {
return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "ancestry_name")
}
protoReq.AncestryName, err = runtime.String(val)
if err != nil {
return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "ancestry_name", err)
}
if err := runtime.PopulateQueryParameters(&protoReq, req.URL.Query(), filter_AncestryService_GetAncestry_0); err != nil {
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err)
}
msg, err := client.GetAncestry(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD))
return msg, metadata, err
}
var (
filter_NotificationService_GetNotification_0 = &utilities.DoubleArray{Encoding: map[string]int{"name": 0}, Base: []int{1, 1, 0}, Check: []int{0, 1, 2}}
)
func request_NotificationService_GetNotification_0(ctx context.Context, marshaler runtime.Marshaler, client NotificationServiceClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {
var protoReq GetNotificationRequest
var metadata runtime.ServerMetadata
var (
val string
ok bool
err error
_ = err
)
val, ok = pathParams["name"]
if !ok {
return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "name")
}
protoReq.Name, err = runtime.String(val)
if err != nil {
return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "name", err)
}
if err := runtime.PopulateQueryParameters(&protoReq, req.URL.Query(), filter_NotificationService_GetNotification_0); err != nil {
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err)
}
msg, err := client.GetNotification(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD))
return msg, metadata, err
}
func request_NotificationService_MarkNotificationAsRead_0(ctx context.Context, marshaler runtime.Marshaler, client NotificationServiceClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {
var protoReq MarkNotificationAsReadRequest
var metadata runtime.ServerMetadata
var (
val string
ok bool
err error
_ = err
)
val, ok = pathParams["name"]
if !ok {
return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "name")
}
protoReq.Name, err = runtime.String(val)
if err != nil {
return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "name", err)
}
msg, err := client.MarkNotificationAsRead(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD))
return msg, metadata, err
}
// RegisterAncestryServiceHandlerFromEndpoint is same as RegisterAncestryServiceHandler but
// automatically dials to "endpoint" and closes the connection when "ctx" gets done.
func RegisterAncestryServiceHandlerFromEndpoint(ctx context.Context, mux *runtime.ServeMux, endpoint string, opts []grpc.DialOption) (err error) {
conn, err := grpc.Dial(endpoint, opts...)
if err != nil {
return err
}
defer func() {
if err != nil {
if cerr := conn.Close(); cerr != nil {
grpclog.Printf("Failed to close conn to %s: %v", endpoint, cerr)
}
return
}
go func() {
<-ctx.Done()
if cerr := conn.Close(); cerr != nil {
grpclog.Printf("Failed to close conn to %s: %v", endpoint, cerr)
}
}()
}()
return RegisterAncestryServiceHandler(ctx, mux, conn)
}
// RegisterAncestryServiceHandler registers the http handlers for service AncestryService to "mux".
// The handlers forward requests to the grpc endpoint over "conn".
func RegisterAncestryServiceHandler(ctx context.Context, mux *runtime.ServeMux, conn *grpc.ClientConn) error {
return RegisterAncestryServiceHandlerClient(ctx, mux, NewAncestryServiceClient(conn))
}
// RegisterAncestryServiceHandler registers the http handlers for service AncestryService to "mux".
// The handlers forward requests to the grpc endpoint over the given implementation of "AncestryServiceClient".
// Note: the gRPC framework executes interceptors within the gRPC handler. If the passed in "AncestryServiceClient"
// doesn't go through the normal gRPC flow (creating a gRPC client etc.) then it will be up to the passed in
// "AncestryServiceClient" to call the correct interceptors.
func RegisterAncestryServiceHandlerClient(ctx context.Context, mux *runtime.ServeMux, client AncestryServiceClient) error {
mux.Handle("POST", pattern_AncestryService_PostAncestry_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {
ctx, cancel := context.WithCancel(req.Context())
defer cancel()
if cn, ok := w.(http.CloseNotifier); ok {
go func(done <-chan struct{}, closed <-chan bool) {
select {
case <-done:
case <-closed:
cancel()
}
}(ctx.Done(), cn.CloseNotify())
}
inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req)
rctx, err := runtime.AnnotateContext(ctx, mux, req)
if err != nil {
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
return
}
resp, md, err := request_AncestryService_PostAncestry_0(rctx, inboundMarshaler, client, req, pathParams)
ctx = runtime.NewServerMetadataContext(ctx, md)
if err != nil {
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
return
}
forward_AncestryService_PostAncestry_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...)
})
mux.Handle("GET", pattern_AncestryService_GetAncestry_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {
ctx, cancel := context.WithCancel(req.Context())
defer cancel()
if cn, ok := w.(http.CloseNotifier); ok {
go func(done <-chan struct{}, closed <-chan bool) {
select {
case <-done:
case <-closed:
cancel()
}
}(ctx.Done(), cn.CloseNotify())
}
inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req)
rctx, err := runtime.AnnotateContext(ctx, mux, req)
if err != nil {
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
return
}
resp, md, err := request_AncestryService_GetAncestry_0(rctx, inboundMarshaler, client, req, pathParams)
ctx = runtime.NewServerMetadataContext(ctx, md)
if err != nil {
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
return
}
forward_AncestryService_GetAncestry_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...)
})
return nil
}
var (
pattern_AncestryService_PostAncestry_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0}, []string{"ancestry"}, ""))
pattern_AncestryService_GetAncestry_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 1, 0, 4, 1, 5, 1}, []string{"ancestry", "ancestry_name"}, ""))
)
var (
forward_AncestryService_PostAncestry_0 = runtime.ForwardResponseMessage
forward_AncestryService_GetAncestry_0 = runtime.ForwardResponseMessage
)
// RegisterNotificationServiceHandlerFromEndpoint is same as RegisterNotificationServiceHandler but
// automatically dials to "endpoint" and closes the connection when "ctx" gets done.
func RegisterNotificationServiceHandlerFromEndpoint(ctx context.Context, mux *runtime.ServeMux, endpoint string, opts []grpc.DialOption) (err error) {
conn, err := grpc.Dial(endpoint, opts...)
if err != nil {
return err
}
defer func() {
if err != nil {
if cerr := conn.Close(); cerr != nil {
grpclog.Printf("Failed to close conn to %s: %v", endpoint, cerr)
}
return
}
go func() {
<-ctx.Done()
if cerr := conn.Close(); cerr != nil {
grpclog.Printf("Failed to close conn to %s: %v", endpoint, cerr)
}
}()
}()
return RegisterNotificationServiceHandler(ctx, mux, conn)
}
// RegisterNotificationServiceHandler registers the http handlers for service NotificationService to "mux".
// The handlers forward requests to the grpc endpoint over "conn".
func RegisterNotificationServiceHandler(ctx context.Context, mux *runtime.ServeMux, conn *grpc.ClientConn) error {
return RegisterNotificationServiceHandlerClient(ctx, mux, NewNotificationServiceClient(conn))
}
// RegisterNotificationServiceHandler registers the http handlers for service NotificationService to "mux".
// The handlers forward requests to the grpc endpoint over the given implementation of "NotificationServiceClient".
// Note: the gRPC framework executes interceptors within the gRPC handler. If the passed in "NotificationServiceClient"
// doesn't go through the normal gRPC flow (creating a gRPC client etc.) then it will be up to the passed in
// "NotificationServiceClient" to call the correct interceptors.
func RegisterNotificationServiceHandlerClient(ctx context.Context, mux *runtime.ServeMux, client NotificationServiceClient) error {
mux.Handle("GET", pattern_NotificationService_GetNotification_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {
ctx, cancel := context.WithCancel(req.Context())
defer cancel()
if cn, ok := w.(http.CloseNotifier); ok {
go func(done <-chan struct{}, closed <-chan bool) {
select {
case <-done:
case <-closed:
cancel()
}
}(ctx.Done(), cn.CloseNotify())
}
inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req)
rctx, err := runtime.AnnotateContext(ctx, mux, req)
if err != nil {
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
return
}
resp, md, err := request_NotificationService_GetNotification_0(rctx, inboundMarshaler, client, req, pathParams)
ctx = runtime.NewServerMetadataContext(ctx, md)
if err != nil {
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
return
}
forward_NotificationService_GetNotification_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...)
})
mux.Handle("DELETE", pattern_NotificationService_MarkNotificationAsRead_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {
ctx, cancel := context.WithCancel(req.Context())
defer cancel()
if cn, ok := w.(http.CloseNotifier); ok {
go func(done <-chan struct{}, closed <-chan bool) {
select {
case <-done:
case <-closed:
cancel()
}
}(ctx.Done(), cn.CloseNotify())
}
inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req)
rctx, err := runtime.AnnotateContext(ctx, mux, req)
if err != nil {
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
return
}
resp, md, err := request_NotificationService_MarkNotificationAsRead_0(rctx, inboundMarshaler, client, req, pathParams)
ctx = runtime.NewServerMetadataContext(ctx, md)
if err != nil {
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
return
}
forward_NotificationService_MarkNotificationAsRead_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...)
})
return nil
}
var (
pattern_NotificationService_GetNotification_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 1, 0, 4, 1, 5, 1}, []string{"notifications", "name"}, ""))
pattern_NotificationService_MarkNotificationAsRead_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 1, 0, 4, 1, 5, 1}, []string{"notifications", "name"}, ""))
)
var (
forward_NotificationService_GetNotification_0 = runtime.ForwardResponseMessage
forward_NotificationService_MarkNotificationAsRead_0 = runtime.ForwardResponseMessage
)

View file

@ -0,0 +1,165 @@
// Copyright 2017 clair 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.
syntax = "proto3";
option go_package = "clairpb";
package clairpb;
import "google/api/annotations.proto";
import "google/protobuf/empty.proto";
import "google/protobuf/timestamp.proto";
message Vulnerability {
string name = 1;
string namespace_name = 2;
string description = 3;
string link = 4;
string severity = 5;
string metadata = 6;
// fixed_by exists when vulnerability is under feature.
string fixed_by = 7;
// affected_versions exists when vulnerability is under notification.
repeated Feature affected_versions = 8;
}
message ClairStatus {
// listers and detectors are processors implemented in this Clair and used to
// scan ancestries
repeated string listers = 1;
repeated string detectors = 2;
google.protobuf.Timestamp last_update_time = 3;
}
message Feature{
string name = 1;
string namespace_name = 2;
string version = 3;
// version_format is the format used by installer package manager to store
// package versions.
string version_format = 4;
repeated Vulnerability vulnerabilities = 5;
}
message Ancestry {
string name = 1;
repeated Feature features = 2;
repeated Layer layers = 3;
// scanned_listers and scanned_detectors are used to scan this ancestry, it
// may be different from listers and detectors in ClairStatus since the
// ancestry could be scanned by previous version of Clair.
repeated string scanned_listers = 4;
repeated string scanned_detectors = 5;
}
message Layer {
string hash = 1;
}
message Notification {
string name = 1;
string created = 2;
string notified = 3;
string deleted = 4;
PagedVulnerableAncestries old = 5;
PagedVulnerableAncestries new = 6;
}
message IndexedAncestryName {
// index is unique to name in all streams simultaneously streamed, increasing
// and larger than all indexes in previous page in same stream.
int32 index = 1;
string name = 2;
}
message PagedVulnerableAncestries {
string current_page = 1;
// if next_page is empty, it signals the end of all pages.
string next_page = 2;
int32 limit = 3;
Vulnerability vulnerability = 4;
repeated IndexedAncestryName ancestries = 5;
}
message PostAncestryRequest {
message PostLayer {
string hash = 1;
string path = 2;
map<string, string> headers = 3;
}
string ancestry_name = 1;
string format = 2;
repeated PostLayer layers = 3;
}
message PostAncestryResponse {
ClairStatus status = 1;
}
message GetAncestryRequest {
string ancestry_name = 1;
bool with_vulnerabilities = 2;
bool with_features = 3;
}
message GetAncestryResponse {
Ancestry ancestry = 1;
ClairStatus status = 2;
}
message GetNotificationRequest {
// if the vulnerability_page is empty, it implies the first page.
string old_vulnerability_page = 1;
string new_vulnerability_page = 2;
int32 limit = 3;
string name = 4;
}
message GetNotificationResponse {
Notification notification = 1;
}
message MarkNotificationAsReadRequest {
string name = 1;
}
service AncestryService{
rpc PostAncestry(PostAncestryRequest) returns (PostAncestryResponse) {
option (google.api.http) = {
post: "/ancestry"
body: "*"
};
}
rpc GetAncestry(GetAncestryRequest) returns (GetAncestryResponse) {
option (google.api.http) = {
get: "/ancestry/{ancestry_name}"
};
}
}
service NotificationService{
rpc GetNotification(GetNotificationRequest) returns (GetNotificationResponse) {
option (google.api.http) = {
get: "/notifications/{name}"
};
}
rpc MarkNotificationAsRead(MarkNotificationAsReadRequest) returns (google.protobuf.Empty) {
option (google.api.http) = {
delete: "/notifications/{name}"
};
}
}

View file

@ -0,0 +1,399 @@
{
"swagger": "2.0",
"info": {
"title": "api/v3/clairpb/clair.proto",
"version": "version not set"
},
"schemes": [
"http",
"https"
],
"consumes": [
"application/json"
],
"produces": [
"application/json"
],
"paths": {
"/ancestry": {
"post": {
"operationId": "PostAncestry",
"responses": {
"200": {
"description": "",
"schema": {
"$ref": "#/definitions/clairpbPostAncestryResponse"
}
}
},
"parameters": [
{
"name": "body",
"in": "body",
"required": true,
"schema": {
"$ref": "#/definitions/clairpbPostAncestryRequest"
}
}
],
"tags": [
"AncestryService"
]
}
},
"/ancestry/{ancestry_name}": {
"get": {
"operationId": "GetAncestry",
"responses": {
"200": {
"description": "",
"schema": {
"$ref": "#/definitions/clairpbGetAncestryResponse"
}
}
},
"parameters": [
{
"name": "ancestry_name",
"in": "path",
"required": true,
"type": "string"
},
{
"name": "with_vulnerabilities",
"in": "query",
"required": false,
"type": "boolean",
"format": "boolean"
},
{
"name": "with_features",
"in": "query",
"required": false,
"type": "boolean",
"format": "boolean"
}
],
"tags": [
"AncestryService"
]
}
},
"/notifications/{name}": {
"get": {
"operationId": "GetNotification",
"responses": {
"200": {
"description": "",
"schema": {
"$ref": "#/definitions/clairpbGetNotificationResponse"
}
}
},
"parameters": [
{
"name": "name",
"in": "path",
"required": true,
"type": "string"
},
{
"name": "old_vulnerability_page",
"description": "if the vulnerability_page is empty, it implies the first page.",
"in": "query",
"required": false,
"type": "string"
},
{
"name": "new_vulnerability_page",
"in": "query",
"required": false,
"type": "string"
},
{
"name": "limit",
"in": "query",
"required": false,
"type": "integer",
"format": "int32"
}
],
"tags": [
"NotificationService"
]
},
"delete": {
"operationId": "MarkNotificationAsRead",
"responses": {
"200": {
"description": "",
"schema": {
"$ref": "#/definitions/protobufEmpty"
}
}
},
"parameters": [
{
"name": "name",
"in": "path",
"required": true,
"type": "string"
}
],
"tags": [
"NotificationService"
]
}
}
},
"definitions": {
"PostAncestryRequestPostLayer": {
"type": "object",
"properties": {
"hash": {
"type": "string"
},
"path": {
"type": "string"
},
"headers": {
"type": "object",
"additionalProperties": {
"type": "string"
}
}
}
},
"clairpbAncestry": {
"type": "object",
"properties": {
"name": {
"type": "string"
},
"features": {
"type": "array",
"items": {
"$ref": "#/definitions/clairpbFeature"
}
},
"layers": {
"type": "array",
"items": {
"$ref": "#/definitions/clairpbLayer"
}
},
"scanned_listers": {
"type": "array",
"items": {
"type": "string"
},
"description": "scanned_listers and scanned_detectors are used to scan this ancestry, it\nmay be different from listers and detectors in ClairStatus since the\nancestry could be scanned by previous version of Clair."
},
"scanned_detectors": {
"type": "array",
"items": {
"type": "string"
}
}
}
},
"clairpbClairStatus": {
"type": "object",
"properties": {
"listers": {
"type": "array",
"items": {
"type": "string"
},
"title": "listers and detectors are processors implemented in this Clair and used to\nscan ancestries"
},
"detectors": {
"type": "array",
"items": {
"type": "string"
}
},
"last_update_time": {
"type": "string",
"format": "date-time"
}
}
},
"clairpbFeature": {
"type": "object",
"properties": {
"name": {
"type": "string"
},
"namespace_name": {
"type": "string"
},
"version": {
"type": "string"
},
"version_format": {
"type": "string",
"description": "version_format is the format used by installer package manager to store\npackage versions."
},
"vulnerabilities": {
"type": "array",
"items": {
"$ref": "#/definitions/clairpbVulnerability"
}
}
}
},
"clairpbGetAncestryResponse": {
"type": "object",
"properties": {
"ancestry": {
"$ref": "#/definitions/clairpbAncestry"
},
"status": {
"$ref": "#/definitions/clairpbClairStatus"
}
}
},
"clairpbGetNotificationResponse": {
"type": "object",
"properties": {
"notification": {
"$ref": "#/definitions/clairpbNotification"
}
}
},
"clairpbIndexedAncestryName": {
"type": "object",
"properties": {
"index": {
"type": "integer",
"format": "int32",
"description": "index is unique to name in all streams simultaneously streamed, increasing\nand larger than all indexes in previous page in same stream."
},
"name": {
"type": "string"
}
}
},
"clairpbLayer": {
"type": "object",
"properties": {
"hash": {
"type": "string"
}
}
},
"clairpbNotification": {
"type": "object",
"properties": {
"name": {
"type": "string"
},
"created": {
"type": "string"
},
"notified": {
"type": "string"
},
"deleted": {
"type": "string"
},
"old": {
"$ref": "#/definitions/clairpbPagedVulnerableAncestries"
},
"new": {
"$ref": "#/definitions/clairpbPagedVulnerableAncestries"
}
}
},
"clairpbPagedVulnerableAncestries": {
"type": "object",
"properties": {
"current_page": {
"type": "string"
},
"next_page": {
"type": "string",
"description": "if next_page is empty, it signals the end of all pages."
},
"limit": {
"type": "integer",
"format": "int32"
},
"vulnerability": {
"$ref": "#/definitions/clairpbVulnerability"
},
"ancestries": {
"type": "array",
"items": {
"$ref": "#/definitions/clairpbIndexedAncestryName"
}
}
}
},
"clairpbPostAncestryRequest": {
"type": "object",
"properties": {
"ancestry_name": {
"type": "string"
},
"format": {
"type": "string"
},
"layers": {
"type": "array",
"items": {
"$ref": "#/definitions/PostAncestryRequestPostLayer"
}
}
}
},
"clairpbPostAncestryResponse": {
"type": "object",
"properties": {
"status": {
"$ref": "#/definitions/clairpbClairStatus"
}
}
},
"clairpbVulnerability": {
"type": "object",
"properties": {
"name": {
"type": "string"
},
"namespace_name": {
"type": "string"
},
"description": {
"type": "string"
},
"link": {
"type": "string"
},
"severity": {
"type": "string"
},
"metadata": {
"type": "string"
},
"fixed_by": {
"type": "string",
"description": "fixed_by exists when vulnerability is under feature."
},
"affected_versions": {
"type": "array",
"items": {
"$ref": "#/definitions/clairpbFeature"
},
"description": "affected_versions exists when vulnerability is under notification."
}
}
},
"protobufEmpty": {
"type": "object",
"description": "service Foo {\n rpc Bar(google.protobuf.Empty) returns (google.protobuf.Empty);\n }\n\nThe JSON representation for `Empty` is empty JSON object `{}`.",
"title": "A generic empty message that you can re-use to avoid defining duplicated\nempty messages in your APIs. A typical example is to use it as the request\nor the response type of an API method. For instance:"
}
}
}

View file

@ -0,0 +1,155 @@
// Copyright 2017 clair 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 clairpb
import (
"encoding/json"
"fmt"
"github.com/coreos/clair/database"
"github.com/coreos/clair/ext/versionfmt"
)
// PagedVulnerableAncestriesFromDatabaseModel converts database
// PagedVulnerableAncestries to api PagedVulnerableAncestries and assigns
// indexes to ancestries.
func PagedVulnerableAncestriesFromDatabaseModel(dbVuln *database.PagedVulnerableAncestries) (*PagedVulnerableAncestries, error) {
if dbVuln == nil {
return nil, nil
}
vuln, err := VulnerabilityFromDatabaseModel(dbVuln.Vulnerability)
if err != nil {
return nil, err
}
next := ""
if !dbVuln.End {
next = string(dbVuln.Next)
}
vulnAncestry := PagedVulnerableAncestries{
Vulnerability: vuln,
CurrentPage: string(dbVuln.Current),
NextPage: next,
Limit: int32(dbVuln.Limit),
}
for index, ancestryName := range dbVuln.Affected {
indexedAncestry := IndexedAncestryName{
Name: ancestryName,
Index: int32(index),
}
vulnAncestry.Ancestries = append(vulnAncestry.Ancestries, &indexedAncestry)
}
return &vulnAncestry, nil
}
// NotificationFromDatabaseModel converts database notification, old and new
// vulnerabilities' paged vulnerable ancestries to be api notification.
func NotificationFromDatabaseModel(dbNotification database.VulnerabilityNotificationWithVulnerable) (*Notification, error) {
var (
noti Notification
err error
)
noti.Name = dbNotification.Name
if !dbNotification.Created.IsZero() {
noti.Created = fmt.Sprintf("%d", dbNotification.Created.Unix())
}
if !dbNotification.Notified.IsZero() {
noti.Notified = fmt.Sprintf("%d", dbNotification.Notified.Unix())
}
if !dbNotification.Deleted.IsZero() {
noti.Deleted = fmt.Sprintf("%d", dbNotification.Deleted.Unix())
}
noti.Old, err = PagedVulnerableAncestriesFromDatabaseModel(dbNotification.Old)
if err != nil {
return nil, err
}
noti.New, err = PagedVulnerableAncestriesFromDatabaseModel(dbNotification.New)
if err != nil {
return nil, err
}
return &noti, nil
}
func VulnerabilityFromDatabaseModel(dbVuln database.Vulnerability) (*Vulnerability, error) {
metaString := ""
if dbVuln.Metadata != nil {
metadataByte, err := json.Marshal(dbVuln.Metadata)
if err != nil {
return nil, err
}
metaString = string(metadataByte)
}
return &Vulnerability{
Name: dbVuln.Name,
NamespaceName: dbVuln.Namespace.Name,
Description: dbVuln.Description,
Link: dbVuln.Link,
Severity: string(dbVuln.Severity),
Metadata: metaString,
}, nil
}
func VulnerabilityWithFixedInFromDatabaseModel(dbVuln database.VulnerabilityWithFixedIn) (*Vulnerability, error) {
vuln, err := VulnerabilityFromDatabaseModel(dbVuln.Vulnerability)
if err != nil {
return nil, err
}
vuln.FixedBy = dbVuln.FixedInVersion
return vuln, nil
}
// AncestryFromDatabaseModel converts database ancestry to api ancestry.
func AncestryFromDatabaseModel(dbAncestry database.Ancestry) *Ancestry {
ancestry := &Ancestry{
Name: dbAncestry.Name,
}
for _, layer := range dbAncestry.Layers {
ancestry.Layers = append(ancestry.Layers, LayerFromDatabaseModel(layer))
}
return ancestry
}
// LayerFromDatabaseModel converts database layer to api layer.
func LayerFromDatabaseModel(dbLayer database.Layer) *Layer {
layer := Layer{Hash: dbLayer.Hash}
return &layer
}
// NamespacedFeatureFromDatabaseModel converts database namespacedFeature to api Feature.
func NamespacedFeatureFromDatabaseModel(feature database.NamespacedFeature) *Feature {
version := feature.Feature.Version
if version == versionfmt.MaxVersion {
version = "None"
}
return &Feature{
Name: feature.Feature.Name,
NamespaceName: feature.Namespace.Name,
VersionFormat: feature.Namespace.VersionFormat,
Version: version,
}
}

View file

@ -0,0 +1,28 @@
#!/usr/bin/env bash
# Copyright 2018 clair 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.
set -o errexit
set -o nounset
set -o pipefail
DOCKER_REPO_ROOT="$GOPATH/src/github.com/coreos/clair"
IMAGE=${IMAGE:-"quay.io/coreos/clair-gen-proto"}
docker run --rm -it \
-v "$DOCKER_REPO_ROOT":"$DOCKER_REPO_ROOT" \
-w "$DOCKER_REPO_ROOT" \
"$IMAGE" \
"./api/v3/clairpb/run_in_docker.sh"

View file

@ -0,0 +1,39 @@
#!/usr/bin/env bash
# Copyright 2018 clair 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.
set -o errexit
set -o nounset
set -o pipefail
protoc -I/usr/include -I. \
-I"${GOPATH}/src" \
-I"${GOPATH}/src/github.com/grpc-ecosystem/grpc-gateway/third_party/googleapis" \
--go_out=plugins=grpc:. \
./api/v3/clairpb/clair.proto
protoc -I/usr/include -I. \
-I"${GOPATH}/src" \
-I"${GOPATH}/src/github.com/grpc-ecosystem/grpc-gateway/third_party/googleapis" \
--grpc-gateway_out=logtostderr=true:. \
./api/v3/clairpb/clair.proto
protoc -I/usr/include -I. \
-I"${GOPATH}/src" \
-I"${GOPATH}/src/github.com/grpc-ecosystem/grpc-gateway/third_party/googleapis" \
--swagger_out=logtostderr=true:. \
./api/v3/clairpb/clair.proto
go generate .

253
vendor/github.com/coreos/clair/api/v3/rpc.go generated vendored Normal file
View file

@ -0,0 +1,253 @@
// Copyright 2017 clair 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 v3
import (
"fmt"
"github.com/golang/protobuf/ptypes"
google_protobuf1 "github.com/golang/protobuf/ptypes/empty"
"golang.org/x/net/context"
"google.golang.org/grpc/codes"
"google.golang.org/grpc/status"
"github.com/coreos/clair"
pb "github.com/coreos/clair/api/v3/clairpb"
"github.com/coreos/clair/database"
"github.com/coreos/clair/pkg/commonerr"
)
// NotificationServer implements NotificationService interface for serving RPC.
type NotificationServer struct {
Store database.Datastore
}
// AncestryServer implements AncestryService interface for serving RPC.
type AncestryServer struct {
Store database.Datastore
}
// PostAncestry implements posting an ancestry via the Clair gRPC service.
func (s *AncestryServer) PostAncestry(ctx context.Context, req *pb.PostAncestryRequest) (*pb.PostAncestryResponse, error) {
ancestryName := req.GetAncestryName()
if ancestryName == "" {
return nil, status.Error(codes.InvalidArgument, "ancestry name should not be empty")
}
layers := req.GetLayers()
if len(layers) == 0 {
return nil, status.Error(codes.InvalidArgument, "ancestry should have at least one layer")
}
ancestryFormat := req.GetFormat()
if ancestryFormat == "" {
return nil, status.Error(codes.InvalidArgument, "ancestry format should not be empty")
}
ancestryLayers := []clair.LayerRequest{}
for _, layer := range layers {
if layer == nil {
err := status.Error(codes.InvalidArgument, "ancestry layer is invalid")
return nil, err
}
if layer.GetHash() == "" {
return nil, status.Error(codes.InvalidArgument, "ancestry layer hash should not be empty")
}
if layer.GetPath() == "" {
return nil, status.Error(codes.InvalidArgument, "ancestry layer path should not be empty")
}
ancestryLayers = append(ancestryLayers, clair.LayerRequest{
Hash: layer.Hash,
Headers: layer.Headers,
Path: layer.Path,
})
}
err := clair.ProcessAncestry(s.Store, ancestryFormat, ancestryName, ancestryLayers)
if err != nil {
return nil, status.Error(codes.Internal, "ancestry is failed to be processed: "+err.Error())
}
clairStatus, err := s.getClairStatus()
if err != nil {
return nil, status.Error(codes.Internal, err.Error())
}
return &pb.PostAncestryResponse{Status: clairStatus}, nil
}
func (s *AncestryServer) getClairStatus() (*pb.ClairStatus, error) {
status := &pb.ClairStatus{
Listers: clair.Processors.Listers,
Detectors: clair.Processors.Detectors,
}
t, firstUpdate, err := clair.GetLastUpdateTime(s.Store)
if err != nil {
return nil, err
}
if firstUpdate {
return status, nil
}
status.LastUpdateTime, err = ptypes.TimestampProto(t)
if err != nil {
return nil, err
}
return status, nil
}
// GetAncestry implements retrieving an ancestry via the Clair gRPC service.
func (s *AncestryServer) GetAncestry(ctx context.Context, req *pb.GetAncestryRequest) (*pb.GetAncestryResponse, error) {
if req.GetAncestryName() == "" {
return nil, status.Errorf(codes.InvalidArgument, "ancestry name should not be empty")
}
tx, err := s.Store.Begin()
if err != nil {
return nil, status.Error(codes.Internal, err.Error())
}
defer tx.Rollback()
ancestry, _, ok, err := tx.FindAncestry(req.GetAncestryName())
if err != nil {
return nil, status.Error(codes.Internal, err.Error())
} else if !ok {
return nil, status.Error(codes.NotFound, fmt.Sprintf("requested ancestry '%s' is not found", req.GetAncestryName()))
}
pbAncestry := pb.AncestryFromDatabaseModel(ancestry)
if req.GetWithFeatures() || req.GetWithVulnerabilities() {
ancestryWFeature, ok, err := tx.FindAncestryFeatures(ancestry.Name)
if err != nil {
return nil, status.Error(codes.Internal, err.Error())
}
if !ok {
return nil, status.Error(codes.NotFound, fmt.Sprintf("requested ancestry '%s' is not found", req.GetAncestryName()))
}
pbAncestry.ScannedDetectors = ancestryWFeature.ProcessedBy.Detectors
pbAncestry.ScannedListers = ancestryWFeature.ProcessedBy.Listers
if req.GetWithVulnerabilities() {
featureVulnerabilities, err := tx.FindAffectedNamespacedFeatures(ancestryWFeature.Features)
if err != nil {
return nil, status.Error(codes.Internal, err.Error())
}
for _, fv := range featureVulnerabilities {
// Ensure that every feature can be found.
if !fv.Valid {
return nil, status.Error(codes.Internal, "ancestry feature is not found")
}
pbFeature := pb.NamespacedFeatureFromDatabaseModel(fv.NamespacedFeature)
for _, v := range fv.AffectedBy {
pbVuln, err := pb.VulnerabilityWithFixedInFromDatabaseModel(v)
if err != nil {
return nil, status.Error(codes.Internal, err.Error())
}
pbFeature.Vulnerabilities = append(pbFeature.Vulnerabilities, pbVuln)
}
pbAncestry.Features = append(pbAncestry.Features, pbFeature)
}
} else {
for _, f := range ancestryWFeature.Features {
pbAncestry.Features = append(pbAncestry.Features, pb.NamespacedFeatureFromDatabaseModel(f))
}
}
}
clairStatus, err := s.getClairStatus()
if err != nil {
return nil, status.Error(codes.Internal, err.Error())
}
return &pb.GetAncestryResponse{
Status: clairStatus,
Ancestry: pbAncestry,
}, nil
}
// GetNotification implements retrieving a notification via the Clair gRPC
// service.
func (s *NotificationServer) GetNotification(ctx context.Context, req *pb.GetNotificationRequest) (*pb.GetNotificationResponse, error) {
if req.GetName() == "" {
return nil, status.Error(codes.InvalidArgument, "notification name should not be empty")
}
if req.GetLimit() <= 0 {
return nil, status.Error(codes.InvalidArgument, "notification page limit should not be empty or less than 1")
}
tx, err := s.Store.Begin()
if err != nil {
return nil, status.Error(codes.Internal, err.Error())
}
defer tx.Rollback()
dbNotification, ok, err := tx.FindVulnerabilityNotification(
req.GetName(),
int(req.GetLimit()),
database.PageNumber(req.GetOldVulnerabilityPage()),
database.PageNumber(req.GetNewVulnerabilityPage()),
)
if err != nil {
return nil, status.Error(codes.Internal, err.Error())
}
if !ok {
return nil, status.Error(codes.NotFound, fmt.Sprintf("requested notification '%s' is not found", req.GetName()))
}
notification, err := pb.NotificationFromDatabaseModel(dbNotification)
if err != nil {
return nil, status.Error(codes.Internal, err.Error())
}
return &pb.GetNotificationResponse{Notification: notification}, nil
}
// MarkNotificationAsRead implements deleting a notification via the Clair gRPC
// service.
func (s *NotificationServer) MarkNotificationAsRead(ctx context.Context, req *pb.MarkNotificationAsReadRequest) (*google_protobuf1.Empty, error) {
if req.GetName() == "" {
return nil, status.Error(codes.InvalidArgument, "notification name should not be empty")
}
tx, err := s.Store.Begin()
if err != nil {
return nil, status.Error(codes.Internal, err.Error())
}
defer tx.Rollback()
err = tx.DeleteNotification(req.GetName())
if err == commonerr.ErrNotFound {
return nil, status.Error(codes.NotFound, "requested notification \""+req.GetName()+"\" is not found")
} else if err != nil {
return nil, status.Error(codes.Internal, err.Error())
}
if err := tx.Commit(); err != nil {
return nil, status.Error(codes.Internal, err.Error())
}
return &google_protobuf1.Empty{}, nil
}

222
vendor/github.com/coreos/clair/api/v3/server.go generated vendored Normal file
View file

@ -0,0 +1,222 @@
// Copyright 2017 clair 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 v3
import (
"context"
"crypto/tls"
"net"
"net/http"
"strconv"
"strings"
"time"
"github.com/cockroachdb/cmux"
"github.com/grpc-ecosystem/go-grpc-prometheus"
"github.com/grpc-ecosystem/grpc-gateway/runtime"
"github.com/prometheus/client_golang/prometheus"
log "github.com/sirupsen/logrus"
"google.golang.org/grpc"
"google.golang.org/grpc/credentials"
pb "github.com/coreos/clair/api/v3/clairpb"
"github.com/coreos/clair/database"
)
// handleShutdown handles the server shut down error.
func handleShutdown(err error) {
if err != nil {
if opErr, ok := err.(*net.OpError); !ok || (ok && opErr.Op != "accept") {
log.Fatal(err)
}
}
}
var (
promResponseDurationMilliseconds = prometheus.NewHistogramVec(prometheus.HistogramOpts{
Name: "clair_v3_api_response_duration_milliseconds",
Help: "The duration of time it takes to receive and write a response to an V2 API request",
Buckets: prometheus.ExponentialBuckets(9.375, 2, 10),
}, []string{"route", "code"})
)
func init() {
prometheus.MustRegister(promResponseDurationMilliseconds)
}
func newGrpcServer(store database.Datastore, tlsConfig *tls.Config) *grpc.Server {
grpcOpts := []grpc.ServerOption{
grpc.UnaryInterceptor(grpc_prometheus.UnaryServerInterceptor),
grpc.StreamInterceptor(grpc_prometheus.StreamServerInterceptor),
}
if tlsConfig != nil {
grpcOpts = append(grpcOpts, grpc.Creds(credentials.NewTLS(tlsConfig)))
}
grpcServer := grpc.NewServer(grpcOpts...)
pb.RegisterAncestryServiceServer(grpcServer, &AncestryServer{Store: store})
pb.RegisterNotificationServiceServer(grpcServer, &NotificationServer{Store: store})
return grpcServer
}
type httpStatusWritter struct {
http.ResponseWriter
StatusCode int
}
func (w *httpStatusWritter) WriteHeader(code int) {
w.StatusCode = code
w.ResponseWriter.WriteHeader(code)
}
// logHandler adds request logging to an http handler.
func logHandler(handler http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
start := time.Now()
lrw := &httpStatusWritter{ResponseWriter: w, StatusCode: http.StatusOK}
handler.ServeHTTP(lrw, r)
statusStr := strconv.Itoa(lrw.StatusCode)
if lrw.StatusCode == 0 {
statusStr = "???"
}
log.WithFields(log.Fields{
"remote addr": r.RemoteAddr,
"method": r.Method,
"request uri": r.RequestURI,
"status": statusStr,
"elapsed time (ms)": float64(time.Since(start).Nanoseconds()) * 1e-6,
}).Info("Handled HTTP request")
})
}
func newGrpcGatewayServer(ctx context.Context, listenerAddr string, tlsConfig *tls.Config) http.Handler {
var (
gwTLSConfig *tls.Config
gwOpts []grpc.DialOption
)
if tlsConfig != nil {
gwTLSConfig = tlsConfig.Clone()
gwTLSConfig.InsecureSkipVerify = true
gwOpts = append(gwOpts, grpc.WithTransportCredentials(credentials.NewTLS(gwTLSConfig)))
} else {
gwOpts = append(gwOpts, grpc.WithInsecure())
}
// changes json serializer to include empty fields with default values
jsonOpt := runtime.WithMarshalerOption(runtime.MIMEWildcard, &runtime.JSONPb{EmitDefaults: true})
gwmux := runtime.NewServeMux(jsonOpt)
conn, err := grpc.DialContext(ctx, listenerAddr, gwOpts...)
if err != nil {
log.WithError(err).Fatal("could not initialize grpc gateway connection")
}
err = pb.RegisterAncestryServiceHandler(ctx, gwmux, conn)
if err != nil {
log.WithError(err).Fatal("could not initialize ancestry grpc gateway")
}
err = pb.RegisterNotificationServiceHandler(ctx, gwmux, conn)
if err != nil {
log.WithError(err).Fatal("could not initialize notification grpc gateway")
}
return logHandler(gwmux)
}
func servePrometheus(mux *http.ServeMux) {
mux.Handle("/metrics", prometheus.Handler())
}
// Run initializes grpc and grpc gateway api services on the same address
func Run(Addr string, tlsConfig *tls.Config, CertFile, KeyFile string, store database.Datastore) {
l, err := net.Listen("tcp", Addr)
if err != nil {
log.WithError(err).Fatalf("could not listen to address" + Addr)
}
log.WithField("addr", l.Addr().String()).Info("starting grpc server")
var (
apiHandler http.Handler
apiListener net.Listener
srv *http.Server
ctx = context.Background()
httpMux = http.NewServeMux()
tcpMux = cmux.New(l)
)
if tlsConfig != nil {
cert, err := tls.LoadX509KeyPair(CertFile, KeyFile)
if err != nil {
log.WithError(err).Fatal("Failed to load certificate files")
}
tlsConfig.Certificates = []tls.Certificate{cert}
tlsConfig.NextProtos = []string{"h2"}
apiListener = tls.NewListener(tcpMux.Match(cmux.Any()), tlsConfig)
go func() { handleShutdown(tcpMux.Serve()) }()
grpcServer := newGrpcServer(store, tlsConfig)
gwmux := newGrpcGatewayServer(ctx, apiListener.Addr().String(), tlsConfig)
httpMux.Handle("/", gwmux)
servePrometheus(httpMux)
apiHandler = grpcHandlerFunc(grpcServer, httpMux)
log.Info("grpc server is configured with client certificate authentication")
} else {
grpcL := tcpMux.Match(cmux.HTTP2HeaderField("content-type", "application/grpc"))
apiListener = tcpMux.Match(cmux.Any())
go func() { handleShutdown(tcpMux.Serve()) }()
grpcServer := newGrpcServer(store, nil)
go func() { handleShutdown(grpcServer.Serve(grpcL)) }()
gwmux := newGrpcGatewayServer(ctx, apiListener.Addr().String(), nil)
httpMux.Handle("/", gwmux)
servePrometheus(httpMux)
apiHandler = httpMux
log.Warn("grpc server is configured without client certificate authentication")
}
srv = &http.Server{
Handler: apiHandler,
TLSConfig: tlsConfig,
}
// blocking call
handleShutdown(srv.Serve(apiListener))
log.Info("Grpc API stopped")
}
// grpcHandlerFunc returns an http.Handler that delegates to grpcServer on incoming gRPC
// connections or otherHandler otherwise. Copied from cockroachdb.
func grpcHandlerFunc(grpcServer *grpc.Server, otherHandler http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
if r.ProtoMajor == 2 && strings.Contains(r.Header.Get("Content-Type"), "application/grpc") {
grpcServer.ServeHTTP(w, r)
} else {
otherHandler.ServeHTTP(w, r)
}
})
}

132
vendor/github.com/coreos/clair/bill-of-materials.json generated vendored Normal file
View file

@ -0,0 +1,132 @@
[
{
"project": "github.com/beorn7/perks/quantile",
"licenses": [
{
"type": "MIT License",
"confidence": 0.9891304347826086
}
]
},
{
"project": "github.com/coreos/clair",
"licenses": [
{
"type": "Apache License 2.0",
"confidence": 1
}
]
},
{
"project": "github.com/coreos/pkg/timeutil",
"licenses": [
{
"type": "Apache License 2.0",
"confidence": 1
}
]
},
{
"project": "github.com/golang/protobuf/proto",
"licenses": [
{
"type": "BSD 3-clause \"New\" or \"Revised\" License",
"confidence": 0.92
}
]
},
{
"project": "github.com/matttproud/golang_protobuf_extensions/pbutil",
"licenses": [
{
"type": "Apache License 2.0",
"confidence": 1
}
]
},
{
"project": "github.com/pborman/uuid",
"licenses": [
{
"type": "BSD 3-clause \"New\" or \"Revised\" License",
"confidence": 0.9663865546218487
}
]
},
{
"project": "github.com/prometheus/client_golang/prometheus",
"licenses": [
{
"type": "Apache License 2.0",
"confidence": 1
}
]
},
{
"project": "github.com/prometheus/client_model/go",
"licenses": [
{
"type": "Apache License 2.0",
"confidence": 1
}
]
},
{
"project": "github.com/prometheus/common",
"licenses": [
{
"type": "Apache License 2.0",
"confidence": 1
}
]
},
{
"project": "github.com/prometheus/procfs",
"licenses": [
{
"type": "Apache License 2.0",
"confidence": 1
}
]
},
{
"project": "github.com/sirupsen/logrus",
"licenses": [
{
"type": "MIT License",
"confidence": 1
}
]
},
{
"project": "github.com/stretchr/testify/assert",
"licenses": [
{
"type": "MIT License",
"confidence": 0.9430051813471503
},
{
"type": "MIT License",
"confidence": 0.9430051813471503
}
]
},
{
"project": "github.com/stretchr/testify/vendor/github.com/davecgh/go-spew/spew",
"licenses": [
{
"type": "ISC License",
"confidence": 0.9850746268656716
}
]
},
{
"project": "github.com/stretchr/testify/vendor/github.com/pmezard/go-difflib/difflib",
"licenses": [
{
"type": "BSD 3-clause \"New\" or \"Revised\" License",
"confidence": 0.9830508474576272
}
]
}
]

61
vendor/github.com/coreos/clair/code-of-conduct.md generated vendored Normal file
View file

@ -0,0 +1,61 @@
## CoreOS Community Code of Conduct
### Contributor Code of Conduct
As contributors and maintainers of this project, and in the interest of
fostering an open and welcoming community, we pledge to respect all people who
contribute through reporting issues, posting feature requests, updating
documentation, submitting pull requests or patches, and other activities.
We are committed to making participation in this project a harassment-free
experience for everyone, regardless of level of experience, gender, gender
identity and expression, sexual orientation, disability, personal appearance,
body size, race, ethnicity, age, religion, or nationality.
Examples of unacceptable behavior by participants include:
* The use of sexualized language or imagery
* Personal attacks
* Trolling or insulting/derogatory comments
* Public or private harassment
* Publishing others' private information, such as physical or electronic addresses, without explicit permission
* Other unethical or unprofessional conduct.
Project maintainers have the right and responsibility to remove, edit, or
reject comments, commits, code, wiki edits, issues, and other contributions
that are not aligned to this Code of Conduct. By adopting this Code of Conduct,
project maintainers commit themselves to fairly and consistently applying these
principles to every aspect of managing this project. Project maintainers who do
not follow or enforce the Code of Conduct may be permanently removed from the
project team.
This code of conduct applies both within project spaces and in public spaces
when an individual is representing the project or its community.
Instances of abusive, harassing, or otherwise unacceptable behavior may be
reported by contacting a project maintainer, Brandon Philips
<brandon.philips@coreos.com>, and/or Rithu John <rithu.john@coreos.com>.
This Code of Conduct is adapted from the Contributor Covenant
(http://contributor-covenant.org), version 1.2.0, available at
http://contributor-covenant.org/version/1/2/0/
### CoreOS Events Code of Conduct
CoreOS events are working conferences intended for professional networking and
collaboration in the CoreOS community. Attendees are expected to behave
according to professional standards and in accordance with their employers
policies on appropriate workplace behavior.
While at CoreOS events or related social networking opportunities, attendees
should not engage in discriminatory or offensive speech or actions including
but not limited to gender, sexuality, race, age, disability, or religion.
Speakers should be especially aware of these concerns.
CoreOS does not condone any statements by speakers contrary to these standards.
CoreOS reserves the right to deny entrance and/or eject from an event (without
refund) any individual found to be engaging in discriminatory or offensive
speech or actions.
Please bring any concerns to the immediate attention of designated on-site
staff, Brandon Philips <brandon.philips@coreos.com>, and/or Rithu John <rithu.john@coreos.com>.

99
vendor/github.com/coreos/clair/config.yaml.sample generated vendored Normal file
View file

@ -0,0 +1,99 @@
# Copyright 2015 clair 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.
# The values specified here are the default values that Clair uses if no configuration file is specified or if the keys are not defined.
clair:
database:
# Database driver
type: pgsql
options:
# PostgreSQL Connection string
# https://www.postgresql.org/docs/current/static/libpq-connect.html#LIBPQ-CONNSTRING
source: host=localhost port=5432 user=postgres sslmode=disable statement_timeout=60000
# Number of elements kept in the cache
# Values unlikely to change (e.g. namespaces) are cached in order to save prevent needless roundtrips to the database.
cachesize: 16384
# 32-bit URL-safe base64 key used to encrypt pagination tokens
# If one is not provided, it will be generated.
# Multiple clair instances in the same cluster need the same value.
paginationkey:
api:
# v3 grpc/RESTful API server address
addr: "0.0.0.0:6060"
# Health server address
# This is an unencrypted endpoint useful for load balancers to check to healthiness of the clair server.
healthaddr: "0.0.0.0:6061"
# Deadline before an API request will respond with a 503
timeout: 900s
# Optional PKI configuration
# If you want to easily generate client certificates and CAs, try the following projects:
# https://github.com/coreos/etcd-ca
# https://github.com/cloudflare/cfssl
servername:
cafile:
keyfile:
certfile:
worker:
namespace_detectors:
- os-release
- lsb-release
- apt-sources
- alpine-release
- redhat-release
feature_listers:
- apk
- dpkg
- rpm
updater:
# Frequency the database will be updated with vulnerabilities from the default data sources
# The value 0 disables the updater entirely.
interval: 2h
enabledupdaters:
- debian
- ubuntu
- rhel
- oracle
- alpine
notifier:
# Number of attempts before the notification is marked as failed to be sent
attempts: 3
# Duration before a failed notification is retried
renotifyinterval: 2h
http:
# Optional endpoint that will receive notifications via POST requests
endpoint:
# Optional PKI configuration
# If you want to easily generate client certificates and CAs, try the following projects:
# https://github.com/cloudflare/cfssl
# https://github.com/coreos/etcd-ca
servername:
cafile:
keyfile:
certfile:
# Optional HTTP Proxy: must be a valid URL (including the scheme).
proxy:

224
vendor/github.com/coreos/clair/database/database.go generated vendored Normal file
View file

@ -0,0 +1,224 @@
// Copyright 2017 clair 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 database defines the Clair's models and a common interface for
// database implementations.
package database
import (
"errors"
"fmt"
"time"
)
var (
// ErrBackendException is an error that occurs when the database backend
// does not work properly (ie. unreachable).
ErrBackendException = errors.New("database: an error occurred when querying the backend")
// ErrInconsistent is an error that occurs when a database consistency check
// fails (i.e. when an entity which is supposed to be unique is detected
// twice)
ErrInconsistent = errors.New("database: inconsistent database")
)
// RegistrableComponentConfig is a configuration block that can be used to
// determine which registrable component should be initialized and pass custom
// configuration to it.
type RegistrableComponentConfig struct {
Type string
Options map[string]interface{}
}
var drivers = make(map[string]Driver)
// Driver is a function that opens a Datastore specified by its database driver
// type and specific configuration.
type Driver func(RegistrableComponentConfig) (Datastore, error)
// Register makes a Constructor available by the provided name.
//
// If this function is called twice with the same name or if the Constructor is
// nil, it panics.
func Register(name string, driver Driver) {
if driver == nil {
panic("database: could not register nil Driver")
}
if _, dup := drivers[name]; dup {
panic("database: could not register duplicate Driver: " + name)
}
drivers[name] = driver
}
// Open opens a Datastore specified by a configuration.
func Open(cfg RegistrableComponentConfig) (Datastore, error) {
driver, ok := drivers[cfg.Type]
if !ok {
return nil, fmt.Errorf("database: unknown Driver %q (forgotten configuration or import?)", cfg.Type)
}
return driver(cfg)
}
// Session contains the required operations on a persistent data store for a
// Clair deployment.
//
// Session is started by Datastore.Begin and terminated with Commit or Rollback.
// Besides Commit and Rollback, other functions cannot be called after the
// session is terminated.
// Any function is not guaranteed to be called successfully if there's a session
// failure.
type Session interface {
// Commit commits changes to datastore.
//
// Commit call after Rollback does no-op.
Commit() error
// Rollback drops changes to datastore.
//
// Rollback call after Commit does no-op.
Rollback() error
// UpsertAncestry inserts or replaces an ancestry and its namespaced
// features and processors used to scan the ancestry.
UpsertAncestry(ancestry Ancestry, features []NamespacedFeature, processedBy Processors) error
// FindAncestry retrieves an ancestry with processors used to scan the
// ancestry. If the ancestry is not found, return false.
//
// The ancestry's processors are returned to short cut processing ancestry
// if it has been processed by all processors in the current Clair instance.
FindAncestry(name string) (ancestry Ancestry, processedBy Processors, found bool, err error)
// FindAncestryFeatures retrieves an ancestry with all detected namespaced
// features. If the ancestry is not found, return false.
FindAncestryFeatures(name string) (ancestry AncestryWithFeatures, found bool, err error)
// PersistFeatures inserts a set of features if not in the database.
PersistFeatures(features []Feature) error
// PersistNamespacedFeatures inserts a set of namespaced features if not in
// the database.
PersistNamespacedFeatures([]NamespacedFeature) error
// CacheAffectedNamespacedFeatures relates the namespaced features with the
// vulnerabilities affecting these features.
//
// NOTE(Sida): it's not necessary for every database implementation and so
// this function may have a better home.
CacheAffectedNamespacedFeatures([]NamespacedFeature) error
// FindAffectedNamespacedFeatures retrieves a set of namespaced features
// with affecting vulnerabilities.
FindAffectedNamespacedFeatures(features []NamespacedFeature) ([]NullableAffectedNamespacedFeature, error)
// PersistNamespaces inserts a set of namespaces if not in the database.
PersistNamespaces([]Namespace) error
// PersistLayer inserts a layer if not in the datastore.
PersistLayer(Layer) error
// PersistLayerContent persists a layer's content in the database. The given
// namespaces and features can be partial content of this layer.
//
// The layer, namespaces and features are expected to be already existing
// in the database.
PersistLayerContent(hash string, namespaces []Namespace, features []Feature, processedBy Processors) error
// FindLayer retrieves a layer and the processors scanned the layer.
FindLayer(hash string) (layer Layer, processedBy Processors, found bool, err error)
// FindLayerWithContent returns a layer with all detected features and
// namespaces.
FindLayerWithContent(hash string) (layer LayerWithContent, found bool, err error)
// InsertVulnerabilities inserts a set of UNIQUE vulnerabilities with
// affected features into database, assuming that all vulnerabilities
// provided are NOT in database and all vulnerabilities' namespaces are
// already in the database.
InsertVulnerabilities([]VulnerabilityWithAffected) error
// FindVulnerability retrieves a set of Vulnerabilities with affected
// features.
FindVulnerabilities([]VulnerabilityID) ([]NullableVulnerability, error)
// DeleteVulnerability removes a set of Vulnerabilities assuming that the
// requested vulnerabilities are in the database.
DeleteVulnerabilities([]VulnerabilityID) error
// InsertVulnerabilityNotifications inserts a set of unique vulnerability
// notifications into datastore, assuming that they are not in the database.
InsertVulnerabilityNotifications([]VulnerabilityNotification) error
// FindNewNotification retrieves a notification, which has never been
// notified or notified before a certain time.
FindNewNotification(notifiedBefore time.Time) (hook NotificationHook, found bool, err error)
// FindVulnerabilityNotification retrieves a vulnerability notification with
// affected ancestries affected by old or new vulnerability.
//
// Because the number of affected ancestries maybe large, they are paginated
// and their pages are specified by the given encrypted PageNumbers, which,
// if empty, are always considered first page.
//
// Session interface implementation should have encrypt and decrypt
// functions for PageNumber.
FindVulnerabilityNotification(name string, limit int,
oldVulnerabilityPage PageNumber,
newVulnerabilityPage PageNumber) (
noti VulnerabilityNotificationWithVulnerable,
found bool, err error)
// MarkNotificationNotified marks a Notification as notified now, assuming
// the requested notification is in the database.
MarkNotificationNotified(name string) error
// DeleteNotification removes a Notification in the database.
DeleteNotification(name string) error
// UpdateKeyValue stores or updates a simple key/value pair.
UpdateKeyValue(key, value string) error
// FindKeyValue retrieves a value from the given key.
FindKeyValue(key string) (value string, found bool, err error)
// Lock creates or renew a Lock in the database with the given name, owner
// and duration.
//
// After the specified duration, the Lock expires by itself if it hasn't been
// unlocked, and thus, let other users create a Lock with the same name.
// However, the owner can renew its Lock by setting renew to true.
// Lock should not block, it should instead returns whether the Lock has been
// successfully acquired/renewed. If it's the case, the expiration time of
// that Lock is returned as well.
Lock(name string, owner string, duration time.Duration, renew bool) (success bool, expiration time.Time, err error)
// Unlock releases an existing Lock.
Unlock(name, owner string) error
// FindLock returns the owner of a Lock specified by the name, and its
// expiration time if it exists.
FindLock(name string) (owner string, expiration time.Time, found bool, err error)
}
// Datastore represents a persistent data store
type Datastore interface {
// Begin starts a session to change.
Begin() (Session, error)
// Ping returns the health status of the database.
Ping() bool
// Close closes the database and frees any allocated resource.
Close()
}

270
vendor/github.com/coreos/clair/database/mock.go generated vendored Normal file
View file

@ -0,0 +1,270 @@
// Copyright 2015 clair 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 database
import "time"
// MockSession implements Session and enables overriding each available method.
// The default behavior of each method is to simply panic.
type MockSession struct {
FctCommit func() error
FctRollback func() error
FctUpsertAncestry func(Ancestry, []NamespacedFeature, Processors) error
FctFindAncestry func(name string) (Ancestry, Processors, bool, error)
FctFindAncestryFeatures func(name string) (AncestryWithFeatures, bool, error)
FctFindAffectedNamespacedFeatures func(features []NamespacedFeature) ([]NullableAffectedNamespacedFeature, error)
FctPersistNamespaces func([]Namespace) error
FctPersistFeatures func([]Feature) error
FctPersistNamespacedFeatures func([]NamespacedFeature) error
FctCacheAffectedNamespacedFeatures func([]NamespacedFeature) error
FctPersistLayer func(Layer) error
FctPersistLayerContent func(hash string, namespaces []Namespace, features []Feature, processedBy Processors) error
FctFindLayer func(name string) (Layer, Processors, bool, error)
FctFindLayerWithContent func(name string) (LayerWithContent, bool, error)
FctInsertVulnerabilities func([]VulnerabilityWithAffected) error
FctFindVulnerabilities func([]VulnerabilityID) ([]NullableVulnerability, error)
FctDeleteVulnerabilities func([]VulnerabilityID) error
FctInsertVulnerabilityNotifications func([]VulnerabilityNotification) error
FctFindNewNotification func(lastNotified time.Time) (NotificationHook, bool, error)
FctFindVulnerabilityNotification func(name string, limit int, oldPage PageNumber, newPage PageNumber) (
vuln VulnerabilityNotificationWithVulnerable, ok bool, err error)
FctMarkNotificationNotified func(name string) error
FctDeleteNotification func(name string) error
FctUpdateKeyValue func(key, value string) error
FctFindKeyValue func(key string) (string, bool, error)
FctLock func(name string, owner string, duration time.Duration, renew bool) (bool, time.Time, error)
FctUnlock func(name, owner string) error
FctFindLock func(name string) (string, time.Time, bool, error)
}
func (ms *MockSession) Commit() error {
if ms.FctCommit != nil {
return ms.FctCommit()
}
panic("required mock function not implemented")
}
func (ms *MockSession) Rollback() error {
if ms.FctRollback != nil {
return ms.FctRollback()
}
panic("required mock function not implemented")
}
func (ms *MockSession) UpsertAncestry(ancestry Ancestry, features []NamespacedFeature, processedBy Processors) error {
if ms.FctUpsertAncestry != nil {
return ms.FctUpsertAncestry(ancestry, features, processedBy)
}
panic("required mock function not implemented")
}
func (ms *MockSession) FindAncestry(name string) (Ancestry, Processors, bool, error) {
if ms.FctFindAncestry != nil {
return ms.FctFindAncestry(name)
}
panic("required mock function not implemented")
}
func (ms *MockSession) FindAncestryFeatures(name string) (AncestryWithFeatures, bool, error) {
if ms.FctFindAncestryFeatures != nil {
return ms.FctFindAncestryFeatures(name)
}
panic("required mock function not implemented")
}
func (ms *MockSession) FindAffectedNamespacedFeatures(features []NamespacedFeature) ([]NullableAffectedNamespacedFeature, error) {
if ms.FctFindAffectedNamespacedFeatures != nil {
return ms.FctFindAffectedNamespacedFeatures(features)
}
panic("required mock function not implemented")
}
func (ms *MockSession) PersistNamespaces(namespaces []Namespace) error {
if ms.FctPersistNamespaces != nil {
return ms.FctPersistNamespaces(namespaces)
}
panic("required mock function not implemented")
}
func (ms *MockSession) PersistFeatures(features []Feature) error {
if ms.FctPersistFeatures != nil {
return ms.FctPersistFeatures(features)
}
panic("required mock function not implemented")
}
func (ms *MockSession) PersistNamespacedFeatures(namespacedFeatures []NamespacedFeature) error {
if ms.FctPersistNamespacedFeatures != nil {
return ms.FctPersistNamespacedFeatures(namespacedFeatures)
}
panic("required mock function not implemented")
}
func (ms *MockSession) CacheAffectedNamespacedFeatures(namespacedFeatures []NamespacedFeature) error {
if ms.FctCacheAffectedNamespacedFeatures != nil {
return ms.FctCacheAffectedNamespacedFeatures(namespacedFeatures)
}
panic("required mock function not implemented")
}
func (ms *MockSession) PersistLayer(layer Layer) error {
if ms.FctPersistLayer != nil {
return ms.FctPersistLayer(layer)
}
panic("required mock function not implemented")
}
func (ms *MockSession) PersistLayerContent(hash string, namespaces []Namespace, features []Feature, processedBy Processors) error {
if ms.FctPersistLayerContent != nil {
return ms.FctPersistLayerContent(hash, namespaces, features, processedBy)
}
panic("required mock function not implemented")
}
func (ms *MockSession) FindLayer(name string) (Layer, Processors, bool, error) {
if ms.FctFindLayer != nil {
return ms.FctFindLayer(name)
}
panic("required mock function not implemented")
}
func (ms *MockSession) FindLayerWithContent(name string) (LayerWithContent, bool, error) {
if ms.FctFindLayerWithContent != nil {
return ms.FctFindLayerWithContent(name)
}
panic("required mock function not implemented")
}
func (ms *MockSession) InsertVulnerabilities(vulnerabilities []VulnerabilityWithAffected) error {
if ms.FctInsertVulnerabilities != nil {
return ms.FctInsertVulnerabilities(vulnerabilities)
}
panic("required mock function not implemented")
}
func (ms *MockSession) FindVulnerabilities(vulnerabilityIDs []VulnerabilityID) ([]NullableVulnerability, error) {
if ms.FctFindVulnerabilities != nil {
return ms.FctFindVulnerabilities(vulnerabilityIDs)
}
panic("required mock function not implemented")
}
func (ms *MockSession) DeleteVulnerabilities(VulnerabilityIDs []VulnerabilityID) error {
if ms.FctDeleteVulnerabilities != nil {
return ms.FctDeleteVulnerabilities(VulnerabilityIDs)
}
panic("required mock function not implemented")
}
func (ms *MockSession) InsertVulnerabilityNotifications(vulnerabilityNotifications []VulnerabilityNotification) error {
if ms.FctInsertVulnerabilityNotifications != nil {
return ms.FctInsertVulnerabilityNotifications(vulnerabilityNotifications)
}
panic("required mock function not implemented")
}
func (ms *MockSession) FindNewNotification(lastNotified time.Time) (NotificationHook, bool, error) {
if ms.FctFindNewNotification != nil {
return ms.FctFindNewNotification(lastNotified)
}
panic("required mock function not implemented")
}
func (ms *MockSession) FindVulnerabilityNotification(name string, limit int, oldPage PageNumber, newPage PageNumber) (
VulnerabilityNotificationWithVulnerable, bool, error) {
if ms.FctFindVulnerabilityNotification != nil {
return ms.FctFindVulnerabilityNotification(name, limit, oldPage, newPage)
}
panic("required mock function not implemented")
}
func (ms *MockSession) MarkNotificationNotified(name string) error {
if ms.FctMarkNotificationNotified != nil {
return ms.FctMarkNotificationNotified(name)
}
panic("required mock function not implemented")
}
func (ms *MockSession) DeleteNotification(name string) error {
if ms.FctDeleteNotification != nil {
return ms.FctDeleteNotification(name)
}
panic("required mock function not implemented")
}
func (ms *MockSession) UpdateKeyValue(key, value string) error {
if ms.FctUpdateKeyValue != nil {
return ms.FctUpdateKeyValue(key, value)
}
panic("required mock function not implemented")
}
func (ms *MockSession) FindKeyValue(key string) (string, bool, error) {
if ms.FctFindKeyValue != nil {
return ms.FctFindKeyValue(key)
}
panic("required mock function not implemented")
}
func (ms *MockSession) Lock(name string, owner string, duration time.Duration, renew bool) (bool, time.Time, error) {
if ms.FctLock != nil {
return ms.FctLock(name, owner, duration, renew)
}
panic("required mock function not implemented")
}
func (ms *MockSession) Unlock(name, owner string) error {
if ms.FctUnlock != nil {
return ms.FctUnlock(name, owner)
}
panic("required mock function not implemented")
}
func (ms *MockSession) FindLock(name string) (string, time.Time, bool, error) {
if ms.FctFindLock != nil {
return ms.FctFindLock(name)
}
panic("required mock function not implemented")
}
// MockDatastore implements Datastore and enables overriding each available method.
// The default behavior of each method is to simply panic.
type MockDatastore struct {
FctBegin func() (Session, error)
FctPing func() bool
FctClose func()
}
func (mds *MockDatastore) Begin() (Session, error) {
if mds.FctBegin != nil {
return mds.FctBegin()
}
panic("required mock function not implemented")
}
func (mds *MockDatastore) Ping() bool {
if mds.FctPing != nil {
return mds.FctPing()
}
panic("required mock function not implemented")
}
func (mds *MockDatastore) Close() {
if mds.FctClose != nil {
mds.FctClose()
return
}
panic("required mock function not implemented")
}

235
vendor/github.com/coreos/clair/database/models.go generated vendored Normal file
View file

@ -0,0 +1,235 @@
// Copyright 2017 clair 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 database
import (
"database/sql/driver"
"encoding/json"
"time"
)
// Processors are extentions to scan layer's content.
type Processors struct {
Listers []string
Detectors []string
}
// Ancestry is a manifest that keeps all layers in an image in order.
type Ancestry struct {
Name string
// Layers should be ordered and i_th layer is the parent of i+1_th layer in
// the slice.
Layers []Layer
}
// AncestryWithFeatures is an ancestry with namespaced features detected in the
// ancestry, which is processed by `ProcessedBy`.
type AncestryWithFeatures struct {
Ancestry
ProcessedBy Processors
Features []NamespacedFeature
}
// Layer corresponds to a layer in an image processed by `ProcessedBy`.
type Layer struct {
// Hash is content hash of the layer.
Hash string
}
// LayerWithContent is a layer with its detected namespaces and features by
// ProcessedBy.
type LayerWithContent struct {
Layer
ProcessedBy Processors
Namespaces []Namespace
Features []Feature
}
// Namespace is the contextual information around features.
//
// e.g. Debian:7, NodeJS.
type Namespace struct {
Name string
VersionFormat string
}
// Feature represents a package detected in a layer but the namespace is not
// determined.
//
// e.g. Name: OpenSSL, Version: 1.0, VersionFormat: dpkg.
// dpkg is the version format of the installer package manager, which in this
// case could be dpkg or apk.
type Feature struct {
Name string
Version string
VersionFormat string
}
// NamespacedFeature is a feature with determined namespace and can be affected
// by vulnerabilities.
//
// e.g. OpenSSL 1.0 dpkg Debian:7.
type NamespacedFeature struct {
Feature
Namespace Namespace
}
// AffectedNamespacedFeature is a namespaced feature affected by the
// vulnerabilities with fixed-in versions for this feature.
type AffectedNamespacedFeature struct {
NamespacedFeature
AffectedBy []VulnerabilityWithFixedIn
}
// VulnerabilityWithFixedIn is used for AffectedNamespacedFeature to retrieve
// the affecting vulnerabilities and the fixed-in versions for the feature.
type VulnerabilityWithFixedIn struct {
Vulnerability
FixedInVersion string
}
// AffectedFeature is used to determine whether a namespaced feature is affected
// by a Vulnerability. Namespace and Feature Name is unique. Affected Feature is
// bound to vulnerability.
type AffectedFeature struct {
Namespace Namespace
FeatureName string
// FixedInVersion is known next feature version that's not affected by the
// vulnerability. Empty FixedInVersion means the unaffected version is
// unknown.
FixedInVersion string
// AffectedVersion contains the version range to determine whether or not a
// feature is affected.
AffectedVersion string
}
// VulnerabilityID is an identifier for every vulnerability. Every vulnerability
// has unique namespace and name.
type VulnerabilityID struct {
Name string
Namespace string
}
// Vulnerability represents CVE or similar vulnerability reports.
type Vulnerability struct {
Name string
Namespace Namespace
Description string
Link string
Severity Severity
Metadata MetadataMap
}
// VulnerabilityWithAffected is an vulnerability with all known affected
// features.
type VulnerabilityWithAffected struct {
Vulnerability
Affected []AffectedFeature
}
// PagedVulnerableAncestries is a vulnerability with a page of affected
// ancestries each with a special index attached for streaming purpose. The
// current page number and next page number are for navigate.
type PagedVulnerableAncestries struct {
Vulnerability
// Affected is a map of special indexes to Ancestries, which the pair
// should be unique in a stream. Every indexes in the map should be larger
// than previous page.
Affected map[int]string
Limit int
Current PageNumber
Next PageNumber
// End signals the end of the pages.
End bool
}
// NotificationHook is a message sent to another service to inform of a change
// to a Vulnerability or the Ancestries affected by a Vulnerability. It contains
// the name of a notification that should be read and marked as read via the
// API.
type NotificationHook struct {
Name string
Created time.Time
Notified time.Time
Deleted time.Time
}
// VulnerabilityNotification is a notification for vulnerability changes.
type VulnerabilityNotification struct {
NotificationHook
Old *Vulnerability
New *Vulnerability
}
// VulnerabilityNotificationWithVulnerable is a notification for vulnerability
// changes with vulnerable ancestries.
type VulnerabilityNotificationWithVulnerable struct {
NotificationHook
Old *PagedVulnerableAncestries
New *PagedVulnerableAncestries
}
// PageNumber is used to do pagination.
type PageNumber string
type MetadataMap map[string]interface{}
// NullableAffectedNamespacedFeature is an affectednamespacedfeature with
// whether it's found in datastore.
type NullableAffectedNamespacedFeature struct {
AffectedNamespacedFeature
Valid bool
}
// NullableVulnerability is a vulnerability with whether the vulnerability is
// found in datastore.
type NullableVulnerability struct {
VulnerabilityWithAffected
Valid bool
}
func (mm *MetadataMap) Scan(value interface{}) error {
if value == nil {
return nil
}
// github.com/lib/pq decodes TEXT/VARCHAR fields into strings.
val, ok := value.(string)
if !ok {
panic("got type other than []byte from database")
}
return json.Unmarshal([]byte(val), mm)
}
func (mm *MetadataMap) Value() (driver.Value, error) {
json, err := json.Marshal(*mm)
return string(json), err
}

View file

@ -0,0 +1,49 @@
// Copyright 2015 clair 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 database
// DebianReleasesMapping translates Debian code names and class names to version numbers
var DebianReleasesMapping = map[string]string{
// Code names
"squeeze": "6",
"wheezy": "7",
"jessie": "8",
"stretch": "9",
"buster": "10",
"sid": "unstable",
// Class names
"oldoldstable": "7",
"oldstable": "8",
"stable": "9",
"testing": "10",
"unstable": "unstable",
}
// UbuntuReleasesMapping translates Ubuntu code names to version numbers
var UbuntuReleasesMapping = map[string]string{
"precise": "12.04",
"quantal": "12.10",
"raring": "13.04",
"trusty": "14.04",
"utopic": "14.10",
"vivid": "15.04",
"wily": "15.10",
"xenial": "16.04",
"yakkety": "16.10",
"zesty": "17.04",
"artful": "17.10",
"bionic": "18.04",
}

144
vendor/github.com/coreos/clair/database/severity.go generated vendored Normal file
View file

@ -0,0 +1,144 @@
// Copyright 2017 clair 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 database
import (
"database/sql/driver"
"errors"
"strings"
)
// ErrFailedToParseSeverity is the error returned when a severity could not
// be parsed from a string.
var ErrFailedToParseSeverity = errors.New("failed to parse Severity from input")
// Severity defines a standard scale for measuring the severity of a
// vulnerability.
type Severity string
const (
// UnknownSeverity is either a security problem that has not been assigned to
// a priority yet or a priority that our system did not recognize.
UnknownSeverity Severity = "Unknown"
// NegligibleSeverity is technically a security problem, but is only
// theoretical in nature, requires a very special situation, has almost no
// install base, or does no real damage. These tend not to get backport from
// upstream, and will likely not be included in security updates unless
// there is an easy fix and some other issue causes an update.
NegligibleSeverity Severity = "Negligible"
// LowSeverity is a security problem, but is hard to exploit due to
// environment, requires a user-assisted attack, a small install base, or
// does very little damage. These tend to be included in security updates
// only when higher priority issues require an update, or if many low
// priority issues have built up.
LowSeverity Severity = "Low"
// MediumSeverity is a real security problem, and is exploitable for many
// people. Includes network daemon denial of service attacks, cross-site
// scripting, and gaining user privileges. Updates should be made soon for
// this priority of issue.
MediumSeverity Severity = "Medium"
// HighSeverity is a real problem, exploitable for many people in a default
// installation. Includes serious remote denial of services, local root
// privilege escalations, or data loss.
HighSeverity Severity = "High"
// CriticalSeverity is a world-burning problem, exploitable for nearly all
// people in a default installation of Linux. Includes remote root privilege
// escalations, or massive data loss.
CriticalSeverity Severity = "Critical"
// Defcon1Severity is a Critical problem which has been manually highlighted
// by the team. It requires an immediate attention.
Defcon1Severity Severity = "Defcon1"
)
// Severities lists all known severities, ordered from lowest to highest.
var Severities = []Severity{
UnknownSeverity,
NegligibleSeverity,
LowSeverity,
MediumSeverity,
HighSeverity,
CriticalSeverity,
Defcon1Severity,
}
// NewSeverity attempts to parse a string into a standard Severity value.
func NewSeverity(s string) (Severity, error) {
for _, ss := range Severities {
if strings.EqualFold(s, string(ss)) {
return ss, nil
}
}
return UnknownSeverity, ErrFailedToParseSeverity
}
// Compare determines the equality of two severities.
//
// If the severities are equal, returns 0.
// If the receiver is less, returns -1.
// If the receiver is greater, returns 1.
func (s Severity) Compare(s2 Severity) int {
var i1, i2 int
for i1 = 0; i1 < len(Severities); i1 = i1 + 1 {
if s == Severities[i1] {
break
}
}
for i2 = 0; i2 < len(Severities); i2 = i2 + 1 {
if s2 == Severities[i2] {
break
}
}
return i1 - i2
}
// Scan implements the database/sql.Scanner interface.
func (s *Severity) Scan(value interface{}) error {
val, ok := value.([]byte)
if !ok {
return errors.New("could not scan a Severity from a non-string input")
}
var err error
*s, err = NewSeverity(string(val))
if err != nil {
return err
}
return nil
}
// Value implements the database/sql/driver.Valuer interface.
func (s Severity) Value() (driver.Value, error) {
return string(s), nil
}
// Valid checks if the severity is valid or not.
func (s Severity) Valid() bool {
for _, v := range Severities {
if s == v {
return true
}
}
return false
}

View file

@ -0,0 +1,35 @@
// Copyright 2017 clair 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 database
import (
"testing"
"github.com/stretchr/testify/assert"
)
func TestCompareSeverity(t *testing.T) {
assert.Equal(t, MediumSeverity.Compare(MediumSeverity), 0, "Severity comparison failed")
assert.True(t, MediumSeverity.Compare(HighSeverity) < 0, "Severity comparison failed")
assert.True(t, CriticalSeverity.Compare(LowSeverity) > 0, "Severity comparison failed")
}
func TestParseSeverity(t *testing.T) {
_, err := NewSeverity("Test")
assert.Equal(t, ErrFailedToParseSeverity, err)
_, err = NewSeverity("Unknown")
assert.Nil(t, err)
}

151
vendor/github.com/coreos/clair/ext/versionfmt/driver.go generated vendored Normal file
View file

@ -0,0 +1,151 @@
// Copyright 2016 clair 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 versionfmt exposes functions to dynamically register formats used to
// parse Feature Versions.
package versionfmt
import (
"errors"
"sync"
log "github.com/sirupsen/logrus"
)
const (
// MinVersion is a special package version which is always sorted first.
MinVersion = "#MINV#"
// MaxVersion is a special package version which is always sorted last.
MaxVersion = "#MAXV#"
)
var (
// ErrUnknownVersionFormat is returned when a function does not have enough
// context to determine the format of a version.
ErrUnknownVersionFormat = errors.New("unknown version format")
// ErrInvalidVersion is returned when a function needs to validate a version,
// but should return an error in the case where the version is invalid.
ErrInvalidVersion = errors.New("invalid version")
parsersM sync.Mutex
parsers = make(map[string]Parser)
)
// Parser represents any format that can compare two version strings.
type Parser interface {
// Valid attempts to parse a version string and returns its success.
Valid(string) bool
// Compare parses two different version strings.
// Returns 0 when equal, -1 when a < b, 1 when b < a.
Compare(a, b string) (int, error)
// InRange computes if a is in range of b
//
// NOTE(Sida): For legacy version formats, rangeB is a version and
// always use if versionA < rangeB as threshold.
InRange(versionA, rangeB string) (bool, error)
// GetFixedIn computes a fixed in version for a certain version range.
//
// NOTE(Sida): For legacy version formats, rangeA is a version and
// be returned directly becuase it was considered fixed in version.
GetFixedIn(rangeA string) (string, error)
}
// RegisterParser provides a way to dynamically register an implementation of a
// Parser.
//
// If RegisterParser is called twice with the same name, the name is blank, or
// if the provided Parser is nil, this function panics.
func RegisterParser(name string, p Parser) {
if name == "" {
panic("versionfmt: could not register a Parser with an empty name")
}
if p == nil {
panic("versionfmt: could not register a nil Parser")
}
parsersM.Lock()
defer parsersM.Unlock()
if _, dup := parsers[name]; dup {
panic("versionfmt: RegisterParser called twice for " + name)
}
parsers[name] = p
}
// GetParser returns the registered Parser with a provided name.
func GetParser(name string) (p Parser, exists bool) {
parsersM.Lock()
defer parsersM.Unlock()
p, exists = parsers[name]
return
}
// Valid is a helper function that will return an error if the version fails to
// validate with a given format.
func Valid(format, version string) error {
versionParser, exists := GetParser(format)
if !exists {
return ErrUnknownVersionFormat
}
if !versionParser.Valid(version) {
return ErrInvalidVersion
}
return nil
}
// Compare is a helper function that will compare two versions with a given
// format and return an error if there are any failures.
func Compare(format, versionA, versionB string) (int, error) {
versionParser, exists := GetParser(format)
if !exists {
return 0, ErrUnknownVersionFormat
}
return versionParser.Compare(versionA, versionB)
}
// InRange is a helper function that checks if `versionA` is in `rangeB`
func InRange(format, version, versionRange string) (bool, error) {
versionParser, exists := GetParser(format)
if !exists {
return false, ErrUnknownVersionFormat
}
in, err := versionParser.InRange(version, versionRange)
if err != nil {
log.WithFields(log.Fields{"Format": format, "Version": version, "Range": versionRange}).Error(err)
}
return in, err
}
// GetFixedIn is a helper function that computes the next fixed in version given
// a affected version range `rangeA`.
func GetFixedIn(format, rangeA string) (string, error) {
versionParser, exists := GetParser(format)
if !exists {
return "", ErrUnknownVersionFormat
}
return versionParser.GetFixedIn(rangeA)
}

133
vendor/github.com/coreos/clair/glide.lock generated vendored Normal file
View file

@ -0,0 +1,133 @@
hash: b5b9ebebad30becd361736196a015af23b1d9a616a375c7fc13823121fd17226
updated: 2017-06-05T16:11:29.019891941-04:00
imports:
- name: github.com/beorn7/perks
version: 4c0e84591b9aa9e6dcfdf3e020114cd81f89d5f9
subpackages:
- quantile
- name: github.com/cockroachdb/cmux
version: 30d10be492927e2dcae0089c374c455d42414fcb
- name: github.com/coreos/pkg
version: 3ac0863d7acf3bc44daf49afef8919af12f704ef
subpackages:
- timeutil
- name: github.com/davecgh/go-spew
version: 6d212800a42e8ab5c146b8ace3490ee17e5225f9
subpackages:
- spew
- name: github.com/fernet/fernet-go
version: 1b2437bc582b3cfbb341ee5a29f8ef5b42912ff2
- name: github.com/golang/protobuf
version: 5a0f697c9ed9d68fef0116532c6e05cfeae00e55
subpackages:
- jsonpb
- proto
- protoc-gen-go/descriptor
- ptypes/any
- ptypes/empty
- ptypes/struct
- name: github.com/grpc-ecosystem/go-grpc-prometheus
version: 2500245aa6110c562d17020fb31a2c133d737799
- name: github.com/grpc-ecosystem/grpc-gateway
version: 2a40dd79571b760642c30f62ada35c65ac2b779c
subpackages:
- runtime
- runtime/internal
- utilities
- name: github.com/guregu/null
version: 41961cea0328defc5f95c1c473f89ebf0d1813f6
subpackages:
- zero
- name: github.com/hashicorp/golang-lru
version: 0a025b7e63adc15a622f29b0b2c4c3848243bbf6
subpackages:
- simplelru
- name: github.com/julienschmidt/httprouter
version: 8c199fb6259ffc1af525cc3ad52ee60ba8359669
- name: github.com/lib/pq
version: 8837942c3e09574accbc5f150e2c5e057189cace
subpackages:
- oid
- name: github.com/matttproud/golang_protobuf_extensions
version: c12348ce28de40eed0136aa2b644d0ee0650e56c
subpackages:
- pbutil
- name: github.com/pborman/uuid
version: a97ce2ca70fa5a848076093f05e639a89ca34d06
- name: github.com/pmezard/go-difflib
version: d8ed2627bdf02c080bf22230dbb337003b7aba2d
subpackages:
- difflib
- name: github.com/prometheus/client_golang
version: c5b7fccd204277076155f10851dad72b76a49317
subpackages:
- prometheus
- name: github.com/prometheus/client_model
version: 6f3806018612930941127f2a7c6c453ba2c527d2
subpackages:
- go
- name: github.com/prometheus/common
version: 13ba4ddd0caa9c28ca7b7bffe1dfa9ed8d5ef207
subpackages:
- expfmt
- internal/bitbucket.org/ww/goautoneg
- model
- name: github.com/prometheus/procfs
version: 65c1f6f8f0fc1e2185eb9863a3bc751496404259
subpackages:
- xfs
- name: github.com/remind101/migrate
version: d22d647232c20dbea6d2aa1dda7f2737cccce614
- name: github.com/sirupsen/logrus
version: ba1b36c82c5e05c4f912a88eab0dcd91a171688f
- name: github.com/stretchr/testify
version: 69483b4bd14f5845b5a1e55bca19e954e827f1d0
subpackages:
- assert
- name: github.com/tylerb/graceful
version: 4654dfbb6ad53cb5e27f37d99b02e16c1872fbbb
- name: golang.org/x/net
version: 59a0b19b5533c7977ddeb86b017bf507ed407b12
subpackages:
- context
- http2
- http2/hpack
- idna
- internal/timeseries
- lex/httplex
- trace
- name: golang.org/x/sys
version: b90f89a1e7a9c1f6b918820b3daa7f08488c8594
subpackages:
- unix
- name: golang.org/x/text
version: ccbd3f7822129ff389f8ca4858a9b9d4d910531c
subpackages:
- secure/bidirule
- transform
- unicode/bidi
- unicode/norm
- name: google.golang.org/genproto
version: aa2eb687b4d3e17154372564ad8d6bf11c3cf21f
subpackages:
- googleapis/api/annotations
- googleapis/rpc/status
- name: google.golang.org/grpc
version: 8de2dff78c3b968a51c99ec526d934f686537437
subpackages:
- codes
- credentials
- grpclb/grpc_lb_v1
- grpclog
- internal
- keepalive
- metadata
- naming
- peer
- stats
- status
- tap
- transport
- name: gopkg.in/yaml.v2
version: cd8b52f8269e0feb286dfeef29f8fe4d5b397e0b
testImports: []

32
vendor/github.com/coreos/clair/glide.yaml generated vendored Normal file
View file

@ -0,0 +1,32 @@
package: github.com/coreos/clair
import:
- package: github.com/coreos/pkg
version: ^3.0.0
subpackages:
- timeutil
- package: github.com/fernet/fernet-go
- package: github.com/guregu/null
version: ^3.1.0
subpackages:
- zero
- package: github.com/hashicorp/golang-lru
- package: github.com/julienschmidt/httprouter
version: ^1.1.0
- package: github.com/lib/pq
- package: github.com/pborman/uuid
version: ^1.0.0
- package: github.com/prometheus/client_golang
version: ^0.8.0
subpackages:
- prometheus
- package: github.com/remind101/migrate
- package: github.com/sirupsen/logrus
version: ^0.11.5
- package: github.com/stretchr/testify
version: ^1.1.4
subpackages:
- assert
- package: github.com/tylerb/graceful
version: ^1.2.15
- package: gopkg.in/yaml.v2
- package: github.com/cockroachdb/cmux

251
vendor/github.com/coreos/clair/notifier.go generated vendored Normal file
View file

@ -0,0 +1,251 @@
// Copyright 2017 clair 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 clair
import (
"time"
"github.com/coreos/pkg/timeutil"
"github.com/pborman/uuid"
"github.com/prometheus/client_golang/prometheus"
log "github.com/sirupsen/logrus"
"github.com/coreos/clair/database"
"github.com/coreos/clair/ext/notification"
"github.com/coreos/clair/pkg/stopper"
)
const (
notifierCheckInterval = 5 * time.Minute
notifierMaxBackOff = 15 * time.Minute
notifierLockRefreshDuration = time.Minute * 2
notifierLockDuration = time.Minute*8 + notifierLockRefreshDuration
logSenderName = "sender name"
logNotiName = "notification name"
)
var (
promNotifierLatencyMilliseconds = prometheus.NewHistogram(prometheus.HistogramOpts{
Name: "clair_notifier_latency_milliseconds",
Help: "Time it takes to send a notification after it's been created.",
})
promNotifierBackendErrorsTotal = prometheus.NewCounterVec(prometheus.CounterOpts{
Name: "clair_notifier_backend_errors_total",
Help: "Number of errors that notifier backends generated.",
}, []string{"backend"})
)
func init() {
prometheus.MustRegister(promNotifierLatencyMilliseconds)
prometheus.MustRegister(promNotifierBackendErrorsTotal)
}
// RunNotifier begins a process that checks for new notifications that should
// be sent out to third parties.
func RunNotifier(config *notification.Config, datastore database.Datastore, stopper *stopper.Stopper) {
defer stopper.End()
// Configure registered notifiers.
for senderName, sender := range notification.Senders() {
if configured, err := sender.Configure(config); configured {
log.WithField(logSenderName, senderName).Info("sender configured")
} else {
notification.UnregisterSender(senderName)
if err != nil {
log.WithError(err).WithField(logSenderName, senderName).Error("could not configure notifier")
}
}
}
// Do not run the updater if there is no notifier enabled.
if len(notification.Senders()) == 0 {
log.Info("notifier service is disabled")
return
}
whoAmI := uuid.New()
log.WithField("lock identifier", whoAmI).Info("notifier service started")
for running := true; running; {
// Find task.
notification := findTask(datastore, config.RenotifyInterval, whoAmI, stopper)
if notification == nil {
// Interrupted while finding a task, Clair is stopping.
break
}
// Handle task.
done := make(chan bool, 1)
go func() {
success, interrupted := handleTask(*notification, stopper, config.Attempts)
if success {
err := markNotificationNotified(datastore, notification.Name)
if err != nil {
log.WithError(err).Error("Failed to mark notification notified")
}
promNotifierLatencyMilliseconds.Observe(float64(time.Since(notification.Created).Nanoseconds()) / float64(time.Millisecond))
}
if interrupted {
running = false
}
unlock(datastore, notification.Name, whoAmI)
done <- true
}()
// Refresh task lock until done.
outer:
for {
select {
case <-done:
break outer
case <-time.After(notifierLockRefreshDuration):
lock(datastore, notification.Name, whoAmI, notifierLockDuration, true)
case <-stopper.Chan():
running = false
break
}
}
}
log.Info("notifier service stopped")
}
func findTask(datastore database.Datastore, renotifyInterval time.Duration, whoAmI string, stopper *stopper.Stopper) *database.NotificationHook {
for {
notification, ok, err := findNewNotification(datastore, renotifyInterval)
if err != nil || !ok {
if !ok {
log.WithError(err).Warning("could not get notification to send")
}
// Wait.
if !stopper.Sleep(notifierCheckInterval) {
return nil
}
continue
}
// Lock the notification.
if hasLock, _ := lock(datastore, notification.Name, whoAmI, notifierLockDuration, false); hasLock {
log.WithField(logNotiName, notification.Name).Info("found and locked a notification")
return &notification
}
}
}
func handleTask(n database.NotificationHook, st *stopper.Stopper, maxAttempts int) (bool, bool) {
// Send notification.
for senderName, sender := range notification.Senders() {
var attempts int
var backOff time.Duration
for {
// Max attempts exceeded.
if attempts >= maxAttempts {
log.WithFields(log.Fields{logNotiName: n.Name, logSenderName: senderName, "max attempts": maxAttempts}).Info("giving up on sending notification : max attempts exceeded")
return false, false
}
// Backoff.
if backOff > 0 {
log.WithFields(log.Fields{"duration": backOff, logNotiName: n.Name, logSenderName: senderName, "attempts": attempts + 1, "max attempts": maxAttempts}).Info("waiting before retrying to send notification")
if !st.Sleep(backOff) {
return false, true
}
}
// Send using the current notifier.
if err := sender.Send(n.Name); err != nil {
// Send failed; increase attempts/backoff and retry.
promNotifierBackendErrorsTotal.WithLabelValues(senderName).Inc()
log.WithError(err).WithFields(log.Fields{logSenderName: senderName, logNotiName: n.Name}).Error("could not send notification via notifier")
backOff = timeutil.ExpBackoff(backOff, notifierMaxBackOff)
attempts++
continue
}
// Send has been successful. Go to the next notifier.
break
}
}
log.WithField(logNotiName, n.Name).Info("successfully sent notification")
return true, false
}
func findNewNotification(datastore database.Datastore, renotifyInterval time.Duration) (database.NotificationHook, bool, error) {
tx, err := datastore.Begin()
if err != nil {
return database.NotificationHook{}, false, err
}
defer tx.Rollback()
return tx.FindNewNotification(time.Now().Add(-renotifyInterval))
}
func markNotificationNotified(datastore database.Datastore, name string) error {
tx, err := datastore.Begin()
if err != nil {
log.WithError(err).Error("an error happens when beginning database transaction")
}
defer tx.Rollback()
if err := tx.MarkNotificationNotified(name); err != nil {
return err
}
return tx.Commit()
}
// unlock removes a lock with provided name, owner. Internally, it handles
// database transaction and catches error.
func unlock(datastore database.Datastore, name, owner string) {
tx, err := datastore.Begin()
if err != nil {
return
}
defer tx.Rollback()
if err := tx.Unlock(name, owner); err != nil {
return
}
if err := tx.Commit(); err != nil {
return
}
}
func lock(datastore database.Datastore, name string, owner string, duration time.Duration, renew bool) (bool, time.Time) {
// any error will cause the function to catch the error and return false.
tx, err := datastore.Begin()
if err != nil {
return false, time.Time{}
}
defer tx.Rollback()
locked, t, err := tx.Lock(name, owner, duration, renew)
if err != nil {
return false, time.Time{}
}
if locked {
if err := tx.Commit(); err != nil {
return false, time.Time{}
}
}
return locked, t
}

698
vendor/github.com/coreos/clair/updater.go generated vendored Normal file
View file

@ -0,0 +1,698 @@
// Copyright 2017 clair 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 clair
import (
"fmt"
"math/rand"
"strconv"
"sync"
"time"
"github.com/pborman/uuid"
"github.com/prometheus/client_golang/prometheus"
log "github.com/sirupsen/logrus"
"github.com/coreos/clair/database"
"github.com/coreos/clair/ext/vulnmdsrc"
"github.com/coreos/clair/ext/vulnsrc"
"github.com/coreos/clair/pkg/stopper"
)
const (
updaterLastFlagName = "updater/last"
updaterLockName = "updater"
updaterLockDuration = updaterLockRefreshDuration + time.Minute*2
updaterLockRefreshDuration = time.Minute * 8
updaterSleepBetweenLoopsDuration = time.Minute
)
var (
promUpdaterErrorsTotal = prometheus.NewCounter(prometheus.CounterOpts{
Name: "clair_updater_errors_total",
Help: "Numbers of errors that the updater generated.",
})
promUpdaterDurationSeconds = prometheus.NewGauge(prometheus.GaugeOpts{
Name: "clair_updater_duration_seconds",
Help: "Time it takes to update the vulnerability database.",
})
promUpdaterNotesTotal = prometheus.NewGauge(prometheus.GaugeOpts{
Name: "clair_updater_notes_total",
Help: "Number of notes that the vulnerability fetchers generated.",
})
// EnabledUpdaters contains all updaters to be used for update.
EnabledUpdaters []string
)
func init() {
prometheus.MustRegister(promUpdaterErrorsTotal)
prometheus.MustRegister(promUpdaterDurationSeconds)
prometheus.MustRegister(promUpdaterNotesTotal)
}
// UpdaterConfig is the configuration for the Updater service.
type UpdaterConfig struct {
EnabledUpdaters []string
Interval time.Duration
}
type vulnerabilityChange struct {
old *database.VulnerabilityWithAffected
new *database.VulnerabilityWithAffected
}
// RunUpdater begins a process that updates the vulnerability database at
// regular intervals.
func RunUpdater(config *UpdaterConfig, datastore database.Datastore, st *stopper.Stopper) {
defer st.End()
// Do not run the updater if there is no config or if the interval is 0.
if config == nil || config.Interval == 0 || len(config.EnabledUpdaters) == 0 {
log.Info("updater service is disabled.")
return
}
whoAmI := uuid.New()
log.WithField("lock identifier", whoAmI).Info("updater service started")
for {
var stop bool
// Determine if this is the first update and define the next update time.
// The next update time is (last update time + interval) or now if this is the first update.
nextUpdate := time.Now().UTC()
lastUpdate, firstUpdate, err := GetLastUpdateTime(datastore)
if err != nil {
log.WithError(err).Error("an error occurred while getting the last update time")
nextUpdate = nextUpdate.Add(config.Interval)
} else if !firstUpdate {
nextUpdate = lastUpdate.Add(config.Interval)
}
// If the next update timer is in the past, then try to update.
if nextUpdate.Before(time.Now().UTC()) {
// Attempt to get a lock on the the update.
log.Debug("attempting to obtain update lock")
hasLock, hasLockUntil := lock(datastore, updaterLockName, whoAmI, updaterLockDuration, false)
if hasLock {
// Launch update in a new go routine.
doneC := make(chan bool, 1)
go func() {
update(datastore, firstUpdate)
doneC <- true
}()
for done := false; !done && !stop; {
select {
case <-doneC:
done = true
case <-time.After(updaterLockRefreshDuration):
// Refresh the lock until the update is done.
lock(datastore, updaterLockName, whoAmI, updaterLockDuration, true)
case <-st.Chan():
stop = true
}
}
// Unlock the updater.
unlock(datastore, updaterLockName, whoAmI)
if stop {
break
}
// Sleep for a short duration to prevent pinning the CPU on a
// consistent failure.
if stopped := sleepUpdater(time.Now().Add(updaterSleepBetweenLoopsDuration), st); stopped {
break
}
continue
} else {
lockOwner, lockExpiration, ok, err := findLock(datastore, updaterLockName)
if !ok || err != nil {
log.Debug("update lock is already taken")
nextUpdate = hasLockUntil
} else {
log.WithFields(log.Fields{"lock owner": lockOwner, "lock expiration": lockExpiration}).Debug("update lock is already taken")
nextUpdate = lockExpiration
}
}
}
if stopped := sleepUpdater(nextUpdate, st); stopped {
break
}
}
// Clean resources.
for _, appenders := range vulnmdsrc.Appenders() {
appenders.Clean()
}
for _, updaters := range vulnsrc.Updaters() {
updaters.Clean()
}
log.Info("updater service stopped")
}
// sleepUpdater sleeps the updater for an approximate duration, but remains
// able to be cancelled by a stopper.
func sleepUpdater(approxWakeup time.Time, st *stopper.Stopper) (stopped bool) {
waitUntil := approxWakeup.Add(time.Duration(rand.ExpFloat64()/0.5) * time.Second)
log.WithField("scheduled time", waitUntil).Debug("updater sleeping")
if !waitUntil.Before(time.Now().UTC()) {
if !st.Sleep(waitUntil.Sub(time.Now())) {
return true
}
}
return false
}
// update fetches all the vulnerabilities from the registered fetchers, updates
// vulnerabilities, and updater flags, and logs notes from updaters.
func update(datastore database.Datastore, firstUpdate bool) {
defer setUpdaterDuration(time.Now())
log.Info("updating vulnerabilities")
// Fetch updates.
success, vulnerabilities, flags, notes := fetch(datastore)
// do vulnerability namespacing again to merge potentially duplicated
// vulnerabilities from each updater.
vulnerabilities = doVulnerabilitiesNamespacing(vulnerabilities)
// deduplicate fetched namespaces and store them into database.
nsMap := map[database.Namespace]struct{}{}
for _, vuln := range vulnerabilities {
nsMap[vuln.Namespace] = struct{}{}
}
namespaces := make([]database.Namespace, 0, len(nsMap))
for ns := range nsMap {
namespaces = append(namespaces, ns)
}
if err := persistNamespaces(datastore, namespaces); err != nil {
log.WithError(err).Error("Unable to insert namespaces")
return
}
changes, err := updateVulnerabilities(datastore, vulnerabilities)
defer func() {
if err != nil {
promUpdaterErrorsTotal.Inc()
}
}()
if err != nil {
log.WithError(err).Error("Unable to update vulnerabilities")
return
}
if !firstUpdate {
err = createVulnerabilityNotifications(datastore, changes)
if err != nil {
log.WithError(err).Error("Unable to create notifications")
return
}
}
err = updateUpdaterFlags(datastore, flags)
if err != nil {
log.WithError(err).Error("Unable to update updater flags")
return
}
for _, note := range notes {
log.WithField("note", note).Warning("fetcher note")
}
promUpdaterNotesTotal.Set(float64(len(notes)))
if success {
err = setLastUpdateTime(datastore)
if err != nil {
log.WithError(err).Error("Unable to set last update time")
return
}
}
log.Info("update finished")
}
func setUpdaterDuration(start time.Time) {
promUpdaterDurationSeconds.Set(time.Since(start).Seconds())
}
// fetch get data from the registered fetchers, in parallel.
func fetch(datastore database.Datastore) (bool, []database.VulnerabilityWithAffected, map[string]string, []string) {
var vulnerabilities []database.VulnerabilityWithAffected
var notes []string
status := true
flags := make(map[string]string)
// Fetch updates in parallel.
log.Info("fetching vulnerability updates")
var responseC = make(chan *vulnsrc.UpdateResponse, 0)
numUpdaters := 0
for n, u := range vulnsrc.Updaters() {
if !updaterEnabled(n) {
continue
}
numUpdaters++
go func(name string, u vulnsrc.Updater) {
response, err := u.Update(datastore)
if err != nil {
promUpdaterErrorsTotal.Inc()
log.WithError(err).WithField("updater name", name).Error("an error occurred when fetching update")
status = false
responseC <- nil
return
}
responseC <- &response
log.WithField("updater name", name).Info("finished fetching")
}(n, u)
}
// Collect results of updates.
for i := 0; i < numUpdaters; i++ {
resp := <-responseC
if resp != nil {
vulnerabilities = append(vulnerabilities, doVulnerabilitiesNamespacing(resp.Vulnerabilities)...)
notes = append(notes, resp.Notes...)
if resp.FlagName != "" && resp.FlagValue != "" {
flags[resp.FlagName] = resp.FlagValue
}
}
}
close(responseC)
return status, addMetadata(datastore, vulnerabilities), flags, notes
}
// Add metadata to the specified vulnerabilities using the registered
// MetadataFetchers, in parallel.
func addMetadata(datastore database.Datastore, vulnerabilities []database.VulnerabilityWithAffected) []database.VulnerabilityWithAffected {
if len(vulnmdsrc.Appenders()) == 0 || len(vulnerabilities) == 0 {
return vulnerabilities
}
log.Info("adding metadata to vulnerabilities")
// Add a mutex to each vulnerability to ensure that only one appender at a
// time can modify the vulnerability's Metadata map.
lockableVulnerabilities := make([]*lockableVulnerability, 0, len(vulnerabilities))
for i := 0; i < len(vulnerabilities); i++ {
lockableVulnerabilities = append(lockableVulnerabilities, &lockableVulnerability{
VulnerabilityWithAffected: &vulnerabilities[i],
})
}
var wg sync.WaitGroup
wg.Add(len(vulnmdsrc.Appenders()))
for n, a := range vulnmdsrc.Appenders() {
go func(name string, appender vulnmdsrc.Appender) {
defer wg.Done()
// Build up a metadata cache.
if err := appender.BuildCache(datastore); err != nil {
promUpdaterErrorsTotal.Inc()
log.WithError(err).WithField("appender name", name).Error("an error occurred when loading metadata fetcher")
return
}
// Append vulnerability metadata to each vulnerability.
for _, vulnerability := range lockableVulnerabilities {
appender.Append(vulnerability.Name, vulnerability.appendFunc)
}
// Purge the metadata cache.
appender.PurgeCache()
}(n, a)
}
wg.Wait()
return vulnerabilities
}
// GetLastUpdateTime retrieves the latest successful time of update and whether
// or not it's the first update.
func GetLastUpdateTime(datastore database.Datastore) (time.Time, bool, error) {
tx, err := datastore.Begin()
if err != nil {
return time.Time{}, false, err
}
defer tx.Rollback()
lastUpdateTSS, ok, err := tx.FindKeyValue(updaterLastFlagName)
if err != nil {
return time.Time{}, false, err
}
if !ok {
// This is the first update.
return time.Time{}, true, nil
}
lastUpdateTS, err := strconv.ParseInt(lastUpdateTSS, 10, 64)
if err != nil {
return time.Time{}, false, err
}
return time.Unix(lastUpdateTS, 0).UTC(), false, nil
}
type lockableVulnerability struct {
*database.VulnerabilityWithAffected
sync.Mutex
}
func (lv *lockableVulnerability) appendFunc(metadataKey string, metadata interface{}, severity database.Severity) {
lv.Lock()
defer lv.Unlock()
// If necessary, initialize the metadata map for the vulnerability.
if lv.Metadata == nil {
lv.Metadata = make(map[string]interface{})
}
// Append the metadata.
lv.Metadata[metadataKey] = metadata
// If necessary, provide a severity for the vulnerability.
if lv.Severity == database.UnknownSeverity {
lv.Severity = severity
}
}
// doVulnerabilitiesNamespacing takes Vulnerabilities that don't have a
// Namespace and split them into multiple vulnerabilities that have a Namespace
// and only contains the Affected Features corresponding to their
// Namespace.
//
// It helps simplifying the fetchers that share the same metadata about a
// Vulnerability regardless of their actual namespace (ie. same vulnerability
// information for every version of a distro).
//
// It also validates the vulnerabilities fetched from updaters. If any
// vulnerability is mal-formated, the updater process will continue but will log
// warning.
func doVulnerabilitiesNamespacing(vulnerabilities []database.VulnerabilityWithAffected) []database.VulnerabilityWithAffected {
vulnerabilitiesMap := make(map[string]*database.VulnerabilityWithAffected)
for _, v := range vulnerabilities {
namespacedFeatures := v.Affected
v.Affected = []database.AffectedFeature{}
for _, fv := range namespacedFeatures {
// validate vulnerabilities, throw out the invalid vulnerabilities
if fv.AffectedVersion == "" || fv.FeatureName == "" || fv.Namespace.Name == "" || fv.Namespace.VersionFormat == "" {
log.WithFields(log.Fields{
"Name": fv.FeatureName,
"Affected Version": fv.AffectedVersion,
"Namespace": fv.Namespace.Name + ":" + fv.Namespace.VersionFormat,
}).Warn("Mal-formated affected feature (skipped)")
continue
}
index := fv.Namespace.Name + ":" + v.Name
if vulnerability, ok := vulnerabilitiesMap[index]; !ok {
newVulnerability := v
newVulnerability.Namespace = fv.Namespace
newVulnerability.Affected = []database.AffectedFeature{fv}
vulnerabilitiesMap[index] = &newVulnerability
} else {
vulnerability.Affected = append(vulnerability.Affected, fv)
}
}
}
// Convert map into a slice.
var response []database.VulnerabilityWithAffected
for _, v := range vulnerabilitiesMap {
// throw out invalid vulnerabilities.
if v.Name == "" || !v.Severity.Valid() || v.Namespace.Name == "" || v.Namespace.VersionFormat == "" {
log.WithFields(log.Fields{
"Name": v.Name,
"Severity": v.Severity,
"Namespace": v.Namespace.Name + ":" + v.Namespace.VersionFormat,
}).Warning("Vulnerability is mal-formatted")
continue
}
response = append(response, *v)
}
return response
}
func findLock(datastore database.Datastore, updaterLockName string) (string, time.Time, bool, error) {
tx, err := datastore.Begin()
if err != nil {
log.WithError(err).Error()
}
defer tx.Rollback()
return tx.FindLock(updaterLockName)
}
// updateUpdaterFlags updates the flags specified by updaters, every transaction
// is independent of each other.
func updateUpdaterFlags(datastore database.Datastore, flags map[string]string) error {
for key, value := range flags {
tx, err := datastore.Begin()
if err != nil {
return err
}
defer tx.Rollback()
err = tx.UpdateKeyValue(key, value)
if err != nil {
return err
}
if err = tx.Commit(); err != nil {
return err
}
}
return nil
}
// setLastUpdateTime records the last successful date time in database.
func setLastUpdateTime(datastore database.Datastore) error {
tx, err := datastore.Begin()
if err != nil {
return err
}
defer tx.Rollback()
err = tx.UpdateKeyValue(updaterLastFlagName, strconv.FormatInt(time.Now().UTC().Unix(), 10))
if err != nil {
return err
}
return tx.Commit()
}
// isVulnerabilityChange compares two vulnerabilities by their severity and
// affected features, and return true if they are different.
func isVulnerabilityChanged(a *database.VulnerabilityWithAffected, b *database.VulnerabilityWithAffected) bool {
if a == b {
return false
} else if a != nil && b != nil && a.Severity == b.Severity && len(a.Affected) == len(b.Affected) {
checked := map[string]bool{}
for _, affected := range a.Affected {
checked[affected.Namespace.Name+":"+affected.FeatureName] = false
}
for _, affected := range b.Affected {
key := affected.Namespace.Name + ":" + affected.FeatureName
if visited, ok := checked[key]; !ok || visited {
return true
}
checked[key] = true
}
return false
}
return true
}
// findVulnerabilityChanges finds vulnerability changes from old
// vulnerabilities to new vulnerabilities.
// old and new vulnerabilities should be unique.
func findVulnerabilityChanges(old []database.VulnerabilityWithAffected, new []database.VulnerabilityWithAffected) ([]vulnerabilityChange, error) {
changes := map[database.VulnerabilityID]vulnerabilityChange{}
for i, vuln := range old {
key := database.VulnerabilityID{
Name: vuln.Name,
Namespace: vuln.Namespace.Name,
}
if _, ok := changes[key]; ok {
return nil, fmt.Errorf("duplicated old vulnerability")
}
changes[key] = vulnerabilityChange{old: &old[i]}
}
for i, vuln := range new {
key := database.VulnerabilityID{
Name: vuln.Name,
Namespace: vuln.Namespace.Name,
}
if change, ok := changes[key]; ok {
if isVulnerabilityChanged(change.old, &vuln) {
change.new = &new[i]
changes[key] = change
} else {
delete(changes, key)
}
} else {
changes[key] = vulnerabilityChange{new: &new[i]}
}
}
vulnChange := make([]vulnerabilityChange, 0, len(changes))
for _, change := range changes {
vulnChange = append(vulnChange, change)
}
return vulnChange, nil
}
// createVulnerabilityNotifications makes notifications out of vulnerability
// changes and insert them into database.
func createVulnerabilityNotifications(datastore database.Datastore, changes []vulnerabilityChange) error {
log.WithField("count", len(changes)).Debug("creating vulnerability notifications")
if len(changes) == 0 {
return nil
}
tx, err := datastore.Begin()
if err != nil {
return err
}
defer tx.Rollback()
notifications := make([]database.VulnerabilityNotification, 0, len(changes))
for _, change := range changes {
var oldVuln, newVuln *database.Vulnerability
if change.old != nil {
oldVuln = &change.old.Vulnerability
}
if change.new != nil {
newVuln = &change.new.Vulnerability
}
notifications = append(notifications, database.VulnerabilityNotification{
NotificationHook: database.NotificationHook{
Name: uuid.New(),
Created: time.Now(),
},
Old: oldVuln,
New: newVuln,
})
}
if err := tx.InsertVulnerabilityNotifications(notifications); err != nil {
return err
}
return tx.Commit()
}
// updateVulnerabilities upserts unique vulnerabilities into the database and
// computes vulnerability changes.
func updateVulnerabilities(datastore database.Datastore, vulnerabilities []database.VulnerabilityWithAffected) ([]vulnerabilityChange, error) {
log.WithField("count", len(vulnerabilities)).Debug("updating vulnerabilities")
if len(vulnerabilities) == 0 {
return nil, nil
}
ids := make([]database.VulnerabilityID, 0, len(vulnerabilities))
for _, vuln := range vulnerabilities {
ids = append(ids, database.VulnerabilityID{
Name: vuln.Name,
Namespace: vuln.Namespace.Name,
})
}
tx, err := datastore.Begin()
if err != nil {
return nil, err
}
defer tx.Rollback()
oldVulnNullable, err := tx.FindVulnerabilities(ids)
if err != nil {
return nil, err
}
oldVuln := []database.VulnerabilityWithAffected{}
for _, vuln := range oldVulnNullable {
if vuln.Valid {
oldVuln = append(oldVuln, vuln.VulnerabilityWithAffected)
}
}
changes, err := findVulnerabilityChanges(oldVuln, vulnerabilities)
if err != nil {
return nil, err
}
toRemove := []database.VulnerabilityID{}
toAdd := []database.VulnerabilityWithAffected{}
for _, change := range changes {
if change.old != nil {
toRemove = append(toRemove, database.VulnerabilityID{
Name: change.old.Name,
Namespace: change.old.Namespace.Name,
})
}
if change.new != nil {
toAdd = append(toAdd, *change.new)
}
}
log.WithField("count", len(toRemove)).Debug("marking vulnerabilities as outdated")
if err := tx.DeleteVulnerabilities(toRemove); err != nil {
return nil, err
}
log.WithField("count", len(toAdd)).Debug("inserting new vulnerabilities")
if err := tx.InsertVulnerabilities(toAdd); err != nil {
return nil, err
}
if err := tx.Commit(); err != nil {
return nil, err
}
return changes, nil
}
func updaterEnabled(updaterName string) bool {
for _, u := range EnabledUpdaters {
if u == updaterName {
return true
}
}
return false
}

324
vendor/github.com/coreos/clair/updater_test.go generated vendored Normal file
View file

@ -0,0 +1,324 @@
// Copyright 2017 clair 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 clair
import (
"errors"
"fmt"
"testing"
"github.com/stretchr/testify/assert"
"github.com/coreos/clair/database"
)
type mockUpdaterDatastore struct {
database.MockDatastore
namespaces map[string]database.Namespace
vulnerabilities map[database.VulnerabilityID]database.VulnerabilityWithAffected
vulnNotification map[string]database.VulnerabilityNotification
keyValues map[string]string
}
type mockUpdaterSession struct {
database.MockSession
store *mockUpdaterDatastore
copy mockUpdaterDatastore
terminated bool
}
func copyUpdaterDatastore(md *mockUpdaterDatastore) mockUpdaterDatastore {
namespaces := map[string]database.Namespace{}
for k, n := range md.namespaces {
namespaces[k] = n
}
vulnerabilities := map[database.VulnerabilityID]database.VulnerabilityWithAffected{}
for key, v := range md.vulnerabilities {
newV := v
affected := []database.AffectedFeature{}
for _, f := range v.Affected {
affected = append(affected, f)
}
newV.Affected = affected
vulnerabilities[key] = newV
}
vulnNoti := map[string]database.VulnerabilityNotification{}
for key, v := range md.vulnNotification {
vulnNoti[key] = v
}
kv := map[string]string{}
for key, value := range md.keyValues {
kv[key] = value
}
return mockUpdaterDatastore{
namespaces: namespaces,
vulnerabilities: vulnerabilities,
vulnNotification: vulnNoti,
keyValues: kv,
}
}
func newmockUpdaterDatastore() *mockUpdaterDatastore {
errSessionDone := errors.New("Session Done")
md := &mockUpdaterDatastore{
namespaces: make(map[string]database.Namespace),
vulnerabilities: make(map[database.VulnerabilityID]database.VulnerabilityWithAffected),
vulnNotification: make(map[string]database.VulnerabilityNotification),
keyValues: make(map[string]string),
}
md.FctBegin = func() (database.Session, error) {
session := &mockUpdaterSession{
store: md,
copy: copyUpdaterDatastore(md),
terminated: false,
}
session.FctCommit = func() error {
if session.terminated {
return errSessionDone
}
session.store.namespaces = session.copy.namespaces
session.store.vulnerabilities = session.copy.vulnerabilities
session.store.vulnNotification = session.copy.vulnNotification
session.store.keyValues = session.copy.keyValues
session.terminated = true
return nil
}
session.FctRollback = func() error {
if session.terminated {
return errSessionDone
}
session.terminated = true
session.copy = mockUpdaterDatastore{}
return nil
}
session.FctPersistNamespaces = func(ns []database.Namespace) error {
if session.terminated {
return errSessionDone
}
for _, n := range ns {
_, ok := session.copy.namespaces[n.Name]
if !ok {
session.copy.namespaces[n.Name] = n
}
}
return nil
}
session.FctFindVulnerabilities = func(ids []database.VulnerabilityID) ([]database.NullableVulnerability, error) {
r := []database.NullableVulnerability{}
for _, id := range ids {
vuln, ok := session.copy.vulnerabilities[id]
r = append(r, database.NullableVulnerability{
VulnerabilityWithAffected: vuln,
Valid: ok,
})
}
return r, nil
}
session.FctDeleteVulnerabilities = func(ids []database.VulnerabilityID) error {
for _, id := range ids {
delete(session.copy.vulnerabilities, id)
}
return nil
}
session.FctInsertVulnerabilities = func(vulnerabilities []database.VulnerabilityWithAffected) error {
for _, vuln := range vulnerabilities {
id := database.VulnerabilityID{
Name: vuln.Name,
Namespace: vuln.Namespace.Name,
}
if _, ok := session.copy.vulnerabilities[id]; ok {
return errors.New("Vulnerability already exists")
}
session.copy.vulnerabilities[id] = vuln
}
return nil
}
session.FctUpdateKeyValue = func(key, value string) error {
session.copy.keyValues[key] = value
return nil
}
session.FctFindKeyValue = func(key string) (string, bool, error) {
s, b := session.copy.keyValues[key]
return s, b, nil
}
session.FctInsertVulnerabilityNotifications = func(notifications []database.VulnerabilityNotification) error {
for _, noti := range notifications {
session.copy.vulnNotification[noti.Name] = noti
}
return nil
}
return session, nil
}
return md
}
func TestDoVulnerabilitiesNamespacing(t *testing.T) {
fv1 := database.AffectedFeature{
Namespace: database.Namespace{Name: "Namespace1"},
FeatureName: "Feature1",
FixedInVersion: "0.1",
AffectedVersion: "0.1",
}
fv2 := database.AffectedFeature{
Namespace: database.Namespace{Name: "Namespace2"},
FeatureName: "Feature1",
FixedInVersion: "0.2",
AffectedVersion: "0.2",
}
fv3 := database.AffectedFeature{
Namespace: database.Namespace{Name: "Namespace2"},
FeatureName: "Feature2",
FixedInVersion: "0.3",
AffectedVersion: "0.3",
}
vulnerability := database.VulnerabilityWithAffected{
Vulnerability: database.Vulnerability{
Name: "DoVulnerabilityNamespacing",
},
Affected: []database.AffectedFeature{fv1, fv2, fv3},
}
vulnerabilities := doVulnerabilitiesNamespacing([]database.VulnerabilityWithAffected{vulnerability})
for _, vulnerability := range vulnerabilities {
switch vulnerability.Namespace.Name {
case fv1.Namespace.Name:
assert.Len(t, vulnerability.Affected, 1)
assert.Contains(t, vulnerability.Affected, fv1)
case fv2.Namespace.Name:
assert.Len(t, vulnerability.Affected, 2)
assert.Contains(t, vulnerability.Affected, fv2)
assert.Contains(t, vulnerability.Affected, fv3)
default:
t.Errorf("Should not have a Vulnerability with '%s' as its Namespace.", vulnerability.Namespace.Name)
fmt.Printf("%#v\n", vulnerability)
}
}
}
func TestCreatVulnerabilityNotification(t *testing.T) {
vf1 := "VersionFormat1"
ns1 := database.Namespace{
Name: "namespace 1",
VersionFormat: vf1,
}
af1 := database.AffectedFeature{
Namespace: ns1,
FeatureName: "feature 1",
}
v1 := database.VulnerabilityWithAffected{
Vulnerability: database.Vulnerability{
Name: "vulnerability 1",
Namespace: ns1,
Severity: database.UnknownSeverity,
},
}
// severity change
v2 := database.VulnerabilityWithAffected{
Vulnerability: database.Vulnerability{
Name: "vulnerability 1",
Namespace: ns1,
Severity: database.LowSeverity,
},
}
// affected versions change
v3 := database.VulnerabilityWithAffected{
Vulnerability: database.Vulnerability{
Name: "vulnerability 1",
Namespace: ns1,
Severity: database.UnknownSeverity,
},
Affected: []database.AffectedFeature{af1},
}
datastore := newmockUpdaterDatastore()
change, err := updateVulnerabilities(datastore, []database.VulnerabilityWithAffected{})
assert.Nil(t, err)
assert.Len(t, change, 0)
change, err = updateVulnerabilities(datastore, []database.VulnerabilityWithAffected{v1})
assert.Nil(t, err)
assert.Len(t, change, 1)
assert.Nil(t, change[0].old)
assertVulnerability(t, *change[0].new, v1)
change, err = updateVulnerabilities(datastore, []database.VulnerabilityWithAffected{v1})
assert.Nil(t, err)
assert.Len(t, change, 0)
change, err = updateVulnerabilities(datastore, []database.VulnerabilityWithAffected{v2})
assert.Nil(t, err)
assert.Len(t, change, 1)
assertVulnerability(t, *change[0].new, v2)
assertVulnerability(t, *change[0].old, v1)
change, err = updateVulnerabilities(datastore, []database.VulnerabilityWithAffected{v3})
assert.Nil(t, err)
assert.Len(t, change, 1)
assertVulnerability(t, *change[0].new, v3)
assertVulnerability(t, *change[0].old, v2)
err = createVulnerabilityNotifications(datastore, change)
assert.Nil(t, err)
assert.Len(t, datastore.vulnNotification, 1)
for _, noti := range datastore.vulnNotification {
assert.Equal(t, *noti.New, v3.Vulnerability)
assert.Equal(t, *noti.Old, v2.Vulnerability)
}
}
func assertVulnerability(t *testing.T, expected database.VulnerabilityWithAffected, actual database.VulnerabilityWithAffected) bool {
expectedAF := expected.Affected
actualAF := actual.Affected
expected.Affected, actual.Affected = nil, nil
assert.Equal(t, expected, actual)
assert.Len(t, actualAF, len(expectedAF))
mapAF := map[database.AffectedFeature]bool{}
for _, af := range expectedAF {
mapAF[af] = false
}
for _, af := range actualAF {
if visited, ok := mapAF[af]; !ok || visited {
return false
}
}
return true
}

568
vendor/github.com/coreos/clair/worker.go generated vendored Normal file
View file

@ -0,0 +1,568 @@
// Copyright 2017 clair 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 clair
import (
"errors"
"regexp"
"sync"
log "github.com/sirupsen/logrus"
"github.com/coreos/clair/database"
"github.com/coreos/clair/ext/featurefmt"
"github.com/coreos/clair/ext/featurens"
"github.com/coreos/clair/ext/imagefmt"
"github.com/coreos/clair/pkg/commonerr"
"github.com/coreos/clair/pkg/strutil"
)
const (
logLayerName = "layer"
)
var (
// ErrUnsupported is the error that should be raised when an OS or package
// manager is not supported.
ErrUnsupported = commonerr.NewBadRequestError("worker: OS and/or package manager are not supported")
// ErrParentUnknown is the error that should be raised when a parent layer
// has yet to be processed for the current layer.
ErrParentUnknown = commonerr.NewBadRequestError("worker: parent layer is unknown, it must be processed first")
urlParametersRegexp = regexp.MustCompile(`(\?|\&)([^=]+)\=([^ &]+)`)
// Processors contain the names of namespace detectors and feature listers
// enabled in this instance of Clair.
//
// Processors are initialized during booting and configured in the
// configuration file.
Processors database.Processors
)
type WorkerConfig struct {
EnabledDetectors []string `yaml:"namespace_detectors"`
EnabledListers []string `yaml:"feature_listers"`
}
// LayerRequest represents all information necessary to download and process a
// layer.
type LayerRequest struct {
Hash string
Path string
Headers map[string]string
}
// partialLayer stores layer's content detected by `processedBy` processors.
type partialLayer struct {
hash string
processedBy database.Processors
namespaces []database.Namespace
features []database.Feature
err error
}
// processRequest stores parameters used for processing layers.
type processRequest struct {
request LayerRequest
// notProcessedBy represents a set of processors used to process the
// request.
notProcessedBy database.Processors
}
// cleanURL removes all parameters from an URL.
func cleanURL(str string) string {
return urlParametersRegexp.ReplaceAllString(str, "")
}
// processLayers in parallel processes a set of requests for unique set of layers
// and returns sets of unique namespaces, features and layers to be inserted
// into the database.
func processRequests(imageFormat string, toDetect []processRequest) ([]database.Namespace, []database.Feature, map[string]partialLayer, error) {
wg := &sync.WaitGroup{}
wg.Add(len(toDetect))
results := make([]partialLayer, len(toDetect))
for i := range toDetect {
go func(req *processRequest, res *partialLayer) {
res.hash = req.request.Hash
res.processedBy = req.notProcessedBy
res.namespaces, res.features, res.err = detectContent(imageFormat, req.request.Hash, req.request.Path, req.request.Headers, req.notProcessedBy)
wg.Done()
}(&toDetect[i], &results[i])
}
wg.Wait()
distinctNS := map[database.Namespace]struct{}{}
distinctF := map[database.Feature]struct{}{}
errs := []error{}
for _, r := range results {
errs = append(errs, r.err)
}
if err := commonerr.CombineErrors(errs...); err != nil {
return nil, nil, nil, err
}
updates := map[string]partialLayer{}
for _, r := range results {
for _, ns := range r.namespaces {
distinctNS[ns] = struct{}{}
}
for _, f := range r.features {
distinctF[f] = struct{}{}
}
if _, ok := updates[r.hash]; !ok {
updates[r.hash] = r
} else {
return nil, nil, nil, errors.New("Duplicated updates is not allowed")
}
}
namespaces := make([]database.Namespace, 0, len(distinctNS))
features := make([]database.Feature, 0, len(distinctF))
for ns := range distinctNS {
namespaces = append(namespaces, ns)
}
for f := range distinctF {
features = append(features, f)
}
return namespaces, features, updates, nil
}
func getLayer(datastore database.Datastore, req LayerRequest) (layer database.LayerWithContent, preq *processRequest, err error) {
var ok bool
tx, err := datastore.Begin()
if err != nil {
return
}
defer tx.Rollback()
layer, ok, err = tx.FindLayerWithContent(req.Hash)
if err != nil {
return
}
if !ok {
l := database.Layer{Hash: req.Hash}
err = tx.PersistLayer(l)
if err != nil {
return
}
if err = tx.Commit(); err != nil {
return
}
layer = database.LayerWithContent{Layer: l}
preq = &processRequest{
request: req,
notProcessedBy: Processors,
}
} else {
notProcessed := getNotProcessedBy(layer.ProcessedBy)
if !(len(notProcessed.Detectors) == 0 && len(notProcessed.Listers) == 0 && ok) {
preq = &processRequest{
request: req,
notProcessedBy: notProcessed,
}
}
}
return
}
// processLayers processes a set of post layer requests, stores layers and
// returns an ordered list of processed layers with detected features and
// namespaces.
func processLayers(datastore database.Datastore, imageFormat string, requests []LayerRequest) ([]database.LayerWithContent, error) {
toDetect := []processRequest{}
layers := map[string]database.LayerWithContent{}
for _, req := range requests {
if _, ok := layers[req.Hash]; ok {
continue
}
layer, preq, err := getLayer(datastore, req)
if err != nil {
return nil, err
}
layers[req.Hash] = layer
if preq != nil {
toDetect = append(toDetect, *preq)
}
}
namespaces, features, partialRes, err := processRequests(imageFormat, toDetect)
if err != nil {
return nil, err
}
// Store partial results.
if err := persistNamespaces(datastore, namespaces); err != nil {
return nil, err
}
if err := persistFeatures(datastore, features); err != nil {
return nil, err
}
for _, res := range partialRes {
if err := persistPartialLayer(datastore, res); err != nil {
return nil, err
}
}
// NOTE(Sida): The full layers are computed using partially
// processed layers in current database session. If any other instances of
// Clair are changing some layers in this set of layers, it might generate
// different results especially when the other Clair is with different
// processors.
completeLayers := []database.LayerWithContent{}
for _, req := range requests {
if partialLayer, ok := partialRes[req.Hash]; ok {
completeLayers = append(completeLayers, combineLayers(layers[req.Hash], partialLayer))
} else {
completeLayers = append(completeLayers, layers[req.Hash])
}
}
return completeLayers, nil
}
func persistPartialLayer(datastore database.Datastore, layer partialLayer) error {
tx, err := datastore.Begin()
if err != nil {
return err
}
defer tx.Rollback()
if err := tx.PersistLayerContent(layer.hash, layer.namespaces, layer.features, layer.processedBy); err != nil {
return err
}
return tx.Commit()
}
func persistFeatures(datastore database.Datastore, features []database.Feature) error {
tx, err := datastore.Begin()
if err != nil {
return err
}
defer tx.Rollback()
if err := tx.PersistFeatures(features); err != nil {
return err
}
return tx.Commit()
}
func persistNamespaces(datastore database.Datastore, namespaces []database.Namespace) error {
tx, err := datastore.Begin()
if err != nil {
return err
}
defer tx.Rollback()
if err := tx.PersistNamespaces(namespaces); err != nil {
return err
}
return tx.Commit()
}
// combineLayers merges `layer` and `partial` without duplicated content.
func combineLayers(layer database.LayerWithContent, partial partialLayer) database.LayerWithContent {
mapF := map[database.Feature]struct{}{}
mapNS := map[database.Namespace]struct{}{}
for _, f := range layer.Features {
mapF[f] = struct{}{}
}
for _, ns := range layer.Namespaces {
mapNS[ns] = struct{}{}
}
for _, f := range partial.features {
mapF[f] = struct{}{}
}
for _, ns := range partial.namespaces {
mapNS[ns] = struct{}{}
}
features := make([]database.Feature, 0, len(mapF))
namespaces := make([]database.Namespace, 0, len(mapNS))
for f := range mapF {
features = append(features, f)
}
for ns := range mapNS {
namespaces = append(namespaces, ns)
}
layer.ProcessedBy.Detectors = append(layer.ProcessedBy.Detectors, strutil.CompareStringLists(partial.processedBy.Detectors, layer.ProcessedBy.Detectors)...)
layer.ProcessedBy.Listers = append(layer.ProcessedBy.Listers, strutil.CompareStringLists(partial.processedBy.Listers, layer.ProcessedBy.Listers)...)
return database.LayerWithContent{
Layer: database.Layer{
Hash: layer.Hash,
},
ProcessedBy: layer.ProcessedBy,
Features: features,
Namespaces: namespaces,
}
}
func isAncestryProcessed(datastore database.Datastore, name string) (bool, error) {
tx, err := datastore.Begin()
if err != nil {
return false, err
}
defer tx.Rollback()
_, processed, ok, err := tx.FindAncestry(name)
if err != nil {
return false, err
}
if !ok {
return false, nil
}
notProcessed := getNotProcessedBy(processed)
return len(notProcessed.Detectors) == 0 && len(notProcessed.Listers) == 0, nil
}
// ProcessAncestry downloads and scans an ancestry if it's not scanned by all
// enabled processors in this instance of Clair.
func ProcessAncestry(datastore database.Datastore, imageFormat, name string, layerRequest []LayerRequest) error {
var err error
if name == "" {
return commonerr.NewBadRequestError("could not process a layer which does not have a name")
}
if imageFormat == "" {
return commonerr.NewBadRequestError("could not process a layer which does not have a format")
}
if ok, err := isAncestryProcessed(datastore, name); ok && err == nil {
log.WithField("ancestry", name).Debug("Ancestry is processed")
return nil
} else if err != nil {
return err
}
layers, err := processLayers(datastore, imageFormat, layerRequest)
if err != nil {
return err
}
if !validateProcessors(layers) {
// This error might be triggered because of multiple workers are
// processing the same instance with different processors.
return errors.New("ancestry layers are scanned with different listers and detectors")
}
return processAncestry(datastore, name, layers)
}
func processAncestry(datastore database.Datastore, name string, layers []database.LayerWithContent) error {
ancestryFeatures, err := computeAncestryFeatures(layers)
if err != nil {
return err
}
ancestryLayers := make([]database.Layer, 0, len(layers))
for _, layer := range layers {
ancestryLayers = append(ancestryLayers, layer.Layer)
}
log.WithFields(log.Fields{
"ancestry": name,
"number of features": len(ancestryFeatures),
"processed by": Processors,
"number of layers": len(ancestryLayers),
}).Debug("compute ancestry features")
if err := persistNamespacedFeatures(datastore, ancestryFeatures); err != nil {
return err
}
tx, err := datastore.Begin()
if err != nil {
return err
}
err = tx.UpsertAncestry(database.Ancestry{Name: name, Layers: ancestryLayers}, ancestryFeatures, Processors)
if err != nil {
tx.Rollback()
return err
}
err = tx.Commit()
if err != nil {
return err
}
return nil
}
func persistNamespacedFeatures(datastore database.Datastore, features []database.NamespacedFeature) error {
tx, err := datastore.Begin()
if err != nil {
return err
}
if err := tx.PersistNamespacedFeatures(features); err != nil {
tx.Rollback()
return err
}
if err := tx.Commit(); err != nil {
return err
}
tx, err = datastore.Begin()
if err != nil {
return err
}
if err := tx.CacheAffectedNamespacedFeatures(features); err != nil {
tx.Rollback()
return err
}
return tx.Commit()
}
// validateProcessors checks if the layers processed by same set of processors.
func validateProcessors(layers []database.LayerWithContent) bool {
if len(layers) == 0 {
return true
}
detectors := layers[0].ProcessedBy.Detectors
listers := layers[0].ProcessedBy.Listers
for _, l := range layers[1:] {
if len(strutil.CompareStringLists(detectors, l.ProcessedBy.Detectors)) != 0 ||
len(strutil.CompareStringLists(listers, l.ProcessedBy.Listers)) != 0 {
return false
}
}
return true
}
// computeAncestryFeatures computes the features in an ancestry based on all
// layers.
func computeAncestryFeatures(ancestryLayers []database.LayerWithContent) ([]database.NamespacedFeature, error) {
// version format -> namespace
namespaces := map[string]database.Namespace{}
// version format -> feature ID -> feature
features := map[string]map[string]database.NamespacedFeature{}
for _, layer := range ancestryLayers {
// At start of the loop, namespaces and features always contain the
// previous layer's result.
for _, ns := range layer.Namespaces {
namespaces[ns.VersionFormat] = ns
}
// version format -> feature ID -> feature
currentFeatures := map[string]map[string]database.NamespacedFeature{}
for _, f := range layer.Features {
if ns, ok := namespaces[f.VersionFormat]; ok {
var currentMap map[string]database.NamespacedFeature
if currentMap, ok = currentFeatures[f.VersionFormat]; !ok {
currentFeatures[f.VersionFormat] = make(map[string]database.NamespacedFeature)
currentMap = currentFeatures[f.VersionFormat]
}
inherited := false
if mapF, ok := features[f.VersionFormat]; ok {
if parentFeature, ok := mapF[f.Name+":"+f.Version]; ok {
currentMap[f.Name+":"+f.Version] = parentFeature
inherited = true
}
}
if !inherited {
currentMap[f.Name+":"+f.Version] = database.NamespacedFeature{
Feature: f,
Namespace: ns,
}
}
} else {
return nil, errors.New("No corresponding version format")
}
}
// NOTE(Sida): we update the feature map in some version format
// only if there's at least one feature with that version format. This
// approach won't differentiate feature file removed vs all detectable
// features removed from that file vs feature file not changed.
//
// One way to differentiate (feature file removed or not changed) vs
// all detectable features removed is to pass in the file status.
for vf, mapF := range currentFeatures {
features[vf] = mapF
}
}
ancestryFeatures := []database.NamespacedFeature{}
for _, featureMap := range features {
for _, feature := range featureMap {
ancestryFeatures = append(ancestryFeatures, feature)
}
}
return ancestryFeatures, nil
}
// getNotProcessedBy returns a processors, which contains the detectors and
// listers not in `processedBy` but implemented in the current clair instance.
func getNotProcessedBy(processedBy database.Processors) database.Processors {
notProcessedLister := strutil.CompareStringLists(Processors.Listers, processedBy.Listers)
notProcessedDetector := strutil.CompareStringLists(Processors.Detectors, processedBy.Detectors)
return database.Processors{
Listers: notProcessedLister,
Detectors: notProcessedDetector,
}
}
// detectContent downloads a layer and detects all features and namespaces.
func detectContent(imageFormat, name, path string, headers map[string]string, toProcess database.Processors) (namespaces []database.Namespace, featureVersions []database.Feature, err error) {
log.WithFields(log.Fields{"Hash": name}).Debug("Process Layer")
totalRequiredFiles := append(featurefmt.RequiredFilenames(toProcess.Listers), featurens.RequiredFilenames(toProcess.Detectors)...)
files, err := imagefmt.Extract(imageFormat, path, headers, totalRequiredFiles)
if err != nil {
log.WithError(err).WithFields(log.Fields{
logLayerName: name,
"path": cleanURL(path),
}).Error("failed to extract data from path")
return
}
namespaces, err = featurens.Detect(files, toProcess.Detectors)
if err != nil {
return
}
if len(featureVersions) > 0 {
log.WithFields(log.Fields{logLayerName: name, "count": len(namespaces)}).Debug("detected layer namespaces")
}
featureVersions, err = featurefmt.ListFeatures(files, toProcess.Listers)
if err != nil {
return
}
if len(featureVersions) > 0 {
log.WithFields(log.Fields{logLayerName: name, "count": len(featureVersions)}).Debug("detected layer features")
}
return
}

640
vendor/github.com/coreos/clair/worker_test.go generated vendored Normal file
View file

@ -0,0 +1,640 @@
// Copyright 2017 clair 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 clair
import (
"errors"
"path/filepath"
"runtime"
"strings"
"testing"
"github.com/stretchr/testify/assert"
"github.com/coreos/clair/database"
"github.com/coreos/clair/ext/featurefmt"
"github.com/coreos/clair/ext/featurens"
"github.com/coreos/clair/ext/versionfmt/dpkg"
"github.com/coreos/clair/pkg/strutil"
// Register the required detectors.
_ "github.com/coreos/clair/ext/featurefmt/dpkg"
_ "github.com/coreos/clair/ext/featurefmt/rpm"
_ "github.com/coreos/clair/ext/featurens/aptsources"
_ "github.com/coreos/clair/ext/featurens/osrelease"
_ "github.com/coreos/clair/ext/imagefmt/docker"
)
type mockDatastore struct {
database.MockDatastore
layers map[string]database.LayerWithContent
ancestry map[string]database.AncestryWithFeatures
namespaces map[string]database.Namespace
features map[string]database.Feature
namespacedFeatures map[string]database.NamespacedFeature
}
type mockSession struct {
database.MockSession
store *mockDatastore
copy mockDatastore
terminated bool
}
func copyDatastore(md *mockDatastore) mockDatastore {
layers := map[string]database.LayerWithContent{}
for k, l := range md.layers {
features := append([]database.Feature(nil), l.Features...)
namespaces := append([]database.Namespace(nil), l.Namespaces...)
listers := append([]string(nil), l.ProcessedBy.Listers...)
detectors := append([]string(nil), l.ProcessedBy.Detectors...)
layers[k] = database.LayerWithContent{
Layer: database.Layer{
Hash: l.Hash,
},
ProcessedBy: database.Processors{
Listers: listers,
Detectors: detectors,
},
Features: features,
Namespaces: namespaces,
}
}
ancestry := map[string]database.AncestryWithFeatures{}
for k, a := range md.ancestry {
nf := append([]database.NamespacedFeature(nil), a.Features...)
l := append([]database.Layer(nil), a.Layers...)
listers := append([]string(nil), a.ProcessedBy.Listers...)
detectors := append([]string(nil), a.ProcessedBy.Detectors...)
ancestry[k] = database.AncestryWithFeatures{
Ancestry: database.Ancestry{
Name: a.Name,
Layers: l,
},
ProcessedBy: database.Processors{
Detectors: detectors,
Listers: listers,
},
Features: nf,
}
}
namespaces := map[string]database.Namespace{}
for k, n := range md.namespaces {
namespaces[k] = n
}
features := map[string]database.Feature{}
for k, f := range md.features {
features[k] = f
}
namespacedFeatures := map[string]database.NamespacedFeature{}
for k, f := range md.namespacedFeatures {
namespacedFeatures[k] = f
}
return mockDatastore{
layers: layers,
ancestry: ancestry,
namespaces: namespaces,
namespacedFeatures: namespacedFeatures,
features: features,
}
}
func newMockDatastore() *mockDatastore {
errSessionDone := errors.New("Session Done")
md := &mockDatastore{
layers: make(map[string]database.LayerWithContent),
ancestry: make(map[string]database.AncestryWithFeatures),
namespaces: make(map[string]database.Namespace),
features: make(map[string]database.Feature),
namespacedFeatures: make(map[string]database.NamespacedFeature),
}
md.FctBegin = func() (database.Session, error) {
session := &mockSession{
store: md,
copy: copyDatastore(md),
terminated: false,
}
session.FctCommit = func() error {
if session.terminated {
return nil
}
session.store.layers = session.copy.layers
session.store.ancestry = session.copy.ancestry
session.store.namespaces = session.copy.namespaces
session.store.features = session.copy.features
session.store.namespacedFeatures = session.copy.namespacedFeatures
session.terminated = true
return nil
}
session.FctRollback = func() error {
if session.terminated {
return nil
}
session.terminated = true
session.copy = mockDatastore{}
return nil
}
session.FctFindAncestry = func(name string) (database.Ancestry, database.Processors, bool, error) {
processors := database.Processors{}
if session.terminated {
return database.Ancestry{}, processors, false, errSessionDone
}
ancestry, ok := session.copy.ancestry[name]
return ancestry.Ancestry, ancestry.ProcessedBy, ok, nil
}
session.FctFindLayer = func(name string) (database.Layer, database.Processors, bool, error) {
processors := database.Processors{}
if session.terminated {
return database.Layer{}, processors, false, errSessionDone
}
layer, ok := session.copy.layers[name]
return layer.Layer, layer.ProcessedBy, ok, nil
}
session.FctFindLayerWithContent = func(name string) (database.LayerWithContent, bool, error) {
if session.terminated {
return database.LayerWithContent{}, false, errSessionDone
}
layer, ok := session.copy.layers[name]
return layer, ok, nil
}
session.FctPersistLayer = func(layer database.Layer) error {
if session.terminated {
return errSessionDone
}
if _, ok := session.copy.layers[layer.Hash]; !ok {
session.copy.layers[layer.Hash] = database.LayerWithContent{Layer: layer}
}
return nil
}
session.FctPersistNamespaces = func(ns []database.Namespace) error {
if session.terminated {
return errSessionDone
}
for _, n := range ns {
_, ok := session.copy.namespaces[n.Name]
if !ok {
session.copy.namespaces[n.Name] = n
}
}
return nil
}
session.FctPersistFeatures = func(fs []database.Feature) error {
if session.terminated {
return errSessionDone
}
for _, f := range fs {
key := FeatureKey(&f)
_, ok := session.copy.features[key]
if !ok {
session.copy.features[key] = f
}
}
return nil
}
session.FctPersistLayerContent = func(hash string, namespaces []database.Namespace, features []database.Feature, processedBy database.Processors) error {
if session.terminated {
return errSessionDone
}
// update the layer
layer, ok := session.copy.layers[hash]
if !ok {
return errors.New("layer not found")
}
layerFeatures := map[string]database.Feature{}
layerNamespaces := map[string]database.Namespace{}
for _, f := range layer.Features {
layerFeatures[FeatureKey(&f)] = f
}
for _, n := range layer.Namespaces {
layerNamespaces[n.Name] = n
}
// ensure that all the namespaces, features are in the database
for _, ns := range namespaces {
if _, ok := session.copy.namespaces[ns.Name]; !ok {
return errors.New("Namespaces should be in the database")
}
if _, ok := layerNamespaces[ns.Name]; !ok {
layer.Namespaces = append(layer.Namespaces, ns)
layerNamespaces[ns.Name] = ns
}
}
for _, f := range features {
if _, ok := session.copy.features[FeatureKey(&f)]; !ok {
return errors.New("Namespaces should be in the database")
}
if _, ok := layerFeatures[FeatureKey(&f)]; !ok {
layer.Features = append(layer.Features, f)
layerFeatures[FeatureKey(&f)] = f
}
}
layer.ProcessedBy.Detectors = append(layer.ProcessedBy.Detectors, strutil.CompareStringLists(processedBy.Detectors, layer.ProcessedBy.Detectors)...)
layer.ProcessedBy.Listers = append(layer.ProcessedBy.Listers, strutil.CompareStringLists(processedBy.Listers, layer.ProcessedBy.Listers)...)
session.copy.layers[hash] = layer
return nil
}
session.FctUpsertAncestry = func(ancestry database.Ancestry, features []database.NamespacedFeature, processors database.Processors) error {
if session.terminated {
return errSessionDone
}
// ensure features are in the database
for _, f := range features {
if _, ok := session.copy.namespacedFeatures[NamespacedFeatureKey(&f)]; !ok {
return errors.New("namepsaced feature not in db")
}
}
ancestryWFeature := database.AncestryWithFeatures{
Ancestry: ancestry,
Features: features,
ProcessedBy: processors,
}
session.copy.ancestry[ancestry.Name] = ancestryWFeature
return nil
}
session.FctPersistNamespacedFeatures = func(namespacedFeatures []database.NamespacedFeature) error {
for i, f := range namespacedFeatures {
session.copy.namespacedFeatures[NamespacedFeatureKey(&f)] = namespacedFeatures[i]
}
return nil
}
session.FctCacheAffectedNamespacedFeatures = func(namespacedFeatures []database.NamespacedFeature) error {
// The function does nothing because we don't care about the vulnerability cache in worker_test.
return nil
}
return session, nil
}
return md
}
func TestMain(m *testing.M) {
Processors = database.Processors{
Listers: featurefmt.ListListers(),
Detectors: featurens.ListDetectors(),
}
m.Run()
}
func FeatureKey(f *database.Feature) string {
return strings.Join([]string{f.Name, f.VersionFormat, f.Version}, "__")
}
func NamespacedFeatureKey(f *database.NamespacedFeature) string {
return strings.Join([]string{f.Name, f.Namespace.Name}, "__")
}
func TestProcessAncestryWithDistUpgrade(t *testing.T) {
// Create the list of Features that should not been upgraded from one layer to another.
nonUpgradedFeatures := []database.Feature{
{Name: "libtext-wrapi18n-perl", Version: "0.06-7"},
{Name: "libtext-charwidth-perl", Version: "0.04-7"},
{Name: "libtext-iconv-perl", Version: "1.7-5"},
{Name: "mawk", Version: "1.3.3-17"},
{Name: "insserv", Version: "1.14.0-5"},
{Name: "db", Version: "5.1.29-5"},
{Name: "ustr", Version: "1.0.4-3"},
{Name: "xz-utils", Version: "5.1.1alpha+20120614-2"},
}
nonUpgradedMap := map[database.Feature]struct{}{}
for _, f := range nonUpgradedFeatures {
f.VersionFormat = "dpkg"
nonUpgradedMap[f] = struct{}{}
}
// Process test layers.
//
// blank.tar: MAINTAINER Quentin MACHU <quentin.machu.fr>
// wheezy.tar: FROM debian:wheezy
// jessie.tar: RUN sed -i "s/precise/trusty/" /etc/apt/sources.list && apt-get update &&
// apt-get -y dist-upgrade
_, f, _, _ := runtime.Caller(0)
testDataPath := filepath.Join(filepath.Dir(f)) + "/testdata/DistUpgrade/"
datastore := newMockDatastore()
layers := []LayerRequest{
{Hash: "blank", Path: testDataPath + "blank.tar.gz"},
{Hash: "wheezy", Path: testDataPath + "wheezy.tar.gz"},
{Hash: "jessie", Path: testDataPath + "jessie.tar.gz"},
}
assert.Nil(t, ProcessAncestry(datastore, "Docker", "Mock", layers))
// check the ancestry features
assert.Len(t, datastore.ancestry["Mock"].Features, 74)
for _, f := range datastore.ancestry["Mock"].Features {
if _, ok := nonUpgradedMap[f.Feature]; ok {
assert.Equal(t, "debian:7", f.Namespace.Name)
} else {
assert.Equal(t, "debian:8", f.Namespace.Name)
}
}
assert.Equal(t, []database.Layer{
{Hash: "blank"},
{Hash: "wheezy"},
{Hash: "jessie"},
}, datastore.ancestry["Mock"].Layers)
}
func TestProcessLayers(t *testing.T) {
_, f, _, _ := runtime.Caller(0)
testDataPath := filepath.Join(filepath.Dir(f)) + "/testdata/DistUpgrade/"
datastore := newMockDatastore()
layers := []LayerRequest{
{Hash: "blank", Path: testDataPath + "blank.tar.gz"},
{Hash: "wheezy", Path: testDataPath + "wheezy.tar.gz"},
{Hash: "jessie", Path: testDataPath + "jessie.tar.gz"},
}
processedLayers, err := processLayers(datastore, "Docker", layers)
assert.Nil(t, err)
assert.Len(t, processedLayers, 3)
// ensure resubmit won't break the stuff
processedLayers, err = processLayers(datastore, "Docker", layers)
assert.Nil(t, err)
assert.Len(t, processedLayers, 3)
// Ensure each processed layer is correct
assert.Len(t, processedLayers[0].Namespaces, 0)
assert.Len(t, processedLayers[1].Namespaces, 1)
assert.Len(t, processedLayers[2].Namespaces, 1)
assert.Len(t, processedLayers[0].Features, 0)
assert.Len(t, processedLayers[1].Features, 52)
assert.Len(t, processedLayers[2].Features, 74)
// Ensure each layer has expected namespaces and features detected
if blank, ok := datastore.layers["blank"]; ok {
assert.Equal(t, blank.ProcessedBy.Detectors, Processors.Detectors)
assert.Equal(t, blank.ProcessedBy.Listers, Processors.Listers)
assert.Len(t, blank.Namespaces, 0)
assert.Len(t, blank.Features, 0)
} else {
assert.Fail(t, "blank is not stored")
return
}
if wheezy, ok := datastore.layers["wheezy"]; ok {
assert.Equal(t, wheezy.ProcessedBy.Detectors, Processors.Detectors)
assert.Equal(t, wheezy.ProcessedBy.Listers, Processors.Listers)
assert.Equal(t, wheezy.Namespaces, []database.Namespace{{Name: "debian:7", VersionFormat: dpkg.ParserName}})
assert.Len(t, wheezy.Features, 52)
} else {
assert.Fail(t, "wheezy is not stored")
return
}
if jessie, ok := datastore.layers["jessie"]; ok {
assert.Equal(t, jessie.ProcessedBy.Detectors, Processors.Detectors)
assert.Equal(t, jessie.ProcessedBy.Listers, Processors.Listers)
assert.Equal(t, jessie.Namespaces, []database.Namespace{{Name: "debian:8", VersionFormat: dpkg.ParserName}})
assert.Len(t, jessie.Features, 74)
} else {
assert.Fail(t, "jessie is not stored")
return
}
}
// TestUpgradeClair checks if a clair is upgraded and certain ancestry's
// features should not change. We assume that Clair should only upgrade
func TestClairUpgrade(t *testing.T) {
_, f, _, _ := runtime.Caller(0)
testDataPath := filepath.Join(filepath.Dir(f)) + "/testdata/DistUpgrade/"
datastore := newMockDatastore()
// suppose there are two ancestries.
layers := []LayerRequest{
{Hash: "blank", Path: testDataPath + "blank.tar.gz"},
{Hash: "wheezy", Path: testDataPath + "wheezy.tar.gz"},
{Hash: "jessie", Path: testDataPath + "jessie.tar.gz"},
}
layers2 := []LayerRequest{
{Hash: "blank", Path: testDataPath + "blank.tar.gz"},
{Hash: "wheezy", Path: testDataPath + "wheezy.tar.gz"},
}
// Suppose user scan an ancestry with an old instance of Clair.
Processors = database.Processors{
Detectors: []string{"os-release"},
Listers: []string{"rpm"},
}
assert.Nil(t, ProcessAncestry(datastore, "Docker", "Mock", layers))
assert.Len(t, datastore.ancestry["Mock"].Features, 0)
assert.Nil(t, ProcessAncestry(datastore, "Docker", "Mock2", layers2))
assert.Len(t, datastore.ancestry["Mock2"].Features, 0)
// Clair is upgraded to use a new namespace detector. The expected
// behavior is that all layers will be rescanned with "apt-sources" and
// the ancestry's features are recalculated.
Processors = database.Processors{
Detectors: []string{"os-release", "apt-sources"},
Listers: []string{"rpm"},
}
// Even though Clair processors are upgraded, the ancestry's features should
// not be upgraded without posting the ancestry to Clair again.
assert.Nil(t, ProcessAncestry(datastore, "Docker", "Mock", layers))
assert.Len(t, datastore.ancestry["Mock"].Features, 0)
// Clair is upgraded to use a new feature lister. The expected behavior is
// that all layers will be rescanned with "dpkg" and the ancestry's features
// are invalidated and recalculated.
Processors = database.Processors{
Detectors: []string{"os-release", "apt-sources"},
Listers: []string{"rpm", "dpkg"},
}
assert.Nil(t, ProcessAncestry(datastore, "Docker", "Mock", layers))
assert.Len(t, datastore.ancestry["Mock"].Features, 74)
assert.Nil(t, ProcessAncestry(datastore, "Docker", "Mock2", layers2))
assert.Len(t, datastore.ancestry["Mock2"].Features, 52)
// check the namespaces are correct
for _, f := range datastore.ancestry["Mock"].Features {
if !assert.NotEqual(t, database.Namespace{}, f.Namespace) {
assert.Fail(t, "Every feature should have a namespace attached")
}
}
for _, f := range datastore.ancestry["Mock2"].Features {
if !assert.NotEqual(t, database.Namespace{}, f.Namespace) {
assert.Fail(t, "Every feature should have a namespace attached")
}
}
}
// TestMultipleNamespaces tests computing ancestry features
func TestComputeAncestryFeatures(t *testing.T) {
vf1 := "format 1"
vf2 := "format 2"
ns1a := database.Namespace{
Name: "namespace 1:a",
VersionFormat: vf1,
}
ns1b := database.Namespace{
Name: "namespace 1:b",
VersionFormat: vf1,
}
ns2a := database.Namespace{
Name: "namespace 2:a",
VersionFormat: vf2,
}
ns2b := database.Namespace{
Name: "namespace 2:b",
VersionFormat: vf2,
}
f1 := database.Feature{
Name: "feature 1",
Version: "0.1",
VersionFormat: vf1,
}
f2 := database.Feature{
Name: "feature 2",
Version: "0.2",
VersionFormat: vf1,
}
f3 := database.Feature{
Name: "feature 1",
Version: "0.3",
VersionFormat: vf2,
}
f4 := database.Feature{
Name: "feature 2",
Version: "0.3",
VersionFormat: vf2,
}
// Suppose Clair is watching two files for namespaces one containing ns1
// changes e.g. os-release and the other one containing ns2 changes e.g.
// node.
blank := database.LayerWithContent{Layer: database.Layer{Hash: "blank"}}
initNS1a := database.LayerWithContent{
Layer: database.Layer{Hash: "init ns1a"},
Namespaces: []database.Namespace{ns1a},
Features: []database.Feature{f1, f2},
}
upgradeNS2b := database.LayerWithContent{
Layer: database.Layer{Hash: "upgrade ns2b"},
Namespaces: []database.Namespace{ns2b},
}
upgradeNS1b := database.LayerWithContent{
Layer: database.Layer{Hash: "upgrade ns1b"},
Namespaces: []database.Namespace{ns1b},
Features: []database.Feature{f1, f2},
}
initNS2a := database.LayerWithContent{
Layer: database.Layer{Hash: "init ns2a"},
Namespaces: []database.Namespace{ns2a},
Features: []database.Feature{f3, f4},
}
removeF2 := database.LayerWithContent{
Layer: database.Layer{Hash: "remove f2"},
Features: []database.Feature{f1},
}
// blank -> ns1:a, f1 f2 (init)
// -> f1 (feature change)
// -> ns2:a, f3, f4 (init ns2a)
// -> ns2:b (ns2 upgrade without changing features)
// -> blank (empty)
// -> ns1:b, f1 f2 (ns1 upgrade and add f2)
// -> f1 (remove f2)
// -> blank (empty)
layers := []database.LayerWithContent{
blank,
initNS1a,
removeF2,
initNS2a,
upgradeNS2b,
blank,
upgradeNS1b,
removeF2,
blank,
}
expected := map[database.NamespacedFeature]bool{
{
Feature: f1,
Namespace: ns1a,
}: false,
{
Feature: f3,
Namespace: ns2a,
}: false,
{
Feature: f4,
Namespace: ns2a,
}: false,
}
features, err := computeAncestryFeatures(layers)
assert.Nil(t, err)
for _, f := range features {
if assert.Contains(t, expected, f) {
if assert.False(t, expected[f]) {
expected[f] = true
}
}
}
for f, visited := range expected {
assert.True(t, visited, "expected feature is missing : "+f.Namespace.Name+":"+f.Name)
}
}

View file

@ -29,6 +29,7 @@
"justincormack",
"silvin-lubecki",
"stevvooe",
"thajeztah",
"tibor",
"tonistiigi",
"vdemeester",

View file

@ -12,9 +12,9 @@ import (
"github.com/docker/cli/cli/config/configfile"
"github.com/docker/cli/cli/config/credentials"
"github.com/docker/docker/pkg/homedir"
"github.com/gotestyourself/gotestyourself/assert"
is "github.com/gotestyourself/gotestyourself/assert/cmp"
"github.com/pkg/errors"
"gotest.tools/assert"
is "gotest.tools/assert/cmp"
)
func setupConfigDir(t *testing.T) (string, func()) {

View file

@ -6,8 +6,8 @@ import (
"github.com/docker/cli/cli/config/credentials"
"github.com/docker/docker/api/types"
"github.com/gotestyourself/gotestyourself/assert"
is "github.com/gotestyourself/gotestyourself/assert/cmp"
"gotest.tools/assert"
is "gotest.tools/assert/cmp"
)
func TestEncodeAuth(t *testing.T) {

View file

@ -4,8 +4,8 @@ import (
"testing"
"github.com/docker/docker/api/types"
"github.com/gotestyourself/gotestyourself/assert"
is "github.com/gotestyourself/gotestyourself/assert/cmp"
"gotest.tools/assert"
is "gotest.tools/assert/cmp"
)
type fakeStore struct {

View file

@ -11,9 +11,9 @@ import (
"github.com/docker/docker-credential-helpers/client"
"github.com/docker/docker-credential-helpers/credentials"
"github.com/docker/docker/api/types"
"github.com/gotestyourself/gotestyourself/assert"
is "github.com/gotestyourself/gotestyourself/assert/cmp"
"github.com/pkg/errors"
"gotest.tools/assert"
is "gotest.tools/assert/cmp"
)
const (

View file

@ -5,8 +5,8 @@ import (
"io/ioutil"
"testing"
"github.com/gotestyourself/gotestyourself/assert"
"github.com/spf13/cobra"
"gotest.tools/assert"
)
func TestRequiresNoArgs(t *testing.T) {

View file

@ -4,8 +4,8 @@ import (
"testing"
"time"
"github.com/gotestyourself/gotestyourself/assert"
is "github.com/gotestyourself/gotestyourself/assert/cmp"
"gotest.tools/assert"
is "gotest.tools/assert/cmp"
)
func TestDurationOptString(t *testing.T) {

View file

@ -5,8 +5,8 @@ import (
"testing"
mounttypes "github.com/docker/docker/api/types/mount"
"github.com/gotestyourself/gotestyourself/assert"
is "github.com/gotestyourself/gotestyourself/assert/cmp"
"gotest.tools/assert"
is "gotest.tools/assert/cmp"
)
func TestMountOptString(t *testing.T) {

View file

@ -3,8 +3,8 @@ package opts
import (
"testing"
"github.com/gotestyourself/gotestyourself/assert"
is "github.com/gotestyourself/gotestyourself/assert/cmp"
"gotest.tools/assert"
is "gotest.tools/assert/cmp"
)
func TestNetworkOptLegacySyntax(t *testing.T) {

View file

@ -4,8 +4,8 @@ import (
"testing"
"github.com/docker/docker/api/types/swarm"
"github.com/gotestyourself/gotestyourself/assert"
is "github.com/gotestyourself/gotestyourself/assert/cmp"
"gotest.tools/assert"
is "gotest.tools/assert/cmp"
)
func TestPortOptValidSimpleSyntax(t *testing.T) {

View file

@ -3,8 +3,8 @@ package opts
import (
"testing"
"github.com/gotestyourself/gotestyourself/assert"
is "github.com/gotestyourself/gotestyourself/assert/cmp"
"gotest.tools/assert"
is "gotest.tools/assert/cmp"
)
func TestQuotedStringSetWithQuotes(t *testing.T) {

View file

@ -4,8 +4,8 @@ import (
"os"
"testing"
"github.com/gotestyourself/gotestyourself/assert"
is "github.com/gotestyourself/gotestyourself/assert/cmp"
"gotest.tools/assert"
is "gotest.tools/assert/cmp"
)
func TestSecretOptionsSimple(t *testing.T) {

View file

@ -6,7 +6,7 @@ github.com/coreos/etcd v3.2.1
github.com/cpuguy83/go-md2man v1.0.8
github.com/davecgh/go-spew 346938d642f2ec3594ed81d874461961cd0faa76
github.com/docker/distribution 83389a148052d74ac602f5f1d62f86ff2f3c4aa5
github.com/docker/docker d37f5c6bdf788a6cb82c07fb707e31a240eff5f9
github.com/docker/docker 162ba6016def672690ee4a1f3978368853a1e149
github.com/docker/docker-credential-helpers 3c90bd29a46b943b2a9842987b58fb91a7c1819b
# the docker/go package contains a customized version of canonical/json
# and is used by Notary. The package is periodically rebased on current Go versions.
@ -15,30 +15,31 @@ github.com/docker/go-connections 7beb39f0b969b075d1325fecb092faf27fd357b6
github.com/docker/go-events 9461782956ad83b30282bf90e31fa6a70c255ba9
github.com/docker/go-metrics d466d4f6fd960e01820085bd7e1a24426ee7ef18
github.com/docker/go-units 9e638d38cf6977a37a8ea0078f3ee75a7cdb2dd1
github.com/docker/swarmkit bd69f6e8e301645afd344913fa1ede53a0a111fb
github.com/docker/swarmkit edd5641391926a50bc5f7040e20b7efc05003c26
github.com/emicklei/go-restful ff4f55a206334ef123e4f79bbf348980da81ca46
github.com/emicklei/go-restful-swagger12 dcef7f55730566d41eae5db10e7d6981829720f6
github.com/flynn-archive/go-shlex 3f9db97f856818214da2e1057f8ad84803971cff
github.com/ghodss/yaml 0ca9ea5df5451ffdf184b4428c902747c2c11cd7
github.com/gogo/protobuf v0.4
github.com/golang/glog 44145f04b68cf362d9c4df2182967c2275eaefed
github.com/gogo/protobuf v1.0.0
github.com/google/go-cmp v0.2.0
github.com/golang/protobuf 7a211bcf3bce0e3f1d74f9894916e6f116ae83b4
github.com/golang/glog 44145f04b68cf362d9c4df2182967c2275eaefed
github.com/golang/protobuf v1.1.0
github.com/google/btree 316fb6d3f031ae8f4d457c6c5186b9e3ded70435
github.com/google/gofuzz 44d81051d367757e1c7c6a5a86423ece9afcf63c
github.com/googleapis/gnostic e4f56557df6250e1945ee6854f181ce4e1c2c646
github.com/gorilla/context v1.1
github.com/gorilla/mux v1.1
github.com/gotestyourself/gotestyourself cf3a5ab914a2efa8bc838d09f5918c1d44d02909
gotest.tools v2.1.0
github.com/go-openapi/jsonpointer 46af16f9f7b149af66e5d1bd010e3574dc06de98
github.com/go-openapi/jsonreference 13c6e3589ad90f49bd3e3bbe2c2cb3d7a4142272
github.com/go-openapi/spec 6aced65f8501fe1217321abf0749d354824ba2ff
github.com/go-openapi/swag 1d0bd113de87027671077d3c71eb3ac5d7dbba72
github.com/gregjones/httpcache c1f8028e62adb3d518b823a2f8e6a95c38bdd3aa
github.com/grpc-ecosystem/grpc-gateway 1a03ca3bad1e1ebadaedd3abb76bc58d4ac8143b
github.com/hashicorp/golang-lru 0a025b7e63adc15a622f29b0b2c4c3848243bbf6
github.com/grpc-ecosystem/grpc-opentracing 8e809c8a86450a29b90dcc9efbf062d0fe6d9746
github.com/hashicorp/golang-lru a0d98a5f288019575c6d1f4bb1573fef2d1fcdc4
github.com/howeyc/gopass 3ca23474a7c7203e0a0a070fd33508f6efdb9b3d
github.com/imdario/mergo 9d5f1277e9a8ed20c3684bda8fde67c05628518c # v0.3.4
github.com/imdario/mergo v0.3.5
github.com/inconshreveable/mousetrap 76626ae9c91c4f2a10f34cad8ce83ea42c93bb75
github.com/juju/ratelimit 5b9ff866471762aa2ab2dced63c9fb6f53921342
github.com/json-iterator/go 6240e1e7983a85228f7fd9c3e1b6932d46ec58e2
@ -48,15 +49,15 @@ github.com/matttproud/golang_protobuf_extensions v1.0.0
github.com/Microsoft/go-winio v0.4.6
github.com/miekg/pkcs11 5f6e0d0dad6f472df908c8e968a98ef00c9224bb
github.com/mitchellh/mapstructure f3009df150dadf309fdee4a54ed65c124afad715
github.com/moby/buildkit aaff9d591ef128560018433fe61beb802e149de8
github.com/moby/buildkit 43e758232a0ac7d50c6a11413186e16684fc1e4f
github.com/morikuni/aec 39771216ff4c63d11f5e604076f9c45e8be1067b
github.com/Nvveen/Gotty a8b993ba6abdb0e0c12b0125c603323a71c7790c https://github.com/ijc25/Gotty
github.com/opencontainers/go-digest 21dfd564fd89c944783d00d069f33e3e7123c448
github.com/opencontainers/go-digest v1.0.0-rc1
github.com/opencontainers/image-spec v1.0.1
github.com/opencontainers/runc 4fc53a81fb7c994640722ac585fa9ca548971871
github.com/opencontainers/runc 69663f0bd4b60df09991c08812a60108003fa340
github.com/opentracing/opentracing-go 1361b9cd60be79c4c3a7fa9841b3c132e40066a7
github.com/peterbourgon/diskv 5f041e8faa004a95c88a202771f4cc3e991971e6
github.com/pkg/errors 839d9e913e063e28dfd0e6c7b7512793e0a48be9
github.com/pmezard/go-difflib v1.0.0
github.com/prometheus/client_golang 52437c81da6b127a9925d17eb3a382a2e5fd395e
github.com/prometheus/client_model fa8ad6fec33561be4280a8f0514318c79d7f6cb6
github.com/prometheus/common ebdfc6da46522d58825777cf1f90490a5b1ef1d8
@ -69,18 +70,18 @@ github.com/sirupsen/logrus v1.0.3
github.com/spf13/cobra v0.0.3
github.com/spf13/pflag v1.0.1
github.com/theupdateframework/notary v0.6.1
github.com/tonistiigi/fsutil dea3a0da73aee887fc02142d995be764106ac5e2
github.com/tonistiigi/fsutil dc68c74458923f357474a9178bd198aa3ed11a5f
github.com/xeipuuv/gojsonpointer e0fe6f68307607d540ed8eac07a342c33fa1b54a
github.com/xeipuuv/gojsonreference e02fc20de94c78484cd5ffb007f8af96be030a45
github.com/xeipuuv/gojsonschema 93e72a773fade158921402d6a24c819b48aba29d
golang.org/x/crypto 558b6879de74bc843225cde5686419267ff707ca
golang.org/x/net 5561cd9b4330353950f399814f427425c0a26fd2
golang.org/x/crypto 1a580b3eff7814fc9b40602fd35256c63b50f491
golang.org/x/net 0ed95abb35c445290478a5348a7b38bb154135fd
golang.org/x/sync fd80eb99c8f653c847d294a001bdf2a3a6f768f5
golang.org/x/sys 37707fdb30a5b38865cfb95e5aab41707daec7fd
golang.org/x/text f72d8390a633d5dfb0cc84043294db9f6c935756
golang.org/x/time a4bde12657593d5e90d0533a3e4fd95e635124cb
google.golang.org/genproto d80a6e20e776b0b17a324d0ba1ab50a39c8e8944
google.golang.org/grpc v1.3.0
google.golang.org/genproto 694d95ba50e67b2e363f3483057db5d4910c18f9
google.golang.org/grpc v1.12.0
gopkg.in/inf.v0 3887ee99ecf07df5b447e9b00d9c0b2adaa9f3e4
gopkg.in/yaml.v2 4c78c975fe7c825c6d1466c42be594d1d6f3aba6
k8s.io/api kubernetes-1.8.2

View file

@ -29,6 +29,7 @@
"justincormack",
"silvin-lubecki",
"stevvooe",
"thajeztah",
"tibor",
"tonistiigi",
"vdemeester",

View file

@ -6,7 +6,7 @@ github.com/coreos/etcd v3.2.1
github.com/cpuguy83/go-md2man v1.0.8
github.com/davecgh/go-spew 346938d642f2ec3594ed81d874461961cd0faa76
github.com/docker/distribution 83389a148052d74ac602f5f1d62f86ff2f3c4aa5
github.com/docker/docker d37f5c6bdf788a6cb82c07fb707e31a240eff5f9
github.com/docker/docker 162ba6016def672690ee4a1f3978368853a1e149
github.com/docker/docker-credential-helpers 3c90bd29a46b943b2a9842987b58fb91a7c1819b
# the docker/go package contains a customized version of canonical/json
# and is used by Notary. The package is periodically rebased on current Go versions.
@ -15,15 +15,15 @@ github.com/docker/go-connections 7beb39f0b969b075d1325fecb092faf27fd357b6
github.com/docker/go-events 9461782956ad83b30282bf90e31fa6a70c255ba9
github.com/docker/go-metrics d466d4f6fd960e01820085bd7e1a24426ee7ef18
github.com/docker/go-units 9e638d38cf6977a37a8ea0078f3ee75a7cdb2dd1
github.com/docker/swarmkit bd69f6e8e301645afd344913fa1ede53a0a111fb
github.com/docker/swarmkit edd5641391926a50bc5f7040e20b7efc05003c26
github.com/emicklei/go-restful ff4f55a206334ef123e4f79bbf348980da81ca46
github.com/emicklei/go-restful-swagger12 dcef7f55730566d41eae5db10e7d6981829720f6
github.com/flynn-archive/go-shlex 3f9db97f856818214da2e1057f8ad84803971cff
github.com/ghodss/yaml 0ca9ea5df5451ffdf184b4428c902747c2c11cd7
github.com/gogo/protobuf v0.4
github.com/golang/glog 44145f04b68cf362d9c4df2182967c2275eaefed
github.com/gogo/protobuf v1.0.0
github.com/google/go-cmp v0.2.0
github.com/golang/protobuf 7a211bcf3bce0e3f1d74f9894916e6f116ae83b4
github.com/golang/glog 44145f04b68cf362d9c4df2182967c2275eaefed
github.com/golang/protobuf v1.1.0
github.com/google/btree 316fb6d3f031ae8f4d457c6c5186b9e3ded70435
github.com/google/gofuzz 44d81051d367757e1c7c6a5a86423ece9afcf63c
github.com/googleapis/gnostic e4f56557df6250e1945ee6854f181ce4e1c2c646
@ -36,9 +36,10 @@ github.com/go-openapi/spec 6aced65f8501fe1217321abf0749d354824ba2ff
github.com/go-openapi/swag 1d0bd113de87027671077d3c71eb3ac5d7dbba72
github.com/gregjones/httpcache c1f8028e62adb3d518b823a2f8e6a95c38bdd3aa
github.com/grpc-ecosystem/grpc-gateway 1a03ca3bad1e1ebadaedd3abb76bc58d4ac8143b
github.com/hashicorp/golang-lru 0a025b7e63adc15a622f29b0b2c4c3848243bbf6
github.com/grpc-ecosystem/grpc-opentracing 8e809c8a86450a29b90dcc9efbf062d0fe6d9746
github.com/hashicorp/golang-lru a0d98a5f288019575c6d1f4bb1573fef2d1fcdc4
github.com/howeyc/gopass 3ca23474a7c7203e0a0a070fd33508f6efdb9b3d
github.com/imdario/mergo 9d5f1277e9a8ed20c3684bda8fde67c05628518c # v0.3.4
github.com/imdario/mergo v0.3.5
github.com/inconshreveable/mousetrap 76626ae9c91c4f2a10f34cad8ce83ea42c93bb75
github.com/juju/ratelimit 5b9ff866471762aa2ab2dced63c9fb6f53921342
github.com/json-iterator/go 6240e1e7983a85228f7fd9c3e1b6932d46ec58e2
@ -48,12 +49,13 @@ github.com/matttproud/golang_protobuf_extensions v1.0.0
github.com/Microsoft/go-winio v0.4.6
github.com/miekg/pkcs11 5f6e0d0dad6f472df908c8e968a98ef00c9224bb
github.com/mitchellh/mapstructure f3009df150dadf309fdee4a54ed65c124afad715
github.com/moby/buildkit aaff9d591ef128560018433fe61beb802e149de8
github.com/moby/buildkit 43e758232a0ac7d50c6a11413186e16684fc1e4f
github.com/morikuni/aec 39771216ff4c63d11f5e604076f9c45e8be1067b
github.com/Nvveen/Gotty a8b993ba6abdb0e0c12b0125c603323a71c7790c https://github.com/ijc25/Gotty
github.com/opencontainers/go-digest 21dfd564fd89c944783d00d069f33e3e7123c448
github.com/opencontainers/go-digest v1.0.0-rc1
github.com/opencontainers/image-spec v1.0.1
github.com/opencontainers/runc 4fc53a81fb7c994640722ac585fa9ca548971871
github.com/opencontainers/runc 69663f0bd4b60df09991c08812a60108003fa340
github.com/opentracing/opentracing-go 1361b9cd60be79c4c3a7fa9841b3c132e40066a7
github.com/peterbourgon/diskv 5f041e8faa004a95c88a202771f4cc3e991971e6
github.com/pkg/errors 839d9e913e063e28dfd0e6c7b7512793e0a48be9
github.com/pmezard/go-difflib v1.0.0
@ -69,18 +71,18 @@ github.com/sirupsen/logrus v1.0.3
github.com/spf13/cobra v0.0.3
github.com/spf13/pflag v1.0.1
github.com/theupdateframework/notary v0.6.1
github.com/tonistiigi/fsutil dea3a0da73aee887fc02142d995be764106ac5e2
github.com/tonistiigi/fsutil dc68c74458923f357474a9178bd198aa3ed11a5f
github.com/xeipuuv/gojsonpointer e0fe6f68307607d540ed8eac07a342c33fa1b54a
github.com/xeipuuv/gojsonreference e02fc20de94c78484cd5ffb007f8af96be030a45
github.com/xeipuuv/gojsonschema 93e72a773fade158921402d6a24c819b48aba29d
golang.org/x/crypto 558b6879de74bc843225cde5686419267ff707ca
golang.org/x/net 5561cd9b4330353950f399814f427425c0a26fd2
golang.org/x/crypto 1a580b3eff7814fc9b40602fd35256c63b50f491
golang.org/x/net 0ed95abb35c445290478a5348a7b38bb154135fd
golang.org/x/sync fd80eb99c8f653c847d294a001bdf2a3a6f768f5
golang.org/x/sys 37707fdb30a5b38865cfb95e5aab41707daec7fd
golang.org/x/text f72d8390a633d5dfb0cc84043294db9f6c935756
golang.org/x/time a4bde12657593d5e90d0533a3e4fd95e635124cb
google.golang.org/genproto d80a6e20e776b0b17a324d0ba1ab50a39c8e8944
google.golang.org/grpc v1.3.0
google.golang.org/genproto 694d95ba50e67b2e363f3483057db5d4910c18f9
google.golang.org/grpc v1.12.0
gopkg.in/inf.v0 3887ee99ecf07df5b447e9b00d9c0b2adaa9f3e4
gopkg.in/yaml.v2 4c78c975fe7c825c6d1466c42be594d1d6f3aba6
k8s.io/api kubernetes-1.8.2

View file

@ -24,10 +24,10 @@
# the case. Therefore, you don't have to disable it anymore.
#
FROM golang:1.10.2 AS base
FROM golang:1.10.3 AS base
# FIXME(vdemeester) this is kept for other script depending on it to not fail right away
# Remove this once the other scripts uses something else to detect the version
ENV GO_VERSION 1.10.2
ENV GO_VERSION 1.10.3
# allow replacing httpredir or deb mirror
ARG APT_MIRROR=deb.debian.org
RUN sed -ri "s/(httpredir|deb).debian.org/$APT_MIRROR/g" /etc/apt/sources.list

View file

@ -1,5 +1,5 @@
## Step 1: Build tests
FROM golang:1.10.2-alpine3.7 as builder
FROM golang:1.10.3-alpine3.7 as builder
RUN apk add --update \
bash \

View file

@ -42,7 +42,7 @@ RUN apt-get update && apt-get install -y --no-install-recommends \
# will need updating, to avoid errors. Ping #docker-maintainers on IRC
# with a heads-up.
# IMPORTANT: When updating this please note that stdlib archive/tar pkg is vendored
ENV GO_VERSION 1.10.2
ENV GO_VERSION 1.10.3
RUN curl -fsSL "https://golang.org/dl/go${GO_VERSION}.linux-amd64.tar.gz" \
| tar -xzC /usr/local
ENV PATH /go/bin:/usr/local/go/bin:$PATH

View file

@ -161,7 +161,7 @@ SHELL ["powershell", "-Command", "$ErrorActionPreference = 'Stop'; $ProgressPref
# Environment variable notes:
# - GO_VERSION must be consistent with 'Dockerfile' used by Linux.
# - FROM_DOCKERFILE is used for detection of building within a container.
ENV GO_VERSION=1.10.2 `
ENV GO_VERSION=1.10.3 `
GIT_VERSION=2.11.1 `
GOPATH=C:\go `
FROM_DOCKERFILE=1

View file

@ -40,6 +40,7 @@
"mlaventure",
"runcom",
"stevvooe",
"thajeztah",
"tianon",
"tibor",
"tonistiigi",

View file

@ -772,6 +772,16 @@ definitions:
- "default"
- "process"
- "hyperv"
MaskedPaths:
type: "array"
description: "The list of paths to be masked inside the container (this overrides the default set of paths)"
items:
type: "string"
ReadonlyPaths:
type: "array"
description: "The list of paths to be set as read-only inside the container (this overrides the default set of paths)"
items:
type: "string"
ContainerConfig:
description: "Configuration for a container that is portable between hosts"
@ -2711,6 +2721,10 @@ definitions:
- "default"
- "process"
- "hyperv"
Init:
description: "Run an init inside the container that forwards signals and reaps processes. This field is omitted if empty, and the default (as configured on the daemon) is used."
type: "boolean"
x-nullable: true
NetworkAttachmentSpec:
description: |
Read-only spec type for non-swarm containers attached to swarm overlay

View file

@ -401,6 +401,12 @@ type HostConfig struct {
// Mounts specs used by the container
Mounts []mount.Mount `json:",omitempty"`
// MaskedPaths is the list of paths to be masked inside the container (this overrides the default set of paths)
MaskedPaths []string
// ReadonlyPaths is the list of paths to be set as read-only inside the container (this overrides the default set of paths)
ReadonlyPaths []string
// Run a custom init inside the container, if null, use the daemon's configured settings
Init *bool `json:",omitempty"`
}

View file

@ -55,6 +55,7 @@ type ContainerSpec struct {
User string `json:",omitempty"`
Groups []string `json:",omitempty"`
Privileges *Privileges `json:",omitempty"`
Init *bool `json:",omitempty"`
StopSignal string `json:",omitempty"`
TTY bool `json:",omitempty"`
OpenStdin bool `json:",omitempty"`

View file

@ -193,7 +193,7 @@ func TestNewEnvClientSetsDefaultVersion(t *testing.T) {
// TestNegotiateAPIVersionEmpty asserts that client.Client can
// negotiate a compatible APIVersion when omitted
func TestNegotiateAPIVersionEmpty(t *testing.T) {
defer env.PatchAll(t, map[string]string{"DOCKER_API_VERSION": ""})
defer env.PatchAll(t, map[string]string{"DOCKER_API_VERSION": ""})()
client, err := NewEnvClient()
assert.NilError(t, err)

View file

@ -9,7 +9,6 @@ import (
"net/http"
"net/http/httputil"
"net/url"
"strings"
"time"
"github.com/docker/docker/api/types"
@ -17,21 +16,6 @@ import (
"github.com/pkg/errors"
)
// tlsClientCon holds tls information and a dialed connection.
type tlsClientCon struct {
*tls.Conn
rawConn net.Conn
}
func (c *tlsClientCon) CloseWrite() error {
// Go standard tls.Conn doesn't provide the CloseWrite() method so we do it
// on its underlying connection.
if conn, ok := c.rawConn.(types.CloseWriter); ok {
return conn.CloseWrite()
}
return nil
}
// postHijacked sends a POST request and hijacks the connection.
func (cli *Client) postHijacked(ctx context.Context, path string, query url.Values, body interface{}, headers map[string][]string) (types.HijackedResponse, error) {
bodyEncoded, err := encodeData(body)
@ -54,96 +38,9 @@ func (cli *Client) postHijacked(ctx context.Context, path string, query url.Valu
return types.HijackedResponse{Conn: conn, Reader: bufio.NewReader(conn)}, err
}
func tlsDial(network, addr string, config *tls.Config) (net.Conn, error) {
return tlsDialWithDialer(new(net.Dialer), network, addr, config)
}
// We need to copy Go's implementation of tls.Dial (pkg/cryptor/tls/tls.go) in
// order to return our custom tlsClientCon struct which holds both the tls.Conn
// object _and_ its underlying raw connection. The rationale for this is that
// we need to be able to close the write end of the connection when attaching,
// which tls.Conn does not provide.
func tlsDialWithDialer(dialer *net.Dialer, network, addr string, config *tls.Config) (net.Conn, error) {
// We want the Timeout and Deadline values from dialer to cover the
// whole process: TCP connection and TLS handshake. This means that we
// also need to start our own timers now.
timeout := dialer.Timeout
if !dialer.Deadline.IsZero() {
deadlineTimeout := time.Until(dialer.Deadline)
if timeout == 0 || deadlineTimeout < timeout {
timeout = deadlineTimeout
}
}
var errChannel chan error
if timeout != 0 {
errChannel = make(chan error, 2)
time.AfterFunc(timeout, func() {
errChannel <- errors.New("")
})
}
proxyDialer, err := sockets.DialerFromEnvironment(dialer)
if err != nil {
return nil, err
}
rawConn, err := proxyDialer.Dial(network, addr)
if err != nil {
return nil, err
}
// When we set up a TCP connection for hijack, there could be long periods
// of inactivity (a long running command with no output) that in certain
// network setups may cause ECONNTIMEOUT, leaving the client in an unknown
// state. Setting TCP KeepAlive on the socket connection will prohibit
// ECONNTIMEOUT unless the socket connection truly is broken
if tcpConn, ok := rawConn.(*net.TCPConn); ok {
tcpConn.SetKeepAlive(true)
tcpConn.SetKeepAlivePeriod(30 * time.Second)
}
colonPos := strings.LastIndex(addr, ":")
if colonPos == -1 {
colonPos = len(addr)
}
hostname := addr[:colonPos]
// If no ServerName is set, infer the ServerName
// from the hostname we're connecting to.
if config.ServerName == "" {
// Make a copy to avoid polluting argument or default.
config = tlsConfigClone(config)
config.ServerName = hostname
}
conn := tls.Client(rawConn, config)
if timeout == 0 {
err = conn.Handshake()
} else {
go func() {
errChannel <- conn.Handshake()
}()
err = <-errChannel
}
if err != nil {
rawConn.Close()
return nil, err
}
// This is Docker difference with standard's crypto/tls package: returned a
// wrapper which holds both the TLS and raw connections.
return &tlsClientCon{conn, rawConn}, nil
}
func dial(proto, addr string, tlsConfig *tls.Config) (net.Conn, error) {
if tlsConfig != nil && proto != "unix" && proto != "npipe" {
// Notice this isn't Go standard's tls.Dial function
return tlsDial(proto, addr, tlsConfig)
return tls.Dial(proto, addr, tlsConfig)
}
if proto == "npipe" {
return sockets.DialPipe(addr, 32*time.Second)

103
vendor/github.com/docker/docker/client/hijack_test.go generated vendored Normal file
View file

@ -0,0 +1,103 @@
package client
import (
"fmt"
"io/ioutil"
"net"
"net/http"
"net/http/httptest"
"net/url"
"testing"
"github.com/docker/docker/api/server/httputils"
"github.com/docker/docker/api/types"
"github.com/gotestyourself/gotestyourself/assert"
"github.com/pkg/errors"
"golang.org/x/net/context"
)
func TestTLSCloseWriter(t *testing.T) {
t.Parallel()
var chErr chan error
ts := &httptest.Server{Config: &http.Server{Handler: http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) {
chErr = make(chan error, 1)
defer close(chErr)
if err := httputils.ParseForm(req); err != nil {
chErr <- errors.Wrap(err, "error parsing form")
http.Error(w, err.Error(), 500)
return
}
r, rw, err := httputils.HijackConnection(w)
if err != nil {
chErr <- errors.Wrap(err, "error hijacking connection")
http.Error(w, err.Error(), 500)
return
}
defer r.Close()
fmt.Fprint(rw, "HTTP/1.1 101 UPGRADED\r\nContent-Type: application/vnd.docker.raw-stream\r\nConnection: Upgrade\r\nUpgrade: tcp\r\n\n")
buf := make([]byte, 5)
_, err = r.Read(buf)
if err != nil {
chErr <- errors.Wrap(err, "error reading from client")
return
}
_, err = rw.Write(buf)
if err != nil {
chErr <- errors.Wrap(err, "error writing to client")
return
}
})}}
var (
l net.Listener
err error
)
for i := 1024; i < 10000; i++ {
l, err = net.Listen("tcp4", fmt.Sprintf("127.0.0.1:%d", i))
if err == nil {
break
}
}
assert.Assert(t, err)
ts.Listener = l
defer l.Close()
defer func() {
if chErr != nil {
assert.Assert(t, <-chErr)
}
}()
ts.StartTLS()
defer ts.Close()
serverURL, err := url.Parse(ts.URL)
assert.Assert(t, err)
client, err := NewClient("tcp://"+serverURL.Host, "", ts.Client(), nil)
assert.Assert(t, err)
resp, err := client.postHijacked(context.Background(), "/asdf", url.Values{}, nil, map[string][]string{"Content-Type": {"text/plain"}})
assert.Assert(t, err)
defer resp.Close()
if _, ok := resp.Conn.(types.CloseWriter); !ok {
t.Fatal("tls conn did not implement the CloseWrite interface")
}
_, err = resp.Conn.Write([]byte("hello"))
assert.Assert(t, err)
b, err := ioutil.ReadAll(resp.Reader)
assert.Assert(t, err)
assert.Assert(t, string(b) == "hello")
assert.Assert(t, resp.CloseWrite())
// This should error since writes are closed
_, err = resp.Conn.Write([]byte("no"))
assert.Assert(t, err != nil)
}

View file

@ -1,11 +0,0 @@
// +build go1.8
package client // import "github.com/docker/docker/client"
import "crypto/tls"
// tlsConfigClone returns a clone of tls.Config. This function is provided for
// compatibility for go1.7 that doesn't include this method in stdlib.
func tlsConfigClone(c *tls.Config) *tls.Config {
return c.Clone()
}

View file

@ -13,7 +13,7 @@ github.com/mattn/go-shellwords v1.0.3
github.com/sirupsen/logrus v1.0.3
github.com/tchap/go-patricia v2.2.6
github.com/vdemeester/shakers 24d7f1d6a71aa5d9cbe7390e4afb66b7eef9e1b3
golang.org/x/net 5561cd9b4330353950f399814f427425c0a26fd2
golang.org/x/net 0ed95abb35c445290478a5348a7b38bb154135fd
golang.org/x/sys 37707fdb30a5b38865cfb95e5aab41707daec7fd
github.com/docker/go-units 9e638d38cf6977a37a8ea0078f3ee75a7cdb2dd1
github.com/docker/go-connections 7beb39f0b969b075d1325fecb092faf27fd357b6
@ -35,7 +35,7 @@ github.com/opentracing/opentracing-go 1361b9cd60be79c4c3a7fa9841b3c132e40066a7
#get libnetwork packages
# When updating, also update LIBNETWORK_COMMIT in hack/dockerfile/install/proxy accordingly
github.com/docker/libnetwork eb6b2a57955e5c149d47c3973573216e8f8baa09
github.com/docker/libnetwork 19279f0492417475b6bfbd0aa529f73e8f178fb5
github.com/docker/go-events 9461782956ad83b30282bf90e31fa6a70c255ba9
github.com/armon/go-radix e39d623f12e8e41c7b5529e9a9dd67a1e2261f80
github.com/armon/go-metrics eb0af217e5e9747e41dd5303755356b62d28e3ec
@ -58,7 +58,7 @@ github.com/coreos/go-semver v0.2.0
github.com/ugorji/go f1f1a805ed361a0e078bb537e4ea78cd37dcf065
github.com/hashicorp/consul v0.5.2
github.com/boltdb/bolt fff57c100f4dea1905678da7e90d92429dff2904
github.com/miekg/dns 75e6e86cc601825c5dbcd4e0c209eab180997cd7
github.com/miekg/dns v1.0.7
github.com/ishidawataru/sctp 07191f837fedd2f13d1ec7b5f885f0f3ec54b1cb
# get graph and distribution packages
@ -112,11 +112,11 @@ github.com/googleapis/gax-go v2.0.0
google.golang.org/genproto 694d95ba50e67b2e363f3483057db5d4910c18f9
# containerd
github.com/containerd/containerd c7083eed5d8633d54c25fe81aa609010a4f2e495
github.com/containerd/containerd 63522d9eaa5a0443d225642c4b6f4f5fdedf932b
github.com/containerd/fifo 3d5202aec260678c48179c56f40e6f38a095738c
github.com/containerd/continuity d3c23511c1bf5851696cba83143d9cbcd666869b
github.com/containerd/cgroups fe281dd265766145e943a034aa41086474ea6130
github.com/containerd/console cb7008ab3d8359b78c5f464cb7cf160107ad5925
github.com/containerd/console 9290d21dc56074581f619579c43d970b4514bc08
github.com/containerd/go-runc f271fa2021de855d4d918dbef83c5fe19db1bdd
github.com/containerd/typeurl f6943554a7e7e88b3c14aad190bf05932da84788
github.com/stevvooe/ttrpc d4528379866b0ce7e9d71f3eb96f0582fc374577
@ -128,7 +128,7 @@ github.com/gogo/protobuf v1.0.0
github.com/cloudflare/cfssl 7fb22c8cba7ecaf98e4082d22d65800cf45e042a
github.com/fernet/fernet-go 1b2437bc582b3cfbb341ee5a29f8ef5b42912ff2
github.com/google/certificate-transparency d90e65c3a07988180c5b1ece71791c0b6506826e
golang.org/x/crypto 558b6879de74bc843225cde5686419267ff707ca
golang.org/x/crypto 1a580b3eff7814fc9b40602fd35256c63b50f491
golang.org/x/time a4bde12657593d5e90d0533a3e4fd95e635124cb
github.com/hashicorp/go-memdb cb9a474f84cc5e41b273b20c6927680b2a8776ad
github.com/hashicorp/go-immutable-radix 8e8ed81f8f0bf1bdd829593fdd5c29922c1ea990

1241
vendor/github.com/golang/protobuf/jsonpb/jsonpb.go generated vendored Normal file

File diff suppressed because it is too large Load diff

1150
vendor/github.com/golang/protobuf/jsonpb/jsonpb_test.go generated vendored Normal file

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,872 @@
// Protocol Buffers - Google's data interchange format
// Copyright 2008 Google Inc. All rights reserved.
// https://developers.google.com/protocol-buffers/
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
// * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
// Author: kenton@google.com (Kenton Varda)
// Based on original Protocol Buffers design by
// Sanjay Ghemawat, Jeff Dean, and others.
//
// The messages in this file describe the definitions found in .proto files.
// A valid .proto file can be translated directly to a FileDescriptorProto
// without any other information (e.g. without reading its imports).
syntax = "proto2";
package google.protobuf;
option go_package = "github.com/golang/protobuf/protoc-gen-go/descriptor;descriptor";
option java_package = "com.google.protobuf";
option java_outer_classname = "DescriptorProtos";
option csharp_namespace = "Google.Protobuf.Reflection";
option objc_class_prefix = "GPB";
option cc_enable_arenas = true;
// descriptor.proto must be optimized for speed because reflection-based
// algorithms don't work during bootstrapping.
option optimize_for = SPEED;
// The protocol compiler can output a FileDescriptorSet containing the .proto
// files it parses.
message FileDescriptorSet {
repeated FileDescriptorProto file = 1;
}
// Describes a complete .proto file.
message FileDescriptorProto {
optional string name = 1; // file name, relative to root of source tree
optional string package = 2; // e.g. "foo", "foo.bar", etc.
// Names of files imported by this file.
repeated string dependency = 3;
// Indexes of the public imported files in the dependency list above.
repeated int32 public_dependency = 10;
// Indexes of the weak imported files in the dependency list.
// For Google-internal migration only. Do not use.
repeated int32 weak_dependency = 11;
// All top-level definitions in this file.
repeated DescriptorProto message_type = 4;
repeated EnumDescriptorProto enum_type = 5;
repeated ServiceDescriptorProto service = 6;
repeated FieldDescriptorProto extension = 7;
optional FileOptions options = 8;
// This field contains optional information about the original source code.
// You may safely remove this entire field without harming runtime
// functionality of the descriptors -- the information is needed only by
// development tools.
optional SourceCodeInfo source_code_info = 9;
// The syntax of the proto file.
// The supported values are "proto2" and "proto3".
optional string syntax = 12;
}
// Describes a message type.
message DescriptorProto {
optional string name = 1;
repeated FieldDescriptorProto field = 2;
repeated FieldDescriptorProto extension = 6;
repeated DescriptorProto nested_type = 3;
repeated EnumDescriptorProto enum_type = 4;
message ExtensionRange {
optional int32 start = 1;
optional int32 end = 2;
optional ExtensionRangeOptions options = 3;
}
repeated ExtensionRange extension_range = 5;
repeated OneofDescriptorProto oneof_decl = 8;
optional MessageOptions options = 7;
// Range of reserved tag numbers. Reserved tag numbers may not be used by
// fields or extension ranges in the same message. Reserved ranges may
// not overlap.
message ReservedRange {
optional int32 start = 1; // Inclusive.
optional int32 end = 2; // Exclusive.
}
repeated ReservedRange reserved_range = 9;
// Reserved field names, which may not be used by fields in the same message.
// A given name may only be reserved once.
repeated string reserved_name = 10;
}
message ExtensionRangeOptions {
// The parser stores options it doesn't recognize here. See above.
repeated UninterpretedOption uninterpreted_option = 999;
// Clients can define custom options in extensions of this message. See above.
extensions 1000 to max;
}
// Describes a field within a message.
message FieldDescriptorProto {
enum Type {
// 0 is reserved for errors.
// Order is weird for historical reasons.
TYPE_DOUBLE = 1;
TYPE_FLOAT = 2;
// Not ZigZag encoded. Negative numbers take 10 bytes. Use TYPE_SINT64 if
// negative values are likely.
TYPE_INT64 = 3;
TYPE_UINT64 = 4;
// Not ZigZag encoded. Negative numbers take 10 bytes. Use TYPE_SINT32 if
// negative values are likely.
TYPE_INT32 = 5;
TYPE_FIXED64 = 6;
TYPE_FIXED32 = 7;
TYPE_BOOL = 8;
TYPE_STRING = 9;
// Tag-delimited aggregate.
// Group type is deprecated and not supported in proto3. However, Proto3
// implementations should still be able to parse the group wire format and
// treat group fields as unknown fields.
TYPE_GROUP = 10;
TYPE_MESSAGE = 11; // Length-delimited aggregate.
// New in version 2.
TYPE_BYTES = 12;
TYPE_UINT32 = 13;
TYPE_ENUM = 14;
TYPE_SFIXED32 = 15;
TYPE_SFIXED64 = 16;
TYPE_SINT32 = 17; // Uses ZigZag encoding.
TYPE_SINT64 = 18; // Uses ZigZag encoding.
};
enum Label {
// 0 is reserved for errors
LABEL_OPTIONAL = 1;
LABEL_REQUIRED = 2;
LABEL_REPEATED = 3;
};
optional string name = 1;
optional int32 number = 3;
optional Label label = 4;
// If type_name is set, this need not be set. If both this and type_name
// are set, this must be one of TYPE_ENUM, TYPE_MESSAGE or TYPE_GROUP.
optional Type type = 5;
// For message and enum types, this is the name of the type. If the name
// starts with a '.', it is fully-qualified. Otherwise, C++-like scoping
// rules are used to find the type (i.e. first the nested types within this
// message are searched, then within the parent, on up to the root
// namespace).
optional string type_name = 6;
// For extensions, this is the name of the type being extended. It is
// resolved in the same manner as type_name.
optional string extendee = 2;
// For numeric types, contains the original text representation of the value.
// For booleans, "true" or "false".
// For strings, contains the default text contents (not escaped in any way).
// For bytes, contains the C escaped value. All bytes >= 128 are escaped.
// TODO(kenton): Base-64 encode?
optional string default_value = 7;
// If set, gives the index of a oneof in the containing type's oneof_decl
// list. This field is a member of that oneof.
optional int32 oneof_index = 9;
// JSON name of this field. The value is set by protocol compiler. If the
// user has set a "json_name" option on this field, that option's value
// will be used. Otherwise, it's deduced from the field's name by converting
// it to camelCase.
optional string json_name = 10;
optional FieldOptions options = 8;
}
// Describes a oneof.
message OneofDescriptorProto {
optional string name = 1;
optional OneofOptions options = 2;
}
// Describes an enum type.
message EnumDescriptorProto {
optional string name = 1;
repeated EnumValueDescriptorProto value = 2;
optional EnumOptions options = 3;
// Range of reserved numeric values. Reserved values may not be used by
// entries in the same enum. Reserved ranges may not overlap.
//
// Note that this is distinct from DescriptorProto.ReservedRange in that it
// is inclusive such that it can appropriately represent the entire int32
// domain.
message EnumReservedRange {
optional int32 start = 1; // Inclusive.
optional int32 end = 2; // Inclusive.
}
// Range of reserved numeric values. Reserved numeric values may not be used
// by enum values in the same enum declaration. Reserved ranges may not
// overlap.
repeated EnumReservedRange reserved_range = 4;
// Reserved enum value names, which may not be reused. A given name may only
// be reserved once.
repeated string reserved_name = 5;
}
// Describes a value within an enum.
message EnumValueDescriptorProto {
optional string name = 1;
optional int32 number = 2;
optional EnumValueOptions options = 3;
}
// Describes a service.
message ServiceDescriptorProto {
optional string name = 1;
repeated MethodDescriptorProto method = 2;
optional ServiceOptions options = 3;
}
// Describes a method of a service.
message MethodDescriptorProto {
optional string name = 1;
// Input and output type names. These are resolved in the same way as
// FieldDescriptorProto.type_name, but must refer to a message type.
optional string input_type = 2;
optional string output_type = 3;
optional MethodOptions options = 4;
// Identifies if client streams multiple client messages
optional bool client_streaming = 5 [default=false];
// Identifies if server streams multiple server messages
optional bool server_streaming = 6 [default=false];
}
// ===================================================================
// Options
// Each of the definitions above may have "options" attached. These are
// just annotations which may cause code to be generated slightly differently
// or may contain hints for code that manipulates protocol messages.
//
// Clients may define custom options as extensions of the *Options messages.
// These extensions may not yet be known at parsing time, so the parser cannot
// store the values in them. Instead it stores them in a field in the *Options
// message called uninterpreted_option. This field must have the same name
// across all *Options messages. We then use this field to populate the
// extensions when we build a descriptor, at which point all protos have been
// parsed and so all extensions are known.
//
// Extension numbers for custom options may be chosen as follows:
// * For options which will only be used within a single application or
// organization, or for experimental options, use field numbers 50000
// through 99999. It is up to you to ensure that you do not use the
// same number for multiple options.
// * For options which will be published and used publicly by multiple
// independent entities, e-mail protobuf-global-extension-registry@google.com
// to reserve extension numbers. Simply provide your project name (e.g.
// Objective-C plugin) and your project website (if available) -- there's no
// need to explain how you intend to use them. Usually you only need one
// extension number. You can declare multiple options with only one extension
// number by putting them in a sub-message. See the Custom Options section of
// the docs for examples:
// https://developers.google.com/protocol-buffers/docs/proto#options
// If this turns out to be popular, a web service will be set up
// to automatically assign option numbers.
message FileOptions {
// Sets the Java package where classes generated from this .proto will be
// placed. By default, the proto package is used, but this is often
// inappropriate because proto packages do not normally start with backwards
// domain names.
optional string java_package = 1;
// If set, all the classes from the .proto file are wrapped in a single
// outer class with the given name. This applies to both Proto1
// (equivalent to the old "--one_java_file" option) and Proto2 (where
// a .proto always translates to a single class, but you may want to
// explicitly choose the class name).
optional string java_outer_classname = 8;
// If set true, then the Java code generator will generate a separate .java
// file for each top-level message, enum, and service defined in the .proto
// file. Thus, these types will *not* be nested inside the outer class
// named by java_outer_classname. However, the outer class will still be
// generated to contain the file's getDescriptor() method as well as any
// top-level extensions defined in the file.
optional bool java_multiple_files = 10 [default=false];
// This option does nothing.
optional bool java_generate_equals_and_hash = 20 [deprecated=true];
// If set true, then the Java2 code generator will generate code that
// throws an exception whenever an attempt is made to assign a non-UTF-8
// byte sequence to a string field.
// Message reflection will do the same.
// However, an extension field still accepts non-UTF-8 byte sequences.
// This option has no effect on when used with the lite runtime.
optional bool java_string_check_utf8 = 27 [default=false];
// Generated classes can be optimized for speed or code size.
enum OptimizeMode {
SPEED = 1; // Generate complete code for parsing, serialization,
// etc.
CODE_SIZE = 2; // Use ReflectionOps to implement these methods.
LITE_RUNTIME = 3; // Generate code using MessageLite and the lite runtime.
}
optional OptimizeMode optimize_for = 9 [default=SPEED];
// Sets the Go package where structs generated from this .proto will be
// placed. If omitted, the Go package will be derived from the following:
// - The basename of the package import path, if provided.
// - Otherwise, the package statement in the .proto file, if present.
// - Otherwise, the basename of the .proto file, without extension.
optional string go_package = 11;
// Should generic services be generated in each language? "Generic" services
// are not specific to any particular RPC system. They are generated by the
// main code generators in each language (without additional plugins).
// Generic services were the only kind of service generation supported by
// early versions of google.protobuf.
//
// Generic services are now considered deprecated in favor of using plugins
// that generate code specific to your particular RPC system. Therefore,
// these default to false. Old code which depends on generic services should
// explicitly set them to true.
optional bool cc_generic_services = 16 [default=false];
optional bool java_generic_services = 17 [default=false];
optional bool py_generic_services = 18 [default=false];
optional bool php_generic_services = 42 [default=false];
// Is this file deprecated?
// Depending on the target platform, this can emit Deprecated annotations
// for everything in the file, or it will be completely ignored; in the very
// least, this is a formalization for deprecating files.
optional bool deprecated = 23 [default=false];
// Enables the use of arenas for the proto messages in this file. This applies
// only to generated classes for C++.
optional bool cc_enable_arenas = 31 [default=false];
// Sets the objective c class prefix which is prepended to all objective c
// generated classes from this .proto. There is no default.
optional string objc_class_prefix = 36;
// Namespace for generated classes; defaults to the package.
optional string csharp_namespace = 37;
// By default Swift generators will take the proto package and CamelCase it
// replacing '.' with underscore and use that to prefix the types/symbols
// defined. When this options is provided, they will use this value instead
// to prefix the types/symbols defined.
optional string swift_prefix = 39;
// Sets the php class prefix which is prepended to all php generated classes
// from this .proto. Default is empty.
optional string php_class_prefix = 40;
// Use this option to change the namespace of php generated classes. Default
// is empty. When this option is empty, the package name will be used for
// determining the namespace.
optional string php_namespace = 41;
// The parser stores options it doesn't recognize here.
// See the documentation for the "Options" section above.
repeated UninterpretedOption uninterpreted_option = 999;
// Clients can define custom options in extensions of this message.
// See the documentation for the "Options" section above.
extensions 1000 to max;
reserved 38;
}
message MessageOptions {
// Set true to use the old proto1 MessageSet wire format for extensions.
// This is provided for backwards-compatibility with the MessageSet wire
// format. You should not use this for any other reason: It's less
// efficient, has fewer features, and is more complicated.
//
// The message must be defined exactly as follows:
// message Foo {
// option message_set_wire_format = true;
// extensions 4 to max;
// }
// Note that the message cannot have any defined fields; MessageSets only
// have extensions.
//
// All extensions of your type must be singular messages; e.g. they cannot
// be int32s, enums, or repeated messages.
//
// Because this is an option, the above two restrictions are not enforced by
// the protocol compiler.
optional bool message_set_wire_format = 1 [default=false];
// Disables the generation of the standard "descriptor()" accessor, which can
// conflict with a field of the same name. This is meant to make migration
// from proto1 easier; new code should avoid fields named "descriptor".
optional bool no_standard_descriptor_accessor = 2 [default=false];
// Is this message deprecated?
// Depending on the target platform, this can emit Deprecated annotations
// for the message, or it will be completely ignored; in the very least,
// this is a formalization for deprecating messages.
optional bool deprecated = 3 [default=false];
// Whether the message is an automatically generated map entry type for the
// maps field.
//
// For maps fields:
// map<KeyType, ValueType> map_field = 1;
// The parsed descriptor looks like:
// message MapFieldEntry {
// option map_entry = true;
// optional KeyType key = 1;
// optional ValueType value = 2;
// }
// repeated MapFieldEntry map_field = 1;
//
// Implementations may choose not to generate the map_entry=true message, but
// use a native map in the target language to hold the keys and values.
// The reflection APIs in such implementions still need to work as
// if the field is a repeated message field.
//
// NOTE: Do not set the option in .proto files. Always use the maps syntax
// instead. The option should only be implicitly set by the proto compiler
// parser.
optional bool map_entry = 7;
reserved 8; // javalite_serializable
reserved 9; // javanano_as_lite
// The parser stores options it doesn't recognize here. See above.
repeated UninterpretedOption uninterpreted_option = 999;
// Clients can define custom options in extensions of this message. See above.
extensions 1000 to max;
}
message FieldOptions {
// The ctype option instructs the C++ code generator to use a different
// representation of the field than it normally would. See the specific
// options below. This option is not yet implemented in the open source
// release -- sorry, we'll try to include it in a future version!
optional CType ctype = 1 [default = STRING];
enum CType {
// Default mode.
STRING = 0;
CORD = 1;
STRING_PIECE = 2;
}
// The packed option can be enabled for repeated primitive fields to enable
// a more efficient representation on the wire. Rather than repeatedly
// writing the tag and type for each element, the entire array is encoded as
// a single length-delimited blob. In proto3, only explicit setting it to
// false will avoid using packed encoding.
optional bool packed = 2;
// The jstype option determines the JavaScript type used for values of the
// field. The option is permitted only for 64 bit integral and fixed types
// (int64, uint64, sint64, fixed64, sfixed64). A field with jstype JS_STRING
// is represented as JavaScript string, which avoids loss of precision that
// can happen when a large value is converted to a floating point JavaScript.
// Specifying JS_NUMBER for the jstype causes the generated JavaScript code to
// use the JavaScript "number" type. The behavior of the default option
// JS_NORMAL is implementation dependent.
//
// This option is an enum to permit additional types to be added, e.g.
// goog.math.Integer.
optional JSType jstype = 6 [default = JS_NORMAL];
enum JSType {
// Use the default type.
JS_NORMAL = 0;
// Use JavaScript strings.
JS_STRING = 1;
// Use JavaScript numbers.
JS_NUMBER = 2;
}
// Should this field be parsed lazily? Lazy applies only to message-type
// fields. It means that when the outer message is initially parsed, the
// inner message's contents will not be parsed but instead stored in encoded
// form. The inner message will actually be parsed when it is first accessed.
//
// This is only a hint. Implementations are free to choose whether to use
// eager or lazy parsing regardless of the value of this option. However,
// setting this option true suggests that the protocol author believes that
// using lazy parsing on this field is worth the additional bookkeeping
// overhead typically needed to implement it.
//
// This option does not affect the public interface of any generated code;
// all method signatures remain the same. Furthermore, thread-safety of the
// interface is not affected by this option; const methods remain safe to
// call from multiple threads concurrently, while non-const methods continue
// to require exclusive access.
//
//
// Note that implementations may choose not to check required fields within
// a lazy sub-message. That is, calling IsInitialized() on the outer message
// may return true even if the inner message has missing required fields.
// This is necessary because otherwise the inner message would have to be
// parsed in order to perform the check, defeating the purpose of lazy
// parsing. An implementation which chooses not to check required fields
// must be consistent about it. That is, for any particular sub-message, the
// implementation must either *always* check its required fields, or *never*
// check its required fields, regardless of whether or not the message has
// been parsed.
optional bool lazy = 5 [default=false];
// Is this field deprecated?
// Depending on the target platform, this can emit Deprecated annotations
// for accessors, or it will be completely ignored; in the very least, this
// is a formalization for deprecating fields.
optional bool deprecated = 3 [default=false];
// For Google-internal migration only. Do not use.
optional bool weak = 10 [default=false];
// The parser stores options it doesn't recognize here. See above.
repeated UninterpretedOption uninterpreted_option = 999;
// Clients can define custom options in extensions of this message. See above.
extensions 1000 to max;
reserved 4; // removed jtype
}
message OneofOptions {
// The parser stores options it doesn't recognize here. See above.
repeated UninterpretedOption uninterpreted_option = 999;
// Clients can define custom options in extensions of this message. See above.
extensions 1000 to max;
}
message EnumOptions {
// Set this option to true to allow mapping different tag names to the same
// value.
optional bool allow_alias = 2;
// Is this enum deprecated?
// Depending on the target platform, this can emit Deprecated annotations
// for the enum, or it will be completely ignored; in the very least, this
// is a formalization for deprecating enums.
optional bool deprecated = 3 [default=false];
reserved 5; // javanano_as_lite
// The parser stores options it doesn't recognize here. See above.
repeated UninterpretedOption uninterpreted_option = 999;
// Clients can define custom options in extensions of this message. See above.
extensions 1000 to max;
}
message EnumValueOptions {
// Is this enum value deprecated?
// Depending on the target platform, this can emit Deprecated annotations
// for the enum value, or it will be completely ignored; in the very least,
// this is a formalization for deprecating enum values.
optional bool deprecated = 1 [default=false];
// The parser stores options it doesn't recognize here. See above.
repeated UninterpretedOption uninterpreted_option = 999;
// Clients can define custom options in extensions of this message. See above.
extensions 1000 to max;
}
message ServiceOptions {
// Note: Field numbers 1 through 32 are reserved for Google's internal RPC
// framework. We apologize for hoarding these numbers to ourselves, but
// we were already using them long before we decided to release Protocol
// Buffers.
// Is this service deprecated?
// Depending on the target platform, this can emit Deprecated annotations
// for the service, or it will be completely ignored; in the very least,
// this is a formalization for deprecating services.
optional bool deprecated = 33 [default=false];
// The parser stores options it doesn't recognize here. See above.
repeated UninterpretedOption uninterpreted_option = 999;
// Clients can define custom options in extensions of this message. See above.
extensions 1000 to max;
}
message MethodOptions {
// Note: Field numbers 1 through 32 are reserved for Google's internal RPC
// framework. We apologize for hoarding these numbers to ourselves, but
// we were already using them long before we decided to release Protocol
// Buffers.
// Is this method deprecated?
// Depending on the target platform, this can emit Deprecated annotations
// for the method, or it will be completely ignored; in the very least,
// this is a formalization for deprecating methods.
optional bool deprecated = 33 [default=false];
// Is this method side-effect-free (or safe in HTTP parlance), or idempotent,
// or neither? HTTP based RPC implementation may choose GET verb for safe
// methods, and PUT verb for idempotent methods instead of the default POST.
enum IdempotencyLevel {
IDEMPOTENCY_UNKNOWN = 0;
NO_SIDE_EFFECTS = 1; // implies idempotent
IDEMPOTENT = 2; // idempotent, but may have side effects
}
optional IdempotencyLevel idempotency_level =
34 [default=IDEMPOTENCY_UNKNOWN];
// The parser stores options it doesn't recognize here. See above.
repeated UninterpretedOption uninterpreted_option = 999;
// Clients can define custom options in extensions of this message. See above.
extensions 1000 to max;
}
// A message representing a option the parser does not recognize. This only
// appears in options protos created by the compiler::Parser class.
// DescriptorPool resolves these when building Descriptor objects. Therefore,
// options protos in descriptor objects (e.g. returned by Descriptor::options(),
// or produced by Descriptor::CopyTo()) will never have UninterpretedOptions
// in them.
message UninterpretedOption {
// The name of the uninterpreted option. Each string represents a segment in
// a dot-separated name. is_extension is true iff a segment represents an
// extension (denoted with parentheses in options specs in .proto files).
// E.g.,{ ["foo", false], ["bar.baz", true], ["qux", false] } represents
// "foo.(bar.baz).qux".
message NamePart {
required string name_part = 1;
required bool is_extension = 2;
}
repeated NamePart name = 2;
// The value of the uninterpreted option, in whatever type the tokenizer
// identified it as during parsing. Exactly one of these should be set.
optional string identifier_value = 3;
optional uint64 positive_int_value = 4;
optional int64 negative_int_value = 5;
optional double double_value = 6;
optional bytes string_value = 7;
optional string aggregate_value = 8;
}
// ===================================================================
// Optional source code info
// Encapsulates information about the original source file from which a
// FileDescriptorProto was generated.
message SourceCodeInfo {
// A Location identifies a piece of source code in a .proto file which
// corresponds to a particular definition. This information is intended
// to be useful to IDEs, code indexers, documentation generators, and similar
// tools.
//
// For example, say we have a file like:
// message Foo {
// optional string foo = 1;
// }
// Let's look at just the field definition:
// optional string foo = 1;
// ^ ^^ ^^ ^ ^^^
// a bc de f ghi
// We have the following locations:
// span path represents
// [a,i) [ 4, 0, 2, 0 ] The whole field definition.
// [a,b) [ 4, 0, 2, 0, 4 ] The label (optional).
// [c,d) [ 4, 0, 2, 0, 5 ] The type (string).
// [e,f) [ 4, 0, 2, 0, 1 ] The name (foo).
// [g,h) [ 4, 0, 2, 0, 3 ] The number (1).
//
// Notes:
// - A location may refer to a repeated field itself (i.e. not to any
// particular index within it). This is used whenever a set of elements are
// logically enclosed in a single code segment. For example, an entire
// extend block (possibly containing multiple extension definitions) will
// have an outer location whose path refers to the "extensions" repeated
// field without an index.
// - Multiple locations may have the same path. This happens when a single
// logical declaration is spread out across multiple places. The most
// obvious example is the "extend" block again -- there may be multiple
// extend blocks in the same scope, each of which will have the same path.
// - A location's span is not always a subset of its parent's span. For
// example, the "extendee" of an extension declaration appears at the
// beginning of the "extend" block and is shared by all extensions within
// the block.
// - Just because a location's span is a subset of some other location's span
// does not mean that it is a descendent. For example, a "group" defines
// both a type and a field in a single declaration. Thus, the locations
// corresponding to the type and field and their components will overlap.
// - Code which tries to interpret locations should probably be designed to
// ignore those that it doesn't understand, as more types of locations could
// be recorded in the future.
repeated Location location = 1;
message Location {
// Identifies which part of the FileDescriptorProto was defined at this
// location.
//
// Each element is a field number or an index. They form a path from
// the root FileDescriptorProto to the place where the definition. For
// example, this path:
// [ 4, 3, 2, 7, 1 ]
// refers to:
// file.message_type(3) // 4, 3
// .field(7) // 2, 7
// .name() // 1
// This is because FileDescriptorProto.message_type has field number 4:
// repeated DescriptorProto message_type = 4;
// and DescriptorProto.field has field number 2:
// repeated FieldDescriptorProto field = 2;
// and FieldDescriptorProto.name has field number 1:
// optional string name = 1;
//
// Thus, the above path gives the location of a field name. If we removed
// the last element:
// [ 4, 3, 2, 7 ]
// this path refers to the whole field declaration (from the beginning
// of the label to the terminating semicolon).
repeated int32 path = 1 [packed=true];
// Always has exactly three or four elements: start line, start column,
// end line (optional, otherwise assumed same as start line), end column.
// These are packed into a single field for efficiency. Note that line
// and column numbers are zero-based -- typically you will want to add
// 1 to each before displaying to a user.
repeated int32 span = 2 [packed=true];
// If this SourceCodeInfo represents a complete declaration, these are any
// comments appearing before and after the declaration which appear to be
// attached to the declaration.
//
// A series of line comments appearing on consecutive lines, with no other
// tokens appearing on those lines, will be treated as a single comment.
//
// leading_detached_comments will keep paragraphs of comments that appear
// before (but not connected to) the current element. Each paragraph,
// separated by empty lines, will be one comment element in the repeated
// field.
//
// Only the comment content is provided; comment markers (e.g. //) are
// stripped out. For block comments, leading whitespace and an asterisk
// will be stripped from the beginning of each line other than the first.
// Newlines are included in the output.
//
// Examples:
//
// optional int32 foo = 1; // Comment attached to foo.
// // Comment attached to bar.
// optional int32 bar = 2;
//
// optional string baz = 3;
// // Comment attached to baz.
// // Another line attached to baz.
//
// // Comment attached to qux.
// //
// // Another line attached to qux.
// optional double qux = 4;
//
// // Detached comment for corge. This is not leading or trailing comments
// // to qux or corge because there are blank lines separating it from
// // both.
//
// // Detached comment for corge paragraph 2.
//
// optional string corge = 5;
// /* Block comment attached
// * to corge. Leading asterisks
// * will be removed. */
// /* Block comment attached to
// * grault. */
// optional int32 grault = 6;
//
// // ignored detached comments.
optional string leading_comments = 3;
optional string trailing_comments = 4;
repeated string leading_detached_comments = 6;
}
}
// Describes the relationship between generated code and its original source
// file. A GeneratedCodeInfo message is associated with only one generated
// source file, but may contain references to different source .proto files.
message GeneratedCodeInfo {
// An Annotation connects some span of text in generated code to an element
// of its generating .proto file.
repeated Annotation annotation = 1;
message Annotation {
// Identifies the element in the original source .proto file. This field
// is formatted the same as SourceCodeInfo.Location.path.
repeated int32 path = 1 [packed=true];
// Identifies the filesystem path to the original source .proto.
optional string source_file = 2;
// Identifies the starting offset in bytes in the generated code
// that relates to the identified object.
optional int32 begin = 3;
// Identifies the ending offset in bytes in the generated code that
// relates to the identified offset. The end offset should be one past
// the last relevant byte (so the length of the text = end - begin).
optional int32 end = 4;
}
}

51
vendor/github.com/golang/protobuf/protoc-gen-go/doc.go generated vendored Normal file
View file

@ -0,0 +1,51 @@
// Go support for Protocol Buffers - Google's data interchange format
//
// Copyright 2010 The Go Authors. All rights reserved.
// https://github.com/golang/protobuf
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
// * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
/*
A plugin for the Google protocol buffer compiler to generate Go code.
Run it by building this program and putting it in your path with the name
protoc-gen-go
That word 'go' at the end becomes part of the option string set for the
protocol compiler, so once the protocol compiler (protoc) is installed
you can run
protoc --go_out=output_directory input_directory/file.proto
to generate Go bindings for the protocol defined by file.proto.
With that input, the output will be written to
output_directory/file.pb.go
The generated code is documented in the package comment for
the library.
See the README and documentation for protocol buffers to learn more:
https://developers.google.com/protocol-buffers/
*/
package documentation

View file

@ -0,0 +1,422 @@
package main
import (
"bytes"
"flag"
"fmt"
"go/build"
"go/parser"
"go/token"
"io/ioutil"
"os"
"os/exec"
"path/filepath"
"regexp"
"runtime"
"strings"
"testing"
)
// Set --regenerate to regenerate the golden files.
var regenerate = flag.Bool("regenerate", false, "regenerate golden files")
// When the environment variable RUN_AS_PROTOC_GEN_GO is set, we skip running
// tests and instead act as protoc-gen-go. This allows the test binary to
// pass itself to protoc.
func init() {
if os.Getenv("RUN_AS_PROTOC_GEN_GO") != "" {
main()
os.Exit(0)
}
}
func TestGolden(t *testing.T) {
workdir, err := ioutil.TempDir("", "proto-test")
if err != nil {
t.Fatal(err)
}
defer os.RemoveAll(workdir)
// Find all the proto files we need to compile. We assume that each directory
// contains the files for a single package.
supportTypeAliases := hasReleaseTag("go1.9")
packages := map[string][]string{}
err = filepath.Walk("testdata", func(path string, info os.FileInfo, err error) error {
if filepath.Base(path) == "import_public" && !supportTypeAliases {
// Public imports require type alias support.
return filepath.SkipDir
}
if !strings.HasSuffix(path, ".proto") {
return nil
}
dir := filepath.Dir(path)
packages[dir] = append(packages[dir], path)
return nil
})
if err != nil {
t.Fatal(err)
}
// Compile each package, using this binary as protoc-gen-go.
for _, sources := range packages {
args := []string{"-Itestdata", "--go_out=plugins=grpc,paths=source_relative:" + workdir}
args = append(args, sources...)
protoc(t, args)
}
// Compare each generated file to the golden version.
filepath.Walk(workdir, func(genPath string, info os.FileInfo, _ error) error {
if info.IsDir() {
return nil
}
// For each generated file, figure out the path to the corresponding
// golden file in the testdata directory.
relPath, err := filepath.Rel(workdir, genPath)
if err != nil {
t.Errorf("filepath.Rel(%q, %q): %v", workdir, genPath, err)
return nil
}
if filepath.SplitList(relPath)[0] == ".." {
t.Errorf("generated file %q is not relative to %q", genPath, workdir)
}
goldenPath := filepath.Join("testdata", relPath)
got, err := ioutil.ReadFile(genPath)
if err != nil {
t.Error(err)
return nil
}
if *regenerate {
// If --regenerate set, just rewrite the golden files.
err := ioutil.WriteFile(goldenPath, got, 0666)
if err != nil {
t.Error(err)
}
return nil
}
want, err := ioutil.ReadFile(goldenPath)
if err != nil {
t.Error(err)
return nil
}
want = fdescRE.ReplaceAll(want, nil)
got = fdescRE.ReplaceAll(got, nil)
if bytes.Equal(got, want) {
return nil
}
cmd := exec.Command("diff", "-u", goldenPath, genPath)
out, _ := cmd.CombinedOutput()
t.Errorf("golden file differs: %v\n%v", relPath, string(out))
return nil
})
}
var fdescRE = regexp.MustCompile(`(?ms)^var fileDescriptor.*}`)
// Source files used by TestParameters.
const (
aProto = `
syntax = "proto3";
package test.alpha;
option go_package = "package/alpha";
import "beta/b.proto";
message M { test.beta.M field = 1; }`
bProto = `
syntax = "proto3";
package test.beta;
// no go_package option
message M {}`
)
func TestParameters(t *testing.T) {
for _, test := range []struct {
parameters string
wantFiles map[string]bool
wantImportsA map[string]bool
wantPackageA string
wantPackageB string
}{{
parameters: "",
wantFiles: map[string]bool{
"package/alpha/a.pb.go": true,
"beta/b.pb.go": true,
},
wantPackageA: "alpha",
wantPackageB: "test_beta",
wantImportsA: map[string]bool{
"github.com/golang/protobuf/proto": true,
"beta": true,
},
}, {
parameters: "import_prefix=prefix",
wantFiles: map[string]bool{
"package/alpha/a.pb.go": true,
"beta/b.pb.go": true,
},
wantPackageA: "alpha",
wantPackageB: "test_beta",
wantImportsA: map[string]bool{
// This really doesn't seem like useful behavior.
"prefixgithub.com/golang/protobuf/proto": true,
"prefixbeta": true,
},
}, {
// import_path only affects the 'package' line.
parameters: "import_path=import/path/of/pkg",
wantPackageA: "alpha",
wantPackageB: "pkg",
wantFiles: map[string]bool{
"package/alpha/a.pb.go": true,
"beta/b.pb.go": true,
},
}, {
parameters: "Mbeta/b.proto=package/gamma",
wantFiles: map[string]bool{
"package/alpha/a.pb.go": true,
"beta/b.pb.go": true,
},
wantPackageA: "alpha",
wantPackageB: "test_beta",
wantImportsA: map[string]bool{
"github.com/golang/protobuf/proto": true,
// Rewritten by the M parameter.
"package/gamma": true,
},
}, {
parameters: "import_prefix=prefix,Mbeta/b.proto=package/gamma",
wantFiles: map[string]bool{
"package/alpha/a.pb.go": true,
"beta/b.pb.go": true,
},
wantPackageA: "alpha",
wantPackageB: "test_beta",
wantImportsA: map[string]bool{
// import_prefix applies after M.
"prefixpackage/gamma": true,
},
}, {
parameters: "paths=source_relative",
wantFiles: map[string]bool{
"alpha/a.pb.go": true,
"beta/b.pb.go": true,
},
wantPackageA: "alpha",
wantPackageB: "test_beta",
}, {
parameters: "paths=source_relative,import_prefix=prefix",
wantFiles: map[string]bool{
// import_prefix doesn't affect filenames.
"alpha/a.pb.go": true,
"beta/b.pb.go": true,
},
wantPackageA: "alpha",
wantPackageB: "test_beta",
}} {
name := test.parameters
if name == "" {
name = "defaults"
}
// TODO: Switch to t.Run when we no longer support Go 1.6.
t.Logf("TEST: %v", name)
workdir, err := ioutil.TempDir("", "proto-test")
if err != nil {
t.Fatal(err)
}
defer os.RemoveAll(workdir)
for _, dir := range []string{"alpha", "beta", "out"} {
if err := os.MkdirAll(filepath.Join(workdir, dir), 0777); err != nil {
t.Fatal(err)
}
}
if err := ioutil.WriteFile(filepath.Join(workdir, "alpha", "a.proto"), []byte(aProto), 0666); err != nil {
t.Fatal(err)
}
if err := ioutil.WriteFile(filepath.Join(workdir, "beta", "b.proto"), []byte(bProto), 0666); err != nil {
t.Fatal(err)
}
protoc(t, []string{
"-I" + workdir,
"--go_out=" + test.parameters + ":" + filepath.Join(workdir, "out"),
filepath.Join(workdir, "alpha", "a.proto"),
})
protoc(t, []string{
"-I" + workdir,
"--go_out=" + test.parameters + ":" + filepath.Join(workdir, "out"),
filepath.Join(workdir, "beta", "b.proto"),
})
contents := make(map[string]string)
gotFiles := make(map[string]bool)
outdir := filepath.Join(workdir, "out")
filepath.Walk(outdir, func(p string, info os.FileInfo, _ error) error {
if info.IsDir() {
return nil
}
base := filepath.Base(p)
if base == "a.pb.go" || base == "b.pb.go" {
b, err := ioutil.ReadFile(p)
if err != nil {
t.Fatal(err)
}
contents[base] = string(b)
}
relPath, _ := filepath.Rel(outdir, p)
gotFiles[relPath] = true
return nil
})
for got := range gotFiles {
if runtime.GOOS == "windows" {
got = filepath.ToSlash(got)
}
if !test.wantFiles[got] {
t.Errorf("unexpected output file: %v", got)
}
}
for want := range test.wantFiles {
if runtime.GOOS == "windows" {
want = filepath.FromSlash(want)
}
if !gotFiles[want] {
t.Errorf("missing output file: %v", want)
}
}
gotPackageA, gotImports, err := parseFile(contents["a.pb.go"])
if err != nil {
t.Fatal(err)
}
gotPackageB, _, err := parseFile(contents["b.pb.go"])
if err != nil {
t.Fatal(err)
}
if got, want := gotPackageA, test.wantPackageA; want != got {
t.Errorf("output file a.pb.go is package %q, want %q", got, want)
}
if got, want := gotPackageB, test.wantPackageB; want != got {
t.Errorf("output file b.pb.go is package %q, want %q", got, want)
}
missingImport := false
WantImport:
for want := range test.wantImportsA {
for _, imp := range gotImports {
if `"`+want+`"` == imp {
continue WantImport
}
}
t.Errorf("output file a.pb.go does not contain expected import %q", want)
missingImport = true
}
if missingImport {
t.Error("got imports:")
for _, imp := range gotImports {
t.Errorf(" %v", imp)
}
}
}
}
func TestPackageComment(t *testing.T) {
workdir, err := ioutil.TempDir("", "proto-test")
if err != nil {
t.Fatal(err)
}
defer os.RemoveAll(workdir)
var packageRE = regexp.MustCompile(`(?m)^package .*`)
for i, test := range []struct {
goPackageOption string
wantPackage string
}{{
goPackageOption: ``,
wantPackage: `package proto_package`,
}, {
goPackageOption: `option go_package = "go_package";`,
wantPackage: `package go_package`,
}, {
goPackageOption: `option go_package = "import/path/of/go_package";`,
wantPackage: `package go_package // import "import/path/of/go_package"`,
}, {
goPackageOption: `option go_package = "import/path/of/something;go_package";`,
wantPackage: `package go_package // import "import/path/of/something"`,
}, {
goPackageOption: `option go_package = "import_path;go_package";`,
wantPackage: `package go_package // import "import_path"`,
}} {
srcName := filepath.Join(workdir, fmt.Sprintf("%d.proto", i))
tgtName := filepath.Join(workdir, fmt.Sprintf("%d.pb.go", i))
buf := &bytes.Buffer{}
fmt.Fprintln(buf, `syntax = "proto3";`)
fmt.Fprintln(buf, `package proto_package;`)
fmt.Fprintln(buf, test.goPackageOption)
if err := ioutil.WriteFile(srcName, buf.Bytes(), 0666); err != nil {
t.Fatal(err)
}
protoc(t, []string{"-I" + workdir, "--go_out=paths=source_relative:" + workdir, srcName})
out, err := ioutil.ReadFile(tgtName)
if err != nil {
t.Fatal(err)
}
pkg := packageRE.Find(out)
if pkg == nil {
t.Errorf("generated .pb.go contains no package line\n\nsource:\n%v\n\noutput:\n%v", buf.String(), string(out))
continue
}
if got, want := string(pkg), test.wantPackage; got != want {
t.Errorf("unexpected package statement with go_package = %q\n got: %v\nwant: %v", test.goPackageOption, got, want)
}
}
}
// parseFile returns a file's package name and a list of all packages it imports.
func parseFile(source string) (packageName string, imports []string, err error) {
fset := token.NewFileSet()
f, err := parser.ParseFile(fset, "<source>", source, parser.ImportsOnly)
if err != nil {
return "", nil, err
}
for _, imp := range f.Imports {
imports = append(imports, imp.Path.Value)
}
return f.Name.Name, imports, nil
}
func protoc(t *testing.T, args []string) {
cmd := exec.Command("protoc", "--plugin=protoc-gen-go="+os.Args[0])
cmd.Args = append(cmd.Args, args...)
// We set the RUN_AS_PROTOC_GEN_GO environment variable to indicate that
// the subprocess should act as a proto compiler rather than a test.
cmd.Env = append(os.Environ(), "RUN_AS_PROTOC_GEN_GO=1")
out, err := cmd.CombinedOutput()
if len(out) > 0 || err != nil {
t.Log("RUNNING: ", strings.Join(cmd.Args, " "))
}
if len(out) > 0 {
t.Log(string(out))
}
if err != nil {
t.Fatalf("protoc: %v", err)
}
}
func hasReleaseTag(want string) bool {
for _, tag := range build.Default.ReleaseTags {
if tag == want {
return true
}
}
return false
}

View file

@ -0,0 +1,34 @@
// Go support for Protocol Buffers - Google's data interchange format
//
// Copyright 2015 The Go Authors. All rights reserved.
// https://github.com/golang/protobuf
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
// * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
package main
import _ "github.com/golang/protobuf/protoc-gen-go/grpc"

View file

@ -0,0 +1,98 @@
// Go support for Protocol Buffers - Google's data interchange format
//
// Copyright 2010 The Go Authors. All rights reserved.
// https://github.com/golang/protobuf
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
// * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
// protoc-gen-go is a plugin for the Google protocol buffer compiler to generate
// Go code. Run it by building this program and putting it in your path with
// the name
// protoc-gen-go
// That word 'go' at the end becomes part of the option string set for the
// protocol compiler, so once the protocol compiler (protoc) is installed
// you can run
// protoc --go_out=output_directory input_directory/file.proto
// to generate Go bindings for the protocol defined by file.proto.
// With that input, the output will be written to
// output_directory/file.pb.go
//
// The generated code is documented in the package comment for
// the library.
//
// See the README and documentation for protocol buffers to learn more:
// https://developers.google.com/protocol-buffers/
package main
import (
"io/ioutil"
"os"
"github.com/golang/protobuf/proto"
"github.com/golang/protobuf/protoc-gen-go/generator"
)
func main() {
// Begin by allocating a generator. The request and response structures are stored there
// so we can do error handling easily - the response structure contains the field to
// report failure.
g := generator.New()
data, err := ioutil.ReadAll(os.Stdin)
if err != nil {
g.Error(err, "reading input")
}
if err := proto.Unmarshal(data, g.Request); err != nil {
g.Error(err, "parsing input proto")
}
if len(g.Request.FileToGenerate) == 0 {
g.Fail("no files to generate")
}
g.CommandLineParameters(g.Request.GetParameter())
// Create a wrapped version of the Descriptors and EnumDescriptors that
// point to the file that defines them.
g.WrapTypes()
g.SetPackageNames()
g.BuildTypeNameMap()
g.GenerateAllFiles()
// Send back the results.
data, err = proto.Marshal(g.Response)
if err != nil {
g.Error(err, "failed to marshal output proto")
}
_, err = os.Stdout.Write(data)
if err != nil {
g.Error(err, "failed to write output proto")
}
}

139
vendor/github.com/golang/protobuf/ptypes/any.go generated vendored Normal file
View file

@ -0,0 +1,139 @@
// Go support for Protocol Buffers - Google's data interchange format
//
// Copyright 2016 The Go Authors. All rights reserved.
// https://github.com/golang/protobuf
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
// * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
package ptypes
// This file implements functions to marshal proto.Message to/from
// google.protobuf.Any message.
import (
"fmt"
"reflect"
"strings"
"github.com/golang/protobuf/proto"
"github.com/golang/protobuf/ptypes/any"
)
const googleApis = "type.googleapis.com/"
// AnyMessageName returns the name of the message contained in a google.protobuf.Any message.
//
// Note that regular type assertions should be done using the Is
// function. AnyMessageName is provided for less common use cases like filtering a
// sequence of Any messages based on a set of allowed message type names.
func AnyMessageName(any *any.Any) (string, error) {
if any == nil {
return "", fmt.Errorf("message is nil")
}
slash := strings.LastIndex(any.TypeUrl, "/")
if slash < 0 {
return "", fmt.Errorf("message type url %q is invalid", any.TypeUrl)
}
return any.TypeUrl[slash+1:], nil
}
// MarshalAny takes the protocol buffer and encodes it into google.protobuf.Any.
func MarshalAny(pb proto.Message) (*any.Any, error) {
value, err := proto.Marshal(pb)
if err != nil {
return nil, err
}
return &any.Any{TypeUrl: googleApis + proto.MessageName(pb), Value: value}, nil
}
// DynamicAny is a value that can be passed to UnmarshalAny to automatically
// allocate a proto.Message for the type specified in a google.protobuf.Any
// message. The allocated message is stored in the embedded proto.Message.
//
// Example:
//
// var x ptypes.DynamicAny
// if err := ptypes.UnmarshalAny(a, &x); err != nil { ... }
// fmt.Printf("unmarshaled message: %v", x.Message)
type DynamicAny struct {
proto.Message
}
// Empty returns a new proto.Message of the type specified in a
// google.protobuf.Any message. It returns an error if corresponding message
// type isn't linked in.
func Empty(any *any.Any) (proto.Message, error) {
aname, err := AnyMessageName(any)
if err != nil {
return nil, err
}
t := proto.MessageType(aname)
if t == nil {
return nil, fmt.Errorf("any: message type %q isn't linked in", aname)
}
return reflect.New(t.Elem()).Interface().(proto.Message), nil
}
// UnmarshalAny parses the protocol buffer representation in a google.protobuf.Any
// message and places the decoded result in pb. It returns an error if type of
// contents of Any message does not match type of pb message.
//
// pb can be a proto.Message, or a *DynamicAny.
func UnmarshalAny(any *any.Any, pb proto.Message) error {
if d, ok := pb.(*DynamicAny); ok {
if d.Message == nil {
var err error
d.Message, err = Empty(any)
if err != nil {
return err
}
}
return UnmarshalAny(any, d.Message)
}
aname, err := AnyMessageName(any)
if err != nil {
return err
}
mname := proto.MessageName(pb)
if aname != mname {
return fmt.Errorf("mismatched message type: got %q want %q", aname, mname)
}
return proto.Unmarshal(any.Value, pb)
}
// Is returns true if any value contains a given message type.
func Is(any *any.Any, pb proto.Message) bool {
aname, err := AnyMessageName(any)
if err != nil {
return false
}
return aname == proto.MessageName(pb)
}

191
vendor/github.com/golang/protobuf/ptypes/any/any.pb.go generated vendored Normal file
View file

@ -0,0 +1,191 @@
// Code generated by protoc-gen-go. DO NOT EDIT.
// source: google/protobuf/any.proto
package any // import "github.com/golang/protobuf/ptypes/any"
import proto "github.com/golang/protobuf/proto"
import fmt "fmt"
import math "math"
// Reference imports to suppress errors if they are not otherwise used.
var _ = proto.Marshal
var _ = fmt.Errorf
var _ = math.Inf
// This is a compile-time assertion to ensure that this generated file
// is compatible with the proto package it is being compiled against.
// A compilation error at this line likely means your copy of the
// proto package needs to be updated.
const _ = proto.ProtoPackageIsVersion2 // please upgrade the proto package
// `Any` contains an arbitrary serialized protocol buffer message along with a
// URL that describes the type of the serialized message.
//
// Protobuf library provides support to pack/unpack Any values in the form
// of utility functions or additional generated methods of the Any type.
//
// Example 1: Pack and unpack a message in C++.
//
// Foo foo = ...;
// Any any;
// any.PackFrom(foo);
// ...
// if (any.UnpackTo(&foo)) {
// ...
// }
//
// Example 2: Pack and unpack a message in Java.
//
// Foo foo = ...;
// Any any = Any.pack(foo);
// ...
// if (any.is(Foo.class)) {
// foo = any.unpack(Foo.class);
// }
//
// Example 3: Pack and unpack a message in Python.
//
// foo = Foo(...)
// any = Any()
// any.Pack(foo)
// ...
// if any.Is(Foo.DESCRIPTOR):
// any.Unpack(foo)
// ...
//
// Example 4: Pack and unpack a message in Go
//
// foo := &pb.Foo{...}
// any, err := ptypes.MarshalAny(foo)
// ...
// foo := &pb.Foo{}
// if err := ptypes.UnmarshalAny(any, foo); err != nil {
// ...
// }
//
// The pack methods provided by protobuf library will by default use
// 'type.googleapis.com/full.type.name' as the type URL and the unpack
// methods only use the fully qualified type name after the last '/'
// in the type URL, for example "foo.bar.com/x/y.z" will yield type
// name "y.z".
//
//
// JSON
// ====
// The JSON representation of an `Any` value uses the regular
// representation of the deserialized, embedded message, with an
// additional field `@type` which contains the type URL. Example:
//
// package google.profile;
// message Person {
// string first_name = 1;
// string last_name = 2;
// }
//
// {
// "@type": "type.googleapis.com/google.profile.Person",
// "firstName": <string>,
// "lastName": <string>
// }
//
// If the embedded message type is well-known and has a custom JSON
// representation, that representation will be embedded adding a field
// `value` which holds the custom JSON in addition to the `@type`
// field. Example (for message [google.protobuf.Duration][]):
//
// {
// "@type": "type.googleapis.com/google.protobuf.Duration",
// "value": "1.212s"
// }
//
type Any struct {
// A URL/resource name whose content describes the type of the
// serialized protocol buffer message.
//
// For URLs which use the scheme `http`, `https`, or no scheme, the
// following restrictions and interpretations apply:
//
// * If no scheme is provided, `https` is assumed.
// * The last segment of the URL's path must represent the fully
// qualified name of the type (as in `path/google.protobuf.Duration`).
// The name should be in a canonical form (e.g., leading "." is
// not accepted).
// * An HTTP GET on the URL must yield a [google.protobuf.Type][]
// value in binary format, or produce an error.
// * Applications are allowed to cache lookup results based on the
// URL, or have them precompiled into a binary to avoid any
// lookup. Therefore, binary compatibility needs to be preserved
// on changes to types. (Use versioned type names to manage
// breaking changes.)
//
// Schemes other than `http`, `https` (or the empty scheme) might be
// used with implementation specific semantics.
//
TypeUrl string `protobuf:"bytes,1,opt,name=type_url,json=typeUrl" json:"type_url,omitempty"`
// Must be a valid serialized protocol buffer of the above specified type.
Value []byte `protobuf:"bytes,2,opt,name=value,proto3" json:"value,omitempty"`
XXX_NoUnkeyedLiteral struct{} `json:"-"`
XXX_unrecognized []byte `json:"-"`
XXX_sizecache int32 `json:"-"`
}
func (m *Any) Reset() { *m = Any{} }
func (m *Any) String() string { return proto.CompactTextString(m) }
func (*Any) ProtoMessage() {}
func (*Any) Descriptor() ([]byte, []int) {
return fileDescriptor_any_744b9ca530f228db, []int{0}
}
func (*Any) XXX_WellKnownType() string { return "Any" }
func (m *Any) XXX_Unmarshal(b []byte) error {
return xxx_messageInfo_Any.Unmarshal(m, b)
}
func (m *Any) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
return xxx_messageInfo_Any.Marshal(b, m, deterministic)
}
func (dst *Any) XXX_Merge(src proto.Message) {
xxx_messageInfo_Any.Merge(dst, src)
}
func (m *Any) XXX_Size() int {
return xxx_messageInfo_Any.Size(m)
}
func (m *Any) XXX_DiscardUnknown() {
xxx_messageInfo_Any.DiscardUnknown(m)
}
var xxx_messageInfo_Any proto.InternalMessageInfo
func (m *Any) GetTypeUrl() string {
if m != nil {
return m.TypeUrl
}
return ""
}
func (m *Any) GetValue() []byte {
if m != nil {
return m.Value
}
return nil
}
func init() {
proto.RegisterType((*Any)(nil), "google.protobuf.Any")
}
func init() { proto.RegisterFile("google/protobuf/any.proto", fileDescriptor_any_744b9ca530f228db) }
var fileDescriptor_any_744b9ca530f228db = []byte{
// 185 bytes of a gzipped FileDescriptorProto
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xe2, 0x92, 0x4c, 0xcf, 0xcf, 0x4f,
0xcf, 0x49, 0xd5, 0x2f, 0x28, 0xca, 0x2f, 0xc9, 0x4f, 0x2a, 0x4d, 0xd3, 0x4f, 0xcc, 0xab, 0xd4,
0x03, 0x73, 0x84, 0xf8, 0x21, 0x52, 0x7a, 0x30, 0x29, 0x25, 0x33, 0x2e, 0x66, 0xc7, 0xbc, 0x4a,
0x21, 0x49, 0x2e, 0x8e, 0x92, 0xca, 0x82, 0xd4, 0xf8, 0xd2, 0xa2, 0x1c, 0x09, 0x46, 0x05, 0x46,
0x0d, 0xce, 0x20, 0x76, 0x10, 0x3f, 0xb4, 0x28, 0x47, 0x48, 0x84, 0x8b, 0xb5, 0x2c, 0x31, 0xa7,
0x34, 0x55, 0x82, 0x49, 0x81, 0x51, 0x83, 0x27, 0x08, 0xc2, 0x71, 0xca, 0xe7, 0x12, 0x4e, 0xce,
0xcf, 0xd5, 0x43, 0x33, 0xce, 0x89, 0xc3, 0x31, 0xaf, 0x32, 0x00, 0xc4, 0x09, 0x60, 0x8c, 0x52,
0x4d, 0xcf, 0x2c, 0xc9, 0x28, 0x4d, 0xd2, 0x4b, 0xce, 0xcf, 0xd5, 0x4f, 0xcf, 0xcf, 0x49, 0xcc,
0x4b, 0x47, 0xb8, 0xa8, 0x00, 0x64, 0x7a, 0x31, 0xc8, 0x61, 0x8b, 0x98, 0x98, 0xdd, 0x03, 0x9c,
0x56, 0x31, 0xc9, 0xb9, 0x43, 0x8c, 0x0a, 0x80, 0x2a, 0xd1, 0x0b, 0x4f, 0xcd, 0xc9, 0xf1, 0xce,
0xcb, 0x2f, 0xcf, 0x0b, 0x01, 0x29, 0x4d, 0x62, 0x03, 0xeb, 0x35, 0x06, 0x04, 0x00, 0x00, 0xff,
0xff, 0x13, 0xf8, 0xe8, 0x42, 0xdd, 0x00, 0x00, 0x00,
}

149
vendor/github.com/golang/protobuf/ptypes/any/any.proto generated vendored Normal file
View file

@ -0,0 +1,149 @@
// Protocol Buffers - Google's data interchange format
// Copyright 2008 Google Inc. All rights reserved.
// https://developers.google.com/protocol-buffers/
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
// * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
syntax = "proto3";
package google.protobuf;
option csharp_namespace = "Google.Protobuf.WellKnownTypes";
option go_package = "github.com/golang/protobuf/ptypes/any";
option java_package = "com.google.protobuf";
option java_outer_classname = "AnyProto";
option java_multiple_files = true;
option objc_class_prefix = "GPB";
// `Any` contains an arbitrary serialized protocol buffer message along with a
// URL that describes the type of the serialized message.
//
// Protobuf library provides support to pack/unpack Any values in the form
// of utility functions or additional generated methods of the Any type.
//
// Example 1: Pack and unpack a message in C++.
//
// Foo foo = ...;
// Any any;
// any.PackFrom(foo);
// ...
// if (any.UnpackTo(&foo)) {
// ...
// }
//
// Example 2: Pack and unpack a message in Java.
//
// Foo foo = ...;
// Any any = Any.pack(foo);
// ...
// if (any.is(Foo.class)) {
// foo = any.unpack(Foo.class);
// }
//
// Example 3: Pack and unpack a message in Python.
//
// foo = Foo(...)
// any = Any()
// any.Pack(foo)
// ...
// if any.Is(Foo.DESCRIPTOR):
// any.Unpack(foo)
// ...
//
// Example 4: Pack and unpack a message in Go
//
// foo := &pb.Foo{...}
// any, err := ptypes.MarshalAny(foo)
// ...
// foo := &pb.Foo{}
// if err := ptypes.UnmarshalAny(any, foo); err != nil {
// ...
// }
//
// The pack methods provided by protobuf library will by default use
// 'type.googleapis.com/full.type.name' as the type URL and the unpack
// methods only use the fully qualified type name after the last '/'
// in the type URL, for example "foo.bar.com/x/y.z" will yield type
// name "y.z".
//
//
// JSON
// ====
// The JSON representation of an `Any` value uses the regular
// representation of the deserialized, embedded message, with an
// additional field `@type` which contains the type URL. Example:
//
// package google.profile;
// message Person {
// string first_name = 1;
// string last_name = 2;
// }
//
// {
// "@type": "type.googleapis.com/google.profile.Person",
// "firstName": <string>,
// "lastName": <string>
// }
//
// If the embedded message type is well-known and has a custom JSON
// representation, that representation will be embedded adding a field
// `value` which holds the custom JSON in addition to the `@type`
// field. Example (for message [google.protobuf.Duration][]):
//
// {
// "@type": "type.googleapis.com/google.protobuf.Duration",
// "value": "1.212s"
// }
//
message Any {
// A URL/resource name whose content describes the type of the
// serialized protocol buffer message.
//
// For URLs which use the scheme `http`, `https`, or no scheme, the
// following restrictions and interpretations apply:
//
// * If no scheme is provided, `https` is assumed.
// * The last segment of the URL's path must represent the fully
// qualified name of the type (as in `path/google.protobuf.Duration`).
// The name should be in a canonical form (e.g., leading "." is
// not accepted).
// * An HTTP GET on the URL must yield a [google.protobuf.Type][]
// value in binary format, or produce an error.
// * Applications are allowed to cache lookup results based on the
// URL, or have them precompiled into a binary to avoid any
// lookup. Therefore, binary compatibility needs to be preserved
// on changes to types. (Use versioned type names to manage
// breaking changes.)
//
// Schemes other than `http`, `https` (or the empty scheme) might be
// used with implementation specific semantics.
//
string type_url = 1;
// Must be a valid serialized protocol buffer of the above specified type.
bytes value = 2;
}

113
vendor/github.com/golang/protobuf/ptypes/any_test.go generated vendored Normal file
View file

@ -0,0 +1,113 @@
// Go support for Protocol Buffers - Google's data interchange format
//
// Copyright 2016 The Go Authors. All rights reserved.
// https://github.com/golang/protobuf
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
// * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
package ptypes
import (
"testing"
"github.com/golang/protobuf/proto"
pb "github.com/golang/protobuf/protoc-gen-go/descriptor"
"github.com/golang/protobuf/ptypes/any"
)
func TestMarshalUnmarshal(t *testing.T) {
orig := &any.Any{Value: []byte("test")}
packed, err := MarshalAny(orig)
if err != nil {
t.Errorf("MarshalAny(%+v): got: _, %v exp: _, nil", orig, err)
}
unpacked := &any.Any{}
err = UnmarshalAny(packed, unpacked)
if err != nil || !proto.Equal(unpacked, orig) {
t.Errorf("got: %v, %+v; want nil, %+v", err, unpacked, orig)
}
}
func TestIs(t *testing.T) {
a, err := MarshalAny(&pb.FileDescriptorProto{})
if err != nil {
t.Fatal(err)
}
if Is(a, &pb.DescriptorProto{}) {
t.Error("FileDescriptorProto is not a DescriptorProto, but Is says it is")
}
if !Is(a, &pb.FileDescriptorProto{}) {
t.Error("FileDescriptorProto is indeed a FileDescriptorProto, but Is says it is not")
}
}
func TestIsDifferentUrlPrefixes(t *testing.T) {
m := &pb.FileDescriptorProto{}
a := &any.Any{TypeUrl: "foo/bar/" + proto.MessageName(m)}
if !Is(a, m) {
t.Errorf("message with type url %q didn't satisfy Is for type %q", a.TypeUrl, proto.MessageName(m))
}
}
func TestUnmarshalDynamic(t *testing.T) {
want := &pb.FileDescriptorProto{Name: proto.String("foo")}
a, err := MarshalAny(want)
if err != nil {
t.Fatal(err)
}
var got DynamicAny
if err := UnmarshalAny(a, &got); err != nil {
t.Fatal(err)
}
if !proto.Equal(got.Message, want) {
t.Errorf("invalid result from UnmarshalAny, got %q want %q", got.Message, want)
}
}
func TestEmpty(t *testing.T) {
want := &pb.FileDescriptorProto{}
a, err := MarshalAny(want)
if err != nil {
t.Fatal(err)
}
got, err := Empty(a)
if err != nil {
t.Fatal(err)
}
if !proto.Equal(got, want) {
t.Errorf("unequal empty message, got %q, want %q", got, want)
}
// that's a valid type_url for a message which shouldn't be linked into this
// test binary. We want an error.
a.TypeUrl = "type.googleapis.com/google.protobuf.FieldMask"
if _, err := Empty(a); err == nil {
t.Errorf("got no error for an attempt to create a message of type %q, which shouldn't be linked in", a.TypeUrl)
}
}

35
vendor/github.com/golang/protobuf/ptypes/doc.go generated vendored Normal file
View file

@ -0,0 +1,35 @@
// Go support for Protocol Buffers - Google's data interchange format
//
// Copyright 2016 The Go Authors. All rights reserved.
// https://github.com/golang/protobuf
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
// * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
/*
Package ptypes contains code for interacting with well-known types.
*/
package ptypes

102
vendor/github.com/golang/protobuf/ptypes/duration.go generated vendored Normal file
View file

@ -0,0 +1,102 @@
// Go support for Protocol Buffers - Google's data interchange format
//
// Copyright 2016 The Go Authors. All rights reserved.
// https://github.com/golang/protobuf
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
// * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
package ptypes
// This file implements conversions between google.protobuf.Duration
// and time.Duration.
import (
"errors"
"fmt"
"time"
durpb "github.com/golang/protobuf/ptypes/duration"
)
const (
// Range of a durpb.Duration in seconds, as specified in
// google/protobuf/duration.proto. This is about 10,000 years in seconds.
maxSeconds = int64(10000 * 365.25 * 24 * 60 * 60)
minSeconds = -maxSeconds
)
// validateDuration determines whether the durpb.Duration is valid according to the
// definition in google/protobuf/duration.proto. A valid durpb.Duration
// may still be too large to fit into a time.Duration (the range of durpb.Duration
// is about 10,000 years, and the range of time.Duration is about 290).
func validateDuration(d *durpb.Duration) error {
if d == nil {
return errors.New("duration: nil Duration")
}
if d.Seconds < minSeconds || d.Seconds > maxSeconds {
return fmt.Errorf("duration: %v: seconds out of range", d)
}
if d.Nanos <= -1e9 || d.Nanos >= 1e9 {
return fmt.Errorf("duration: %v: nanos out of range", d)
}
// Seconds and Nanos must have the same sign, unless d.Nanos is zero.
if (d.Seconds < 0 && d.Nanos > 0) || (d.Seconds > 0 && d.Nanos < 0) {
return fmt.Errorf("duration: %v: seconds and nanos have different signs", d)
}
return nil
}
// Duration converts a durpb.Duration to a time.Duration. Duration
// returns an error if the durpb.Duration is invalid or is too large to be
// represented in a time.Duration.
func Duration(p *durpb.Duration) (time.Duration, error) {
if err := validateDuration(p); err != nil {
return 0, err
}
d := time.Duration(p.Seconds) * time.Second
if int64(d/time.Second) != p.Seconds {
return 0, fmt.Errorf("duration: %v is out of range for time.Duration", p)
}
if p.Nanos != 0 {
d += time.Duration(p.Nanos)
if (d < 0) != (p.Nanos < 0) {
return 0, fmt.Errorf("duration: %v is out of range for time.Duration", p)
}
}
return d, nil
}
// DurationProto converts a time.Duration to a durpb.Duration.
func DurationProto(d time.Duration) *durpb.Duration {
nanos := d.Nanoseconds()
secs := nanos / 1e9
nanos -= secs * 1e9
return &durpb.Duration{
Seconds: secs,
Nanos: int32(nanos),
}
}

View file

@ -0,0 +1,159 @@
// Code generated by protoc-gen-go. DO NOT EDIT.
// source: google/protobuf/duration.proto
package duration // import "github.com/golang/protobuf/ptypes/duration"
import proto "github.com/golang/protobuf/proto"
import fmt "fmt"
import math "math"
// Reference imports to suppress errors if they are not otherwise used.
var _ = proto.Marshal
var _ = fmt.Errorf
var _ = math.Inf
// This is a compile-time assertion to ensure that this generated file
// is compatible with the proto package it is being compiled against.
// A compilation error at this line likely means your copy of the
// proto package needs to be updated.
const _ = proto.ProtoPackageIsVersion2 // please upgrade the proto package
// A Duration represents a signed, fixed-length span of time represented
// as a count of seconds and fractions of seconds at nanosecond
// resolution. It is independent of any calendar and concepts like "day"
// or "month". It is related to Timestamp in that the difference between
// two Timestamp values is a Duration and it can be added or subtracted
// from a Timestamp. Range is approximately +-10,000 years.
//
// # Examples
//
// Example 1: Compute Duration from two Timestamps in pseudo code.
//
// Timestamp start = ...;
// Timestamp end = ...;
// Duration duration = ...;
//
// duration.seconds = end.seconds - start.seconds;
// duration.nanos = end.nanos - start.nanos;
//
// if (duration.seconds < 0 && duration.nanos > 0) {
// duration.seconds += 1;
// duration.nanos -= 1000000000;
// } else if (durations.seconds > 0 && duration.nanos < 0) {
// duration.seconds -= 1;
// duration.nanos += 1000000000;
// }
//
// Example 2: Compute Timestamp from Timestamp + Duration in pseudo code.
//
// Timestamp start = ...;
// Duration duration = ...;
// Timestamp end = ...;
//
// end.seconds = start.seconds + duration.seconds;
// end.nanos = start.nanos + duration.nanos;
//
// if (end.nanos < 0) {
// end.seconds -= 1;
// end.nanos += 1000000000;
// } else if (end.nanos >= 1000000000) {
// end.seconds += 1;
// end.nanos -= 1000000000;
// }
//
// Example 3: Compute Duration from datetime.timedelta in Python.
//
// td = datetime.timedelta(days=3, minutes=10)
// duration = Duration()
// duration.FromTimedelta(td)
//
// # JSON Mapping
//
// In JSON format, the Duration type is encoded as a string rather than an
// object, where the string ends in the suffix "s" (indicating seconds) and
// is preceded by the number of seconds, with nanoseconds expressed as
// fractional seconds. For example, 3 seconds with 0 nanoseconds should be
// encoded in JSON format as "3s", while 3 seconds and 1 nanosecond should
// be expressed in JSON format as "3.000000001s", and 3 seconds and 1
// microsecond should be expressed in JSON format as "3.000001s".
//
//
type Duration struct {
// Signed seconds of the span of time. Must be from -315,576,000,000
// to +315,576,000,000 inclusive. Note: these bounds are computed from:
// 60 sec/min * 60 min/hr * 24 hr/day * 365.25 days/year * 10000 years
Seconds int64 `protobuf:"varint,1,opt,name=seconds" json:"seconds,omitempty"`
// Signed fractions of a second at nanosecond resolution of the span
// of time. Durations less than one second are represented with a 0
// `seconds` field and a positive or negative `nanos` field. For durations
// of one second or more, a non-zero value for the `nanos` field must be
// of the same sign as the `seconds` field. Must be from -999,999,999
// to +999,999,999 inclusive.
Nanos int32 `protobuf:"varint,2,opt,name=nanos" json:"nanos,omitempty"`
XXX_NoUnkeyedLiteral struct{} `json:"-"`
XXX_unrecognized []byte `json:"-"`
XXX_sizecache int32 `json:"-"`
}
func (m *Duration) Reset() { *m = Duration{} }
func (m *Duration) String() string { return proto.CompactTextString(m) }
func (*Duration) ProtoMessage() {}
func (*Duration) Descriptor() ([]byte, []int) {
return fileDescriptor_duration_e7d612259e3f0613, []int{0}
}
func (*Duration) XXX_WellKnownType() string { return "Duration" }
func (m *Duration) XXX_Unmarshal(b []byte) error {
return xxx_messageInfo_Duration.Unmarshal(m, b)
}
func (m *Duration) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
return xxx_messageInfo_Duration.Marshal(b, m, deterministic)
}
func (dst *Duration) XXX_Merge(src proto.Message) {
xxx_messageInfo_Duration.Merge(dst, src)
}
func (m *Duration) XXX_Size() int {
return xxx_messageInfo_Duration.Size(m)
}
func (m *Duration) XXX_DiscardUnknown() {
xxx_messageInfo_Duration.DiscardUnknown(m)
}
var xxx_messageInfo_Duration proto.InternalMessageInfo
func (m *Duration) GetSeconds() int64 {
if m != nil {
return m.Seconds
}
return 0
}
func (m *Duration) GetNanos() int32 {
if m != nil {
return m.Nanos
}
return 0
}
func init() {
proto.RegisterType((*Duration)(nil), "google.protobuf.Duration")
}
func init() {
proto.RegisterFile("google/protobuf/duration.proto", fileDescriptor_duration_e7d612259e3f0613)
}
var fileDescriptor_duration_e7d612259e3f0613 = []byte{
// 190 bytes of a gzipped FileDescriptorProto
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xe2, 0x92, 0x4b, 0xcf, 0xcf, 0x4f,
0xcf, 0x49, 0xd5, 0x2f, 0x28, 0xca, 0x2f, 0xc9, 0x4f, 0x2a, 0x4d, 0xd3, 0x4f, 0x29, 0x2d, 0x4a,
0x2c, 0xc9, 0xcc, 0xcf, 0xd3, 0x03, 0x8b, 0x08, 0xf1, 0x43, 0xe4, 0xf5, 0x60, 0xf2, 0x4a, 0x56,
0x5c, 0x1c, 0x2e, 0x50, 0x25, 0x42, 0x12, 0x5c, 0xec, 0xc5, 0xa9, 0xc9, 0xf9, 0x79, 0x29, 0xc5,
0x12, 0x8c, 0x0a, 0x8c, 0x1a, 0xcc, 0x41, 0x30, 0xae, 0x90, 0x08, 0x17, 0x6b, 0x5e, 0x62, 0x5e,
0x7e, 0xb1, 0x04, 0x93, 0x02, 0xa3, 0x06, 0x6b, 0x10, 0x84, 0xe3, 0x54, 0xc3, 0x25, 0x9c, 0x9c,
0x9f, 0xab, 0x87, 0x66, 0xa4, 0x13, 0x2f, 0xcc, 0xc0, 0x00, 0x90, 0x48, 0x00, 0x63, 0x94, 0x56,
0x7a, 0x66, 0x49, 0x46, 0x69, 0x92, 0x5e, 0x72, 0x7e, 0xae, 0x7e, 0x7a, 0x7e, 0x4e, 0x62, 0x5e,
0x3a, 0xc2, 0x7d, 0x05, 0x25, 0x95, 0x05, 0xa9, 0xc5, 0x70, 0x67, 0xfe, 0x60, 0x64, 0x5c, 0xc4,
0xc4, 0xec, 0x1e, 0xe0, 0xb4, 0x8a, 0x49, 0xce, 0x1d, 0x62, 0x6e, 0x00, 0x54, 0xa9, 0x5e, 0x78,
0x6a, 0x4e, 0x8e, 0x77, 0x5e, 0x7e, 0x79, 0x5e, 0x08, 0x48, 0x4b, 0x12, 0x1b, 0xd8, 0x0c, 0x63,
0x40, 0x00, 0x00, 0x00, 0xff, 0xff, 0xdc, 0x84, 0x30, 0xff, 0xf3, 0x00, 0x00, 0x00,
}

View file

@ -0,0 +1,117 @@
// Protocol Buffers - Google's data interchange format
// Copyright 2008 Google Inc. All rights reserved.
// https://developers.google.com/protocol-buffers/
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
// * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
syntax = "proto3";
package google.protobuf;
option csharp_namespace = "Google.Protobuf.WellKnownTypes";
option cc_enable_arenas = true;
option go_package = "github.com/golang/protobuf/ptypes/duration";
option java_package = "com.google.protobuf";
option java_outer_classname = "DurationProto";
option java_multiple_files = true;
option objc_class_prefix = "GPB";
// A Duration represents a signed, fixed-length span of time represented
// as a count of seconds and fractions of seconds at nanosecond
// resolution. It is independent of any calendar and concepts like "day"
// or "month". It is related to Timestamp in that the difference between
// two Timestamp values is a Duration and it can be added or subtracted
// from a Timestamp. Range is approximately +-10,000 years.
//
// # Examples
//
// Example 1: Compute Duration from two Timestamps in pseudo code.
//
// Timestamp start = ...;
// Timestamp end = ...;
// Duration duration = ...;
//
// duration.seconds = end.seconds - start.seconds;
// duration.nanos = end.nanos - start.nanos;
//
// if (duration.seconds < 0 && duration.nanos > 0) {
// duration.seconds += 1;
// duration.nanos -= 1000000000;
// } else if (durations.seconds > 0 && duration.nanos < 0) {
// duration.seconds -= 1;
// duration.nanos += 1000000000;
// }
//
// Example 2: Compute Timestamp from Timestamp + Duration in pseudo code.
//
// Timestamp start = ...;
// Duration duration = ...;
// Timestamp end = ...;
//
// end.seconds = start.seconds + duration.seconds;
// end.nanos = start.nanos + duration.nanos;
//
// if (end.nanos < 0) {
// end.seconds -= 1;
// end.nanos += 1000000000;
// } else if (end.nanos >= 1000000000) {
// end.seconds += 1;
// end.nanos -= 1000000000;
// }
//
// Example 3: Compute Duration from datetime.timedelta in Python.
//
// td = datetime.timedelta(days=3, minutes=10)
// duration = Duration()
// duration.FromTimedelta(td)
//
// # JSON Mapping
//
// In JSON format, the Duration type is encoded as a string rather than an
// object, where the string ends in the suffix "s" (indicating seconds) and
// is preceded by the number of seconds, with nanoseconds expressed as
// fractional seconds. For example, 3 seconds with 0 nanoseconds should be
// encoded in JSON format as "3s", while 3 seconds and 1 nanosecond should
// be expressed in JSON format as "3.000000001s", and 3 seconds and 1
// microsecond should be expressed in JSON format as "3.000001s".
//
//
message Duration {
// Signed seconds of the span of time. Must be from -315,576,000,000
// to +315,576,000,000 inclusive. Note: these bounds are computed from:
// 60 sec/min * 60 min/hr * 24 hr/day * 365.25 days/year * 10000 years
int64 seconds = 1;
// Signed fractions of a second at nanosecond resolution of the span
// of time. Durations less than one second are represented with a 0
// `seconds` field and a positive or negative `nanos` field. For durations
// of one second or more, a non-zero value for the `nanos` field must be
// of the same sign as the `seconds` field. Must be from -999,999,999
// to +999,999,999 inclusive.
int32 nanos = 2;
}

View file

@ -0,0 +1,121 @@
// Go support for Protocol Buffers - Google's data interchange format
//
// Copyright 2016 The Go Authors. All rights reserved.
// https://github.com/golang/protobuf
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
// * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
package ptypes
import (
"math"
"testing"
"time"
"github.com/golang/protobuf/proto"
durpb "github.com/golang/protobuf/ptypes/duration"
)
const (
minGoSeconds = math.MinInt64 / int64(1e9)
maxGoSeconds = math.MaxInt64 / int64(1e9)
)
var durationTests = []struct {
proto *durpb.Duration
isValid bool
inRange bool
dur time.Duration
}{
// The zero duration.
{&durpb.Duration{Seconds: 0, Nanos: 0}, true, true, 0},
// Some ordinary non-zero durations.
{&durpb.Duration{Seconds: 100, Nanos: 0}, true, true, 100 * time.Second},
{&durpb.Duration{Seconds: -100, Nanos: 0}, true, true, -100 * time.Second},
{&durpb.Duration{Seconds: 100, Nanos: 987}, true, true, 100*time.Second + 987},
{&durpb.Duration{Seconds: -100, Nanos: -987}, true, true, -(100*time.Second + 987)},
// The largest duration representable in Go.
{&durpb.Duration{Seconds: maxGoSeconds, Nanos: int32(math.MaxInt64 - 1e9*maxGoSeconds)}, true, true, math.MaxInt64},
// The smallest duration representable in Go.
{&durpb.Duration{Seconds: minGoSeconds, Nanos: int32(math.MinInt64 - 1e9*minGoSeconds)}, true, true, math.MinInt64},
{nil, false, false, 0},
{&durpb.Duration{Seconds: -100, Nanos: 987}, false, false, 0},
{&durpb.Duration{Seconds: 100, Nanos: -987}, false, false, 0},
{&durpb.Duration{Seconds: math.MinInt64, Nanos: 0}, false, false, 0},
{&durpb.Duration{Seconds: math.MaxInt64, Nanos: 0}, false, false, 0},
// The largest valid duration.
{&durpb.Duration{Seconds: maxSeconds, Nanos: 1e9 - 1}, true, false, 0},
// The smallest valid duration.
{&durpb.Duration{Seconds: minSeconds, Nanos: -(1e9 - 1)}, true, false, 0},
// The smallest invalid duration above the valid range.
{&durpb.Duration{Seconds: maxSeconds + 1, Nanos: 0}, false, false, 0},
// The largest invalid duration below the valid range.
{&durpb.Duration{Seconds: minSeconds - 1, Nanos: -(1e9 - 1)}, false, false, 0},
// One nanosecond past the largest duration representable in Go.
{&durpb.Duration{Seconds: maxGoSeconds, Nanos: int32(math.MaxInt64-1e9*maxGoSeconds) + 1}, true, false, 0},
// One nanosecond past the smallest duration representable in Go.
{&durpb.Duration{Seconds: minGoSeconds, Nanos: int32(math.MinInt64-1e9*minGoSeconds) - 1}, true, false, 0},
// One second past the largest duration representable in Go.
{&durpb.Duration{Seconds: maxGoSeconds + 1, Nanos: int32(math.MaxInt64 - 1e9*maxGoSeconds)}, true, false, 0},
// One second past the smallest duration representable in Go.
{&durpb.Duration{Seconds: minGoSeconds - 1, Nanos: int32(math.MinInt64 - 1e9*minGoSeconds)}, true, false, 0},
}
func TestValidateDuration(t *testing.T) {
for _, test := range durationTests {
err := validateDuration(test.proto)
gotValid := (err == nil)
if gotValid != test.isValid {
t.Errorf("validateDuration(%v) = %t, want %t", test.proto, gotValid, test.isValid)
}
}
}
func TestDuration(t *testing.T) {
for _, test := range durationTests {
got, err := Duration(test.proto)
gotOK := (err == nil)
wantOK := test.isValid && test.inRange
if gotOK != wantOK {
t.Errorf("Duration(%v) ok = %t, want %t", test.proto, gotOK, wantOK)
}
if err == nil && got != test.dur {
t.Errorf("Duration(%v) = %v, want %v", test.proto, got, test.dur)
}
}
}
func TestDurationProto(t *testing.T) {
for _, test := range durationTests {
if test.isValid && test.inRange {
got := DurationProto(test.dur)
if !proto.Equal(got, test.proto) {
t.Errorf("DurationProto(%v) = %v, want %v", test.dur, got, test.proto)
}
}
}
}

View file

@ -0,0 +1,79 @@
// Code generated by protoc-gen-go. DO NOT EDIT.
// source: google/protobuf/empty.proto
package empty // import "github.com/golang/protobuf/ptypes/empty"
import proto "github.com/golang/protobuf/proto"
import fmt "fmt"
import math "math"
// Reference imports to suppress errors if they are not otherwise used.
var _ = proto.Marshal
var _ = fmt.Errorf
var _ = math.Inf
// This is a compile-time assertion to ensure that this generated file
// is compatible with the proto package it is being compiled against.
// A compilation error at this line likely means your copy of the
// proto package needs to be updated.
const _ = proto.ProtoPackageIsVersion2 // please upgrade the proto package
// A generic empty message that you can re-use to avoid defining duplicated
// empty messages in your APIs. A typical example is to use it as the request
// or the response type of an API method. For instance:
//
// service Foo {
// rpc Bar(google.protobuf.Empty) returns (google.protobuf.Empty);
// }
//
// The JSON representation for `Empty` is empty JSON object `{}`.
type Empty struct {
XXX_NoUnkeyedLiteral struct{} `json:"-"`
XXX_unrecognized []byte `json:"-"`
XXX_sizecache int32 `json:"-"`
}
func (m *Empty) Reset() { *m = Empty{} }
func (m *Empty) String() string { return proto.CompactTextString(m) }
func (*Empty) ProtoMessage() {}
func (*Empty) Descriptor() ([]byte, []int) {
return fileDescriptor_empty_39e6d6db0632e5b2, []int{0}
}
func (*Empty) XXX_WellKnownType() string { return "Empty" }
func (m *Empty) XXX_Unmarshal(b []byte) error {
return xxx_messageInfo_Empty.Unmarshal(m, b)
}
func (m *Empty) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
return xxx_messageInfo_Empty.Marshal(b, m, deterministic)
}
func (dst *Empty) XXX_Merge(src proto.Message) {
xxx_messageInfo_Empty.Merge(dst, src)
}
func (m *Empty) XXX_Size() int {
return xxx_messageInfo_Empty.Size(m)
}
func (m *Empty) XXX_DiscardUnknown() {
xxx_messageInfo_Empty.DiscardUnknown(m)
}
var xxx_messageInfo_Empty proto.InternalMessageInfo
func init() {
proto.RegisterType((*Empty)(nil), "google.protobuf.Empty")
}
func init() { proto.RegisterFile("google/protobuf/empty.proto", fileDescriptor_empty_39e6d6db0632e5b2) }
var fileDescriptor_empty_39e6d6db0632e5b2 = []byte{
// 148 bytes of a gzipped FileDescriptorProto
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xe2, 0x92, 0x4e, 0xcf, 0xcf, 0x4f,
0xcf, 0x49, 0xd5, 0x2f, 0x28, 0xca, 0x2f, 0xc9, 0x4f, 0x2a, 0x4d, 0xd3, 0x4f, 0xcd, 0x2d, 0x28,
0xa9, 0xd4, 0x03, 0x73, 0x85, 0xf8, 0x21, 0x92, 0x7a, 0x30, 0x49, 0x25, 0x76, 0x2e, 0x56, 0x57,
0x90, 0xbc, 0x53, 0x19, 0x97, 0x70, 0x72, 0x7e, 0xae, 0x1e, 0x9a, 0xbc, 0x13, 0x17, 0x58, 0x36,
0x00, 0xc4, 0x0d, 0x60, 0x8c, 0x52, 0x4f, 0xcf, 0x2c, 0xc9, 0x28, 0x4d, 0xd2, 0x4b, 0xce, 0xcf,
0xd5, 0x4f, 0xcf, 0xcf, 0x49, 0xcc, 0x4b, 0x47, 0x58, 0x53, 0x50, 0x52, 0x59, 0x90, 0x5a, 0x0c,
0xb1, 0xed, 0x07, 0x23, 0xe3, 0x22, 0x26, 0x66, 0xf7, 0x00, 0xa7, 0x55, 0x4c, 0x72, 0xee, 0x10,
0x13, 0x03, 0xa0, 0xea, 0xf4, 0xc2, 0x53, 0x73, 0x72, 0xbc, 0xf3, 0xf2, 0xcb, 0xf3, 0x42, 0x40,
0xea, 0x93, 0xd8, 0xc0, 0x06, 0x18, 0x03, 0x02, 0x00, 0x00, 0xff, 0xff, 0x64, 0xd4, 0xb3, 0xa6,
0xb7, 0x00, 0x00, 0x00,
}

View file

@ -0,0 +1,52 @@
// Protocol Buffers - Google's data interchange format
// Copyright 2008 Google Inc. All rights reserved.
// https://developers.google.com/protocol-buffers/
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
// * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
syntax = "proto3";
package google.protobuf;
option csharp_namespace = "Google.Protobuf.WellKnownTypes";
option go_package = "github.com/golang/protobuf/ptypes/empty";
option java_package = "com.google.protobuf";
option java_outer_classname = "EmptyProto";
option java_multiple_files = true;
option objc_class_prefix = "GPB";
option cc_enable_arenas = true;
// A generic empty message that you can re-use to avoid defining duplicated
// empty messages in your APIs. A typical example is to use it as the request
// or the response type of an API method. For instance:
//
// service Foo {
// rpc Bar(google.protobuf.Empty) returns (google.protobuf.Empty);
// }
//
// The JSON representation for `Empty` is empty JSON object `{}`.
message Empty {}

View file

@ -0,0 +1,440 @@
// Code generated by protoc-gen-go. DO NOT EDIT.
// source: google/protobuf/struct.proto
package structpb // import "github.com/golang/protobuf/ptypes/struct"
import proto "github.com/golang/protobuf/proto"
import fmt "fmt"
import math "math"
// Reference imports to suppress errors if they are not otherwise used.
var _ = proto.Marshal
var _ = fmt.Errorf
var _ = math.Inf
// This is a compile-time assertion to ensure that this generated file
// is compatible with the proto package it is being compiled against.
// A compilation error at this line likely means your copy of the
// proto package needs to be updated.
const _ = proto.ProtoPackageIsVersion2 // please upgrade the proto package
// `NullValue` is a singleton enumeration to represent the null value for the
// `Value` type union.
//
// The JSON representation for `NullValue` is JSON `null`.
type NullValue int32
const (
// Null value.
NullValue_NULL_VALUE NullValue = 0
)
var NullValue_name = map[int32]string{
0: "NULL_VALUE",
}
var NullValue_value = map[string]int32{
"NULL_VALUE": 0,
}
func (x NullValue) String() string {
return proto.EnumName(NullValue_name, int32(x))
}
func (NullValue) EnumDescriptor() ([]byte, []int) {
return fileDescriptor_struct_3a5a94e0c7801b27, []int{0}
}
func (NullValue) XXX_WellKnownType() string { return "NullValue" }
// `Struct` represents a structured data value, consisting of fields
// which map to dynamically typed values. In some languages, `Struct`
// might be supported by a native representation. For example, in
// scripting languages like JS a struct is represented as an
// object. The details of that representation are described together
// with the proto support for the language.
//
// The JSON representation for `Struct` is JSON object.
type Struct struct {
// Unordered map of dynamically typed values.
Fields map[string]*Value `protobuf:"bytes,1,rep,name=fields" json:"fields,omitempty" protobuf_key:"bytes,1,opt,name=key" protobuf_val:"bytes,2,opt,name=value"`
XXX_NoUnkeyedLiteral struct{} `json:"-"`
XXX_unrecognized []byte `json:"-"`
XXX_sizecache int32 `json:"-"`
}
func (m *Struct) Reset() { *m = Struct{} }
func (m *Struct) String() string { return proto.CompactTextString(m) }
func (*Struct) ProtoMessage() {}
func (*Struct) Descriptor() ([]byte, []int) {
return fileDescriptor_struct_3a5a94e0c7801b27, []int{0}
}
func (*Struct) XXX_WellKnownType() string { return "Struct" }
func (m *Struct) XXX_Unmarshal(b []byte) error {
return xxx_messageInfo_Struct.Unmarshal(m, b)
}
func (m *Struct) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
return xxx_messageInfo_Struct.Marshal(b, m, deterministic)
}
func (dst *Struct) XXX_Merge(src proto.Message) {
xxx_messageInfo_Struct.Merge(dst, src)
}
func (m *Struct) XXX_Size() int {
return xxx_messageInfo_Struct.Size(m)
}
func (m *Struct) XXX_DiscardUnknown() {
xxx_messageInfo_Struct.DiscardUnknown(m)
}
var xxx_messageInfo_Struct proto.InternalMessageInfo
func (m *Struct) GetFields() map[string]*Value {
if m != nil {
return m.Fields
}
return nil
}
// `Value` represents a dynamically typed value which can be either
// null, a number, a string, a boolean, a recursive struct value, or a
// list of values. A producer of value is expected to set one of that
// variants, absence of any variant indicates an error.
//
// The JSON representation for `Value` is JSON value.
type Value struct {
// The kind of value.
//
// Types that are valid to be assigned to Kind:
// *Value_NullValue
// *Value_NumberValue
// *Value_StringValue
// *Value_BoolValue
// *Value_StructValue
// *Value_ListValue
Kind isValue_Kind `protobuf_oneof:"kind"`
XXX_NoUnkeyedLiteral struct{} `json:"-"`
XXX_unrecognized []byte `json:"-"`
XXX_sizecache int32 `json:"-"`
}
func (m *Value) Reset() { *m = Value{} }
func (m *Value) String() string { return proto.CompactTextString(m) }
func (*Value) ProtoMessage() {}
func (*Value) Descriptor() ([]byte, []int) {
return fileDescriptor_struct_3a5a94e0c7801b27, []int{1}
}
func (*Value) XXX_WellKnownType() string { return "Value" }
func (m *Value) XXX_Unmarshal(b []byte) error {
return xxx_messageInfo_Value.Unmarshal(m, b)
}
func (m *Value) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
return xxx_messageInfo_Value.Marshal(b, m, deterministic)
}
func (dst *Value) XXX_Merge(src proto.Message) {
xxx_messageInfo_Value.Merge(dst, src)
}
func (m *Value) XXX_Size() int {
return xxx_messageInfo_Value.Size(m)
}
func (m *Value) XXX_DiscardUnknown() {
xxx_messageInfo_Value.DiscardUnknown(m)
}
var xxx_messageInfo_Value proto.InternalMessageInfo
type isValue_Kind interface {
isValue_Kind()
}
type Value_NullValue struct {
NullValue NullValue `protobuf:"varint,1,opt,name=null_value,json=nullValue,enum=google.protobuf.NullValue,oneof"`
}
type Value_NumberValue struct {
NumberValue float64 `protobuf:"fixed64,2,opt,name=number_value,json=numberValue,oneof"`
}
type Value_StringValue struct {
StringValue string `protobuf:"bytes,3,opt,name=string_value,json=stringValue,oneof"`
}
type Value_BoolValue struct {
BoolValue bool `protobuf:"varint,4,opt,name=bool_value,json=boolValue,oneof"`
}
type Value_StructValue struct {
StructValue *Struct `protobuf:"bytes,5,opt,name=struct_value,json=structValue,oneof"`
}
type Value_ListValue struct {
ListValue *ListValue `protobuf:"bytes,6,opt,name=list_value,json=listValue,oneof"`
}
func (*Value_NullValue) isValue_Kind() {}
func (*Value_NumberValue) isValue_Kind() {}
func (*Value_StringValue) isValue_Kind() {}
func (*Value_BoolValue) isValue_Kind() {}
func (*Value_StructValue) isValue_Kind() {}
func (*Value_ListValue) isValue_Kind() {}
func (m *Value) GetKind() isValue_Kind {
if m != nil {
return m.Kind
}
return nil
}
func (m *Value) GetNullValue() NullValue {
if x, ok := m.GetKind().(*Value_NullValue); ok {
return x.NullValue
}
return NullValue_NULL_VALUE
}
func (m *Value) GetNumberValue() float64 {
if x, ok := m.GetKind().(*Value_NumberValue); ok {
return x.NumberValue
}
return 0
}
func (m *Value) GetStringValue() string {
if x, ok := m.GetKind().(*Value_StringValue); ok {
return x.StringValue
}
return ""
}
func (m *Value) GetBoolValue() bool {
if x, ok := m.GetKind().(*Value_BoolValue); ok {
return x.BoolValue
}
return false
}
func (m *Value) GetStructValue() *Struct {
if x, ok := m.GetKind().(*Value_StructValue); ok {
return x.StructValue
}
return nil
}
func (m *Value) GetListValue() *ListValue {
if x, ok := m.GetKind().(*Value_ListValue); ok {
return x.ListValue
}
return nil
}
// XXX_OneofFuncs is for the internal use of the proto package.
func (*Value) XXX_OneofFuncs() (func(msg proto.Message, b *proto.Buffer) error, func(msg proto.Message, tag, wire int, b *proto.Buffer) (bool, error), func(msg proto.Message) (n int), []interface{}) {
return _Value_OneofMarshaler, _Value_OneofUnmarshaler, _Value_OneofSizer, []interface{}{
(*Value_NullValue)(nil),
(*Value_NumberValue)(nil),
(*Value_StringValue)(nil),
(*Value_BoolValue)(nil),
(*Value_StructValue)(nil),
(*Value_ListValue)(nil),
}
}
func _Value_OneofMarshaler(msg proto.Message, b *proto.Buffer) error {
m := msg.(*Value)
// kind
switch x := m.Kind.(type) {
case *Value_NullValue:
b.EncodeVarint(1<<3 | proto.WireVarint)
b.EncodeVarint(uint64(x.NullValue))
case *Value_NumberValue:
b.EncodeVarint(2<<3 | proto.WireFixed64)
b.EncodeFixed64(math.Float64bits(x.NumberValue))
case *Value_StringValue:
b.EncodeVarint(3<<3 | proto.WireBytes)
b.EncodeStringBytes(x.StringValue)
case *Value_BoolValue:
t := uint64(0)
if x.BoolValue {
t = 1
}
b.EncodeVarint(4<<3 | proto.WireVarint)
b.EncodeVarint(t)
case *Value_StructValue:
b.EncodeVarint(5<<3 | proto.WireBytes)
if err := b.EncodeMessage(x.StructValue); err != nil {
return err
}
case *Value_ListValue:
b.EncodeVarint(6<<3 | proto.WireBytes)
if err := b.EncodeMessage(x.ListValue); err != nil {
return err
}
case nil:
default:
return fmt.Errorf("Value.Kind has unexpected type %T", x)
}
return nil
}
func _Value_OneofUnmarshaler(msg proto.Message, tag, wire int, b *proto.Buffer) (bool, error) {
m := msg.(*Value)
switch tag {
case 1: // kind.null_value
if wire != proto.WireVarint {
return true, proto.ErrInternalBadWireType
}
x, err := b.DecodeVarint()
m.Kind = &Value_NullValue{NullValue(x)}
return true, err
case 2: // kind.number_value
if wire != proto.WireFixed64 {
return true, proto.ErrInternalBadWireType
}
x, err := b.DecodeFixed64()
m.Kind = &Value_NumberValue{math.Float64frombits(x)}
return true, err
case 3: // kind.string_value
if wire != proto.WireBytes {
return true, proto.ErrInternalBadWireType
}
x, err := b.DecodeStringBytes()
m.Kind = &Value_StringValue{x}
return true, err
case 4: // kind.bool_value
if wire != proto.WireVarint {
return true, proto.ErrInternalBadWireType
}
x, err := b.DecodeVarint()
m.Kind = &Value_BoolValue{x != 0}
return true, err
case 5: // kind.struct_value
if wire != proto.WireBytes {
return true, proto.ErrInternalBadWireType
}
msg := new(Struct)
err := b.DecodeMessage(msg)
m.Kind = &Value_StructValue{msg}
return true, err
case 6: // kind.list_value
if wire != proto.WireBytes {
return true, proto.ErrInternalBadWireType
}
msg := new(ListValue)
err := b.DecodeMessage(msg)
m.Kind = &Value_ListValue{msg}
return true, err
default:
return false, nil
}
}
func _Value_OneofSizer(msg proto.Message) (n int) {
m := msg.(*Value)
// kind
switch x := m.Kind.(type) {
case *Value_NullValue:
n += 1 // tag and wire
n += proto.SizeVarint(uint64(x.NullValue))
case *Value_NumberValue:
n += 1 // tag and wire
n += 8
case *Value_StringValue:
n += 1 // tag and wire
n += proto.SizeVarint(uint64(len(x.StringValue)))
n += len(x.StringValue)
case *Value_BoolValue:
n += 1 // tag and wire
n += 1
case *Value_StructValue:
s := proto.Size(x.StructValue)
n += 1 // tag and wire
n += proto.SizeVarint(uint64(s))
n += s
case *Value_ListValue:
s := proto.Size(x.ListValue)
n += 1 // tag and wire
n += proto.SizeVarint(uint64(s))
n += s
case nil:
default:
panic(fmt.Sprintf("proto: unexpected type %T in oneof", x))
}
return n
}
// `ListValue` is a wrapper around a repeated field of values.
//
// The JSON representation for `ListValue` is JSON array.
type ListValue struct {
// Repeated field of dynamically typed values.
Values []*Value `protobuf:"bytes,1,rep,name=values" json:"values,omitempty"`
XXX_NoUnkeyedLiteral struct{} `json:"-"`
XXX_unrecognized []byte `json:"-"`
XXX_sizecache int32 `json:"-"`
}
func (m *ListValue) Reset() { *m = ListValue{} }
func (m *ListValue) String() string { return proto.CompactTextString(m) }
func (*ListValue) ProtoMessage() {}
func (*ListValue) Descriptor() ([]byte, []int) {
return fileDescriptor_struct_3a5a94e0c7801b27, []int{2}
}
func (*ListValue) XXX_WellKnownType() string { return "ListValue" }
func (m *ListValue) XXX_Unmarshal(b []byte) error {
return xxx_messageInfo_ListValue.Unmarshal(m, b)
}
func (m *ListValue) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
return xxx_messageInfo_ListValue.Marshal(b, m, deterministic)
}
func (dst *ListValue) XXX_Merge(src proto.Message) {
xxx_messageInfo_ListValue.Merge(dst, src)
}
func (m *ListValue) XXX_Size() int {
return xxx_messageInfo_ListValue.Size(m)
}
func (m *ListValue) XXX_DiscardUnknown() {
xxx_messageInfo_ListValue.DiscardUnknown(m)
}
var xxx_messageInfo_ListValue proto.InternalMessageInfo
func (m *ListValue) GetValues() []*Value {
if m != nil {
return m.Values
}
return nil
}
func init() {
proto.RegisterType((*Struct)(nil), "google.protobuf.Struct")
proto.RegisterMapType((map[string]*Value)(nil), "google.protobuf.Struct.FieldsEntry")
proto.RegisterType((*Value)(nil), "google.protobuf.Value")
proto.RegisterType((*ListValue)(nil), "google.protobuf.ListValue")
proto.RegisterEnum("google.protobuf.NullValue", NullValue_name, NullValue_value)
}
func init() {
proto.RegisterFile("google/protobuf/struct.proto", fileDescriptor_struct_3a5a94e0c7801b27)
}
var fileDescriptor_struct_3a5a94e0c7801b27 = []byte{
// 417 bytes of a gzipped FileDescriptorProto
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x74, 0x92, 0x41, 0x8b, 0xd3, 0x40,
0x14, 0xc7, 0x3b, 0xc9, 0x36, 0x98, 0x17, 0x59, 0x97, 0x11, 0xb4, 0xac, 0xa2, 0xa1, 0x7b, 0x09,
0x22, 0x29, 0xd6, 0x8b, 0x18, 0x2f, 0x06, 0xd6, 0x5d, 0x30, 0x2c, 0x31, 0xba, 0x15, 0xbc, 0x94,
0x26, 0x4d, 0x63, 0xe8, 0x74, 0x26, 0x24, 0x33, 0x4a, 0x8f, 0x7e, 0x0b, 0xcf, 0x1e, 0x3d, 0xfa,
0xe9, 0x3c, 0xca, 0xcc, 0x24, 0xa9, 0xb4, 0xf4, 0x94, 0xbc, 0xf7, 0x7e, 0xef, 0x3f, 0xef, 0xff,
0x66, 0xe0, 0x71, 0xc1, 0x58, 0x41, 0xf2, 0x49, 0x55, 0x33, 0xce, 0x52, 0xb1, 0x9a, 0x34, 0xbc,
0x16, 0x19, 0xf7, 0x55, 0x8c, 0xef, 0xe9, 0xaa, 0xdf, 0x55, 0xc7, 0x3f, 0x11, 0x58, 0x1f, 0x15,
0x81, 0x03, 0xb0, 0x56, 0x65, 0x4e, 0x96, 0xcd, 0x08, 0xb9, 0xa6, 0xe7, 0x4c, 0x2f, 0xfc, 0x3d,
0xd8, 0xd7, 0xa0, 0xff, 0x4e, 0x51, 0x97, 0x94, 0xd7, 0xdb, 0xa4, 0x6d, 0x39, 0xff, 0x00, 0xce,
0x7f, 0x69, 0x7c, 0x06, 0xe6, 0x3a, 0xdf, 0x8e, 0x90, 0x8b, 0x3c, 0x3b, 0x91, 0xbf, 0xf8, 0x39,
0x0c, 0xbf, 0x2d, 0x88, 0xc8, 0x47, 0x86, 0x8b, 0x3c, 0x67, 0xfa, 0xe0, 0x40, 0x7c, 0x26, 0xab,
0x89, 0x86, 0x5e, 0x1b, 0xaf, 0xd0, 0xf8, 0x8f, 0x01, 0x43, 0x95, 0xc4, 0x01, 0x00, 0x15, 0x84,
0xcc, 0xb5, 0x80, 0x14, 0x3d, 0x9d, 0x9e, 0x1f, 0x08, 0xdc, 0x08, 0x42, 0x14, 0x7f, 0x3d, 0x48,
0x6c, 0xda, 0x05, 0xf8, 0x02, 0xee, 0x52, 0xb1, 0x49, 0xf3, 0x7a, 0xbe, 0x3b, 0x1f, 0x5d, 0x0f,
0x12, 0x47, 0x67, 0x7b, 0xa8, 0xe1, 0x75, 0x49, 0x8b, 0x16, 0x32, 0xe5, 0xe0, 0x12, 0xd2, 0x59,
0x0d, 0x3d, 0x05, 0x48, 0x19, 0xeb, 0xc6, 0x38, 0x71, 0x91, 0x77, 0x47, 0x1e, 0x25, 0x73, 0x1a,
0x78, 0xa3, 0x54, 0x44, 0xc6, 0x5b, 0x64, 0xa8, 0xac, 0x3e, 0x3c, 0xb2, 0xc7, 0x56, 0x5e, 0x64,
0xbc, 0x77, 0x49, 0xca, 0xa6, 0xeb, 0xb5, 0x54, 0xef, 0xa1, 0xcb, 0xa8, 0x6c, 0x78, 0xef, 0x92,
0x74, 0x41, 0x68, 0xc1, 0xc9, 0xba, 0xa4, 0xcb, 0x71, 0x00, 0x76, 0x4f, 0x60, 0x1f, 0x2c, 0x25,
0xd6, 0xdd, 0xe8, 0xb1, 0xa5, 0xb7, 0xd4, 0xb3, 0x47, 0x60, 0xf7, 0x4b, 0xc4, 0xa7, 0x00, 0x37,
0xb7, 0x51, 0x34, 0x9f, 0xbd, 0x8d, 0x6e, 0x2f, 0xcf, 0x06, 0xe1, 0x0f, 0x04, 0xf7, 0x33, 0xb6,
0xd9, 0x97, 0x08, 0x1d, 0xed, 0x26, 0x96, 0x71, 0x8c, 0xbe, 0xbc, 0x28, 0x4a, 0xfe, 0x55, 0xa4,
0x7e, 0xc6, 0x36, 0x93, 0x82, 0x91, 0x05, 0x2d, 0x76, 0x4f, 0xb1, 0xe2, 0xdb, 0x2a, 0x6f, 0xda,
0x17, 0x19, 0xe8, 0x4f, 0x95, 0xfe, 0x45, 0xe8, 0x97, 0x61, 0x5e, 0xc5, 0xe1, 0x6f, 0xe3, 0xc9,
0x95, 0x16, 0x8f, 0xbb, 0xf9, 0x3e, 0xe7, 0x84, 0xbc, 0xa7, 0xec, 0x3b, 0xfd, 0x24, 0x3b, 0x53,
0x4b, 0x49, 0xbd, 0xfc, 0x17, 0x00, 0x00, 0xff, 0xff, 0xe8, 0x1b, 0x59, 0xf8, 0xe5, 0x02, 0x00,
0x00,
}

View file

@ -0,0 +1,96 @@
// Protocol Buffers - Google's data interchange format
// Copyright 2008 Google Inc. All rights reserved.
// https://developers.google.com/protocol-buffers/
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
// * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
syntax = "proto3";
package google.protobuf;
option csharp_namespace = "Google.Protobuf.WellKnownTypes";
option cc_enable_arenas = true;
option go_package = "github.com/golang/protobuf/ptypes/struct;structpb";
option java_package = "com.google.protobuf";
option java_outer_classname = "StructProto";
option java_multiple_files = true;
option objc_class_prefix = "GPB";
// `Struct` represents a structured data value, consisting of fields
// which map to dynamically typed values. In some languages, `Struct`
// might be supported by a native representation. For example, in
// scripting languages like JS a struct is represented as an
// object. The details of that representation are described together
// with the proto support for the language.
//
// The JSON representation for `Struct` is JSON object.
message Struct {
// Unordered map of dynamically typed values.
map<string, Value> fields = 1;
}
// `Value` represents a dynamically typed value which can be either
// null, a number, a string, a boolean, a recursive struct value, or a
// list of values. A producer of value is expected to set one of that
// variants, absence of any variant indicates an error.
//
// The JSON representation for `Value` is JSON value.
message Value {
// The kind of value.
oneof kind {
// Represents a null value.
NullValue null_value = 1;
// Represents a double value.
double number_value = 2;
// Represents a string value.
string string_value = 3;
// Represents a boolean value.
bool bool_value = 4;
// Represents a structured value.
Struct struct_value = 5;
// Represents a repeated `Value`.
ListValue list_value = 6;
}
}
// `NullValue` is a singleton enumeration to represent the null value for the
// `Value` type union.
//
// The JSON representation for `NullValue` is JSON `null`.
enum NullValue {
// Null value.
NULL_VALUE = 0;
}
// `ListValue` is a wrapper around a repeated field of values.
//
// The JSON representation for `ListValue` is JSON array.
message ListValue {
// Repeated field of dynamically typed values.
repeated Value values = 1;
}

134
vendor/github.com/golang/protobuf/ptypes/timestamp.go generated vendored Normal file
View file

@ -0,0 +1,134 @@
// Go support for Protocol Buffers - Google's data interchange format
//
// Copyright 2016 The Go Authors. All rights reserved.
// https://github.com/golang/protobuf
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
// * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
package ptypes
// This file implements operations on google.protobuf.Timestamp.
import (
"errors"
"fmt"
"time"
tspb "github.com/golang/protobuf/ptypes/timestamp"
)
const (
// Seconds field of the earliest valid Timestamp.
// This is time.Date(1, 1, 1, 0, 0, 0, 0, time.UTC).Unix().
minValidSeconds = -62135596800
// Seconds field just after the latest valid Timestamp.
// This is time.Date(10000, 1, 1, 0, 0, 0, 0, time.UTC).Unix().
maxValidSeconds = 253402300800
)
// validateTimestamp determines whether a Timestamp is valid.
// A valid timestamp represents a time in the range
// [0001-01-01, 10000-01-01) and has a Nanos field
// in the range [0, 1e9).
//
// If the Timestamp is valid, validateTimestamp returns nil.
// Otherwise, it returns an error that describes
// the problem.
//
// Every valid Timestamp can be represented by a time.Time, but the converse is not true.
func validateTimestamp(ts *tspb.Timestamp) error {
if ts == nil {
return errors.New("timestamp: nil Timestamp")
}
if ts.Seconds < minValidSeconds {
return fmt.Errorf("timestamp: %v before 0001-01-01", ts)
}
if ts.Seconds >= maxValidSeconds {
return fmt.Errorf("timestamp: %v after 10000-01-01", ts)
}
if ts.Nanos < 0 || ts.Nanos >= 1e9 {
return fmt.Errorf("timestamp: %v: nanos not in range [0, 1e9)", ts)
}
return nil
}
// Timestamp converts a google.protobuf.Timestamp proto to a time.Time.
// It returns an error if the argument is invalid.
//
// Unlike most Go functions, if Timestamp returns an error, the first return value
// is not the zero time.Time. Instead, it is the value obtained from the
// time.Unix function when passed the contents of the Timestamp, in the UTC
// locale. This may or may not be a meaningful time; many invalid Timestamps
// do map to valid time.Times.
//
// A nil Timestamp returns an error. The first return value in that case is
// undefined.
func Timestamp(ts *tspb.Timestamp) (time.Time, error) {
// Don't return the zero value on error, because corresponds to a valid
// timestamp. Instead return whatever time.Unix gives us.
var t time.Time
if ts == nil {
t = time.Unix(0, 0).UTC() // treat nil like the empty Timestamp
} else {
t = time.Unix(ts.Seconds, int64(ts.Nanos)).UTC()
}
return t, validateTimestamp(ts)
}
// TimestampNow returns a google.protobuf.Timestamp for the current time.
func TimestampNow() *tspb.Timestamp {
ts, err := TimestampProto(time.Now())
if err != nil {
panic("ptypes: time.Now() out of Timestamp range")
}
return ts
}
// TimestampProto converts the time.Time to a google.protobuf.Timestamp proto.
// It returns an error if the resulting Timestamp is invalid.
func TimestampProto(t time.Time) (*tspb.Timestamp, error) {
seconds := t.Unix()
nanos := int32(t.Sub(time.Unix(seconds, 0)))
ts := &tspb.Timestamp{
Seconds: seconds,
Nanos: nanos,
}
if err := validateTimestamp(ts); err != nil {
return nil, err
}
return ts, nil
}
// TimestampString returns the RFC 3339 string for valid Timestamps. For invalid
// Timestamps, it returns an error message in parentheses.
func TimestampString(ts *tspb.Timestamp) string {
t, err := Timestamp(ts)
if err != nil {
return fmt.Sprintf("(%v)", err)
}
return t.Format(time.RFC3339Nano)
}

View file

@ -0,0 +1,175 @@
// Code generated by protoc-gen-go. DO NOT EDIT.
// source: google/protobuf/timestamp.proto
package timestamp // import "github.com/golang/protobuf/ptypes/timestamp"
import proto "github.com/golang/protobuf/proto"
import fmt "fmt"
import math "math"
// Reference imports to suppress errors if they are not otherwise used.
var _ = proto.Marshal
var _ = fmt.Errorf
var _ = math.Inf
// This is a compile-time assertion to ensure that this generated file
// is compatible with the proto package it is being compiled against.
// A compilation error at this line likely means your copy of the
// proto package needs to be updated.
const _ = proto.ProtoPackageIsVersion2 // please upgrade the proto package
// A Timestamp represents a point in time independent of any time zone
// or calendar, represented as seconds and fractions of seconds at
// nanosecond resolution in UTC Epoch time. It is encoded using the
// Proleptic Gregorian Calendar which extends the Gregorian calendar
// backwards to year one. It is encoded assuming all minutes are 60
// seconds long, i.e. leap seconds are "smeared" so that no leap second
// table is needed for interpretation. Range is from
// 0001-01-01T00:00:00Z to 9999-12-31T23:59:59.999999999Z.
// By restricting to that range, we ensure that we can convert to
// and from RFC 3339 date strings.
// See [https://www.ietf.org/rfc/rfc3339.txt](https://www.ietf.org/rfc/rfc3339.txt).
//
// # Examples
//
// Example 1: Compute Timestamp from POSIX `time()`.
//
// Timestamp timestamp;
// timestamp.set_seconds(time(NULL));
// timestamp.set_nanos(0);
//
// Example 2: Compute Timestamp from POSIX `gettimeofday()`.
//
// struct timeval tv;
// gettimeofday(&tv, NULL);
//
// Timestamp timestamp;
// timestamp.set_seconds(tv.tv_sec);
// timestamp.set_nanos(tv.tv_usec * 1000);
//
// Example 3: Compute Timestamp from Win32 `GetSystemTimeAsFileTime()`.
//
// FILETIME ft;
// GetSystemTimeAsFileTime(&ft);
// UINT64 ticks = (((UINT64)ft.dwHighDateTime) << 32) | ft.dwLowDateTime;
//
// // A Windows tick is 100 nanoseconds. Windows epoch 1601-01-01T00:00:00Z
// // is 11644473600 seconds before Unix epoch 1970-01-01T00:00:00Z.
// Timestamp timestamp;
// timestamp.set_seconds((INT64) ((ticks / 10000000) - 11644473600LL));
// timestamp.set_nanos((INT32) ((ticks % 10000000) * 100));
//
// Example 4: Compute Timestamp from Java `System.currentTimeMillis()`.
//
// long millis = System.currentTimeMillis();
//
// Timestamp timestamp = Timestamp.newBuilder().setSeconds(millis / 1000)
// .setNanos((int) ((millis % 1000) * 1000000)).build();
//
//
// Example 5: Compute Timestamp from current time in Python.
//
// timestamp = Timestamp()
// timestamp.GetCurrentTime()
//
// # JSON Mapping
//
// In JSON format, the Timestamp type is encoded as a string in the
// [RFC 3339](https://www.ietf.org/rfc/rfc3339.txt) format. That is, the
// format is "{year}-{month}-{day}T{hour}:{min}:{sec}[.{frac_sec}]Z"
// where {year} is always expressed using four digits while {month}, {day},
// {hour}, {min}, and {sec} are zero-padded to two digits each. The fractional
// seconds, which can go up to 9 digits (i.e. up to 1 nanosecond resolution),
// are optional. The "Z" suffix indicates the timezone ("UTC"); the timezone
// is required, though only UTC (as indicated by "Z") is presently supported.
//
// For example, "2017-01-15T01:30:15.01Z" encodes 15.01 seconds past
// 01:30 UTC on January 15, 2017.
//
// In JavaScript, one can convert a Date object to this format using the
// standard [toISOString()](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date/toISOString]
// method. In Python, a standard `datetime.datetime` object can be converted
// to this format using [`strftime`](https://docs.python.org/2/library/time.html#time.strftime)
// with the time format spec '%Y-%m-%dT%H:%M:%S.%fZ'. Likewise, in Java, one
// can use the Joda Time's [`ISODateTimeFormat.dateTime()`](
// http://www.joda.org/joda-time/apidocs/org/joda/time/format/ISODateTimeFormat.html#dateTime--)
// to obtain a formatter capable of generating timestamps in this format.
//
//
type Timestamp struct {
// Represents seconds of UTC time since Unix epoch
// 1970-01-01T00:00:00Z. Must be from 0001-01-01T00:00:00Z to
// 9999-12-31T23:59:59Z inclusive.
Seconds int64 `protobuf:"varint,1,opt,name=seconds" json:"seconds,omitempty"`
// Non-negative fractions of a second at nanosecond resolution. Negative
// second values with fractions must still have non-negative nanos values
// that count forward in time. Must be from 0 to 999,999,999
// inclusive.
Nanos int32 `protobuf:"varint,2,opt,name=nanos" json:"nanos,omitempty"`
XXX_NoUnkeyedLiteral struct{} `json:"-"`
XXX_unrecognized []byte `json:"-"`
XXX_sizecache int32 `json:"-"`
}
func (m *Timestamp) Reset() { *m = Timestamp{} }
func (m *Timestamp) String() string { return proto.CompactTextString(m) }
func (*Timestamp) ProtoMessage() {}
func (*Timestamp) Descriptor() ([]byte, []int) {
return fileDescriptor_timestamp_b826e8e5fba671a8, []int{0}
}
func (*Timestamp) XXX_WellKnownType() string { return "Timestamp" }
func (m *Timestamp) XXX_Unmarshal(b []byte) error {
return xxx_messageInfo_Timestamp.Unmarshal(m, b)
}
func (m *Timestamp) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
return xxx_messageInfo_Timestamp.Marshal(b, m, deterministic)
}
func (dst *Timestamp) XXX_Merge(src proto.Message) {
xxx_messageInfo_Timestamp.Merge(dst, src)
}
func (m *Timestamp) XXX_Size() int {
return xxx_messageInfo_Timestamp.Size(m)
}
func (m *Timestamp) XXX_DiscardUnknown() {
xxx_messageInfo_Timestamp.DiscardUnknown(m)
}
var xxx_messageInfo_Timestamp proto.InternalMessageInfo
func (m *Timestamp) GetSeconds() int64 {
if m != nil {
return m.Seconds
}
return 0
}
func (m *Timestamp) GetNanos() int32 {
if m != nil {
return m.Nanos
}
return 0
}
func init() {
proto.RegisterType((*Timestamp)(nil), "google.protobuf.Timestamp")
}
func init() {
proto.RegisterFile("google/protobuf/timestamp.proto", fileDescriptor_timestamp_b826e8e5fba671a8)
}
var fileDescriptor_timestamp_b826e8e5fba671a8 = []byte{
// 191 bytes of a gzipped FileDescriptorProto
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xe2, 0x92, 0x4f, 0xcf, 0xcf, 0x4f,
0xcf, 0x49, 0xd5, 0x2f, 0x28, 0xca, 0x2f, 0xc9, 0x4f, 0x2a, 0x4d, 0xd3, 0x2f, 0xc9, 0xcc, 0x4d,
0x2d, 0x2e, 0x49, 0xcc, 0x2d, 0xd0, 0x03, 0x0b, 0x09, 0xf1, 0x43, 0x14, 0xe8, 0xc1, 0x14, 0x28,
0x59, 0x73, 0x71, 0x86, 0xc0, 0xd4, 0x08, 0x49, 0x70, 0xb1, 0x17, 0xa7, 0x26, 0xe7, 0xe7, 0xa5,
0x14, 0x4b, 0x30, 0x2a, 0x30, 0x6a, 0x30, 0x07, 0xc1, 0xb8, 0x42, 0x22, 0x5c, 0xac, 0x79, 0x89,
0x79, 0xf9, 0xc5, 0x12, 0x4c, 0x0a, 0x8c, 0x1a, 0xac, 0x41, 0x10, 0x8e, 0x53, 0x1d, 0x97, 0x70,
0x72, 0x7e, 0xae, 0x1e, 0x9a, 0x99, 0x4e, 0x7c, 0x70, 0x13, 0x03, 0x40, 0x42, 0x01, 0x8c, 0x51,
0xda, 0xe9, 0x99, 0x25, 0x19, 0xa5, 0x49, 0x7a, 0xc9, 0xf9, 0xb9, 0xfa, 0xe9, 0xf9, 0x39, 0x89,
0x79, 0xe9, 0x08, 0x27, 0x16, 0x94, 0x54, 0x16, 0xa4, 0x16, 0x23, 0x5c, 0xfa, 0x83, 0x91, 0x71,
0x11, 0x13, 0xb3, 0x7b, 0x80, 0xd3, 0x2a, 0x26, 0x39, 0x77, 0x88, 0xc9, 0x01, 0x50, 0xb5, 0x7a,
0xe1, 0xa9, 0x39, 0x39, 0xde, 0x79, 0xf9, 0xe5, 0x79, 0x21, 0x20, 0x3d, 0x49, 0x6c, 0x60, 0x43,
0x8c, 0x01, 0x01, 0x00, 0x00, 0xff, 0xff, 0xbc, 0x77, 0x4a, 0x07, 0xf7, 0x00, 0x00, 0x00,
}

View file

@ -0,0 +1,133 @@
// Protocol Buffers - Google's data interchange format
// Copyright 2008 Google Inc. All rights reserved.
// https://developers.google.com/protocol-buffers/
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
// * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
syntax = "proto3";
package google.protobuf;
option csharp_namespace = "Google.Protobuf.WellKnownTypes";
option cc_enable_arenas = true;
option go_package = "github.com/golang/protobuf/ptypes/timestamp";
option java_package = "com.google.protobuf";
option java_outer_classname = "TimestampProto";
option java_multiple_files = true;
option objc_class_prefix = "GPB";
// A Timestamp represents a point in time independent of any time zone
// or calendar, represented as seconds and fractions of seconds at
// nanosecond resolution in UTC Epoch time. It is encoded using the
// Proleptic Gregorian Calendar which extends the Gregorian calendar
// backwards to year one. It is encoded assuming all minutes are 60
// seconds long, i.e. leap seconds are "smeared" so that no leap second
// table is needed for interpretation. Range is from
// 0001-01-01T00:00:00Z to 9999-12-31T23:59:59.999999999Z.
// By restricting to that range, we ensure that we can convert to
// and from RFC 3339 date strings.
// See [https://www.ietf.org/rfc/rfc3339.txt](https://www.ietf.org/rfc/rfc3339.txt).
//
// # Examples
//
// Example 1: Compute Timestamp from POSIX `time()`.
//
// Timestamp timestamp;
// timestamp.set_seconds(time(NULL));
// timestamp.set_nanos(0);
//
// Example 2: Compute Timestamp from POSIX `gettimeofday()`.
//
// struct timeval tv;
// gettimeofday(&tv, NULL);
//
// Timestamp timestamp;
// timestamp.set_seconds(tv.tv_sec);
// timestamp.set_nanos(tv.tv_usec * 1000);
//
// Example 3: Compute Timestamp from Win32 `GetSystemTimeAsFileTime()`.
//
// FILETIME ft;
// GetSystemTimeAsFileTime(&ft);
// UINT64 ticks = (((UINT64)ft.dwHighDateTime) << 32) | ft.dwLowDateTime;
//
// // A Windows tick is 100 nanoseconds. Windows epoch 1601-01-01T00:00:00Z
// // is 11644473600 seconds before Unix epoch 1970-01-01T00:00:00Z.
// Timestamp timestamp;
// timestamp.set_seconds((INT64) ((ticks / 10000000) - 11644473600LL));
// timestamp.set_nanos((INT32) ((ticks % 10000000) * 100));
//
// Example 4: Compute Timestamp from Java `System.currentTimeMillis()`.
//
// long millis = System.currentTimeMillis();
//
// Timestamp timestamp = Timestamp.newBuilder().setSeconds(millis / 1000)
// .setNanos((int) ((millis % 1000) * 1000000)).build();
//
//
// Example 5: Compute Timestamp from current time in Python.
//
// timestamp = Timestamp()
// timestamp.GetCurrentTime()
//
// # JSON Mapping
//
// In JSON format, the Timestamp type is encoded as a string in the
// [RFC 3339](https://www.ietf.org/rfc/rfc3339.txt) format. That is, the
// format is "{year}-{month}-{day}T{hour}:{min}:{sec}[.{frac_sec}]Z"
// where {year} is always expressed using four digits while {month}, {day},
// {hour}, {min}, and {sec} are zero-padded to two digits each. The fractional
// seconds, which can go up to 9 digits (i.e. up to 1 nanosecond resolution),
// are optional. The "Z" suffix indicates the timezone ("UTC"); the timezone
// is required, though only UTC (as indicated by "Z") is presently supported.
//
// For example, "2017-01-15T01:30:15.01Z" encodes 15.01 seconds past
// 01:30 UTC on January 15, 2017.
//
// In JavaScript, one can convert a Date object to this format using the
// standard [toISOString()](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date/toISOString]
// method. In Python, a standard `datetime.datetime` object can be converted
// to this format using [`strftime`](https://docs.python.org/2/library/time.html#time.strftime)
// with the time format spec '%Y-%m-%dT%H:%M:%S.%fZ'. Likewise, in Java, one
// can use the Joda Time's [`ISODateTimeFormat.dateTime()`](
// http://www.joda.org/joda-time/apidocs/org/joda/time/format/ISODateTimeFormat.html#dateTime--)
// to obtain a formatter capable of generating timestamps in this format.
//
//
message Timestamp {
// Represents seconds of UTC time since Unix epoch
// 1970-01-01T00:00:00Z. Must be from 0001-01-01T00:00:00Z to
// 9999-12-31T23:59:59Z inclusive.
int64 seconds = 1;
// Non-negative fractions of a second at nanosecond resolution. Negative
// second values with fractions must still have non-negative nanos values
// that count forward in time. Must be from 0 to 999,999,999
// inclusive.
int32 nanos = 2;
}

View file

@ -0,0 +1,153 @@
// Go support for Protocol Buffers - Google's data interchange format
//
// Copyright 2016 The Go Authors. All rights reserved.
// https://github.com/golang/protobuf
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
// * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
package ptypes
import (
"math"
"testing"
"time"
"github.com/golang/protobuf/proto"
tspb "github.com/golang/protobuf/ptypes/timestamp"
)
var tests = []struct {
ts *tspb.Timestamp
valid bool
t time.Time
}{
// The timestamp representing the Unix epoch date.
{&tspb.Timestamp{Seconds: 0, Nanos: 0}, true, utcDate(1970, 1, 1)},
// The smallest representable timestamp.
{&tspb.Timestamp{Seconds: math.MinInt64, Nanos: math.MinInt32}, false,
time.Unix(math.MinInt64, math.MinInt32).UTC()},
// The smallest representable timestamp with non-negative nanos.
{&tspb.Timestamp{Seconds: math.MinInt64, Nanos: 0}, false, time.Unix(math.MinInt64, 0).UTC()},
// The earliest valid timestamp.
{&tspb.Timestamp{Seconds: minValidSeconds, Nanos: 0}, true, utcDate(1, 1, 1)},
//"0001-01-01T00:00:00Z"},
// The largest representable timestamp.
{&tspb.Timestamp{Seconds: math.MaxInt64, Nanos: math.MaxInt32}, false,
time.Unix(math.MaxInt64, math.MaxInt32).UTC()},
// The largest representable timestamp with nanos in range.
{&tspb.Timestamp{Seconds: math.MaxInt64, Nanos: 1e9 - 1}, false,
time.Unix(math.MaxInt64, 1e9-1).UTC()},
// The largest valid timestamp.
{&tspb.Timestamp{Seconds: maxValidSeconds - 1, Nanos: 1e9 - 1}, true,
time.Date(9999, 12, 31, 23, 59, 59, 1e9-1, time.UTC)},
// The smallest invalid timestamp that is larger than the valid range.
{&tspb.Timestamp{Seconds: maxValidSeconds, Nanos: 0}, false, time.Unix(maxValidSeconds, 0).UTC()},
// A date before the epoch.
{&tspb.Timestamp{Seconds: -281836800, Nanos: 0}, true, utcDate(1961, 1, 26)},
// A date after the epoch.
{&tspb.Timestamp{Seconds: 1296000000, Nanos: 0}, true, utcDate(2011, 1, 26)},
// A date after the epoch, in the middle of the day.
{&tspb.Timestamp{Seconds: 1296012345, Nanos: 940483}, true,
time.Date(2011, 1, 26, 3, 25, 45, 940483, time.UTC)},
}
func TestValidateTimestamp(t *testing.T) {
for _, s := range tests {
got := validateTimestamp(s.ts)
if (got == nil) != s.valid {
t.Errorf("validateTimestamp(%v) = %v, want %v", s.ts, got, s.valid)
}
}
}
func TestTimestamp(t *testing.T) {
for _, s := range tests {
got, err := Timestamp(s.ts)
if (err == nil) != s.valid {
t.Errorf("Timestamp(%v) error = %v, but valid = %t", s.ts, err, s.valid)
} else if s.valid && got != s.t {
t.Errorf("Timestamp(%v) = %v, want %v", s.ts, got, s.t)
}
}
// Special case: a nil Timestamp is an error, but returns the 0 Unix time.
got, err := Timestamp(nil)
want := time.Unix(0, 0).UTC()
if got != want {
t.Errorf("Timestamp(nil) = %v, want %v", got, want)
}
if err == nil {
t.Errorf("Timestamp(nil) error = nil, expected error")
}
}
func TestTimestampProto(t *testing.T) {
for _, s := range tests {
got, err := TimestampProto(s.t)
if (err == nil) != s.valid {
t.Errorf("TimestampProto(%v) error = %v, but valid = %t", s.t, err, s.valid)
} else if s.valid && !proto.Equal(got, s.ts) {
t.Errorf("TimestampProto(%v) = %v, want %v", s.t, got, s.ts)
}
}
// No corresponding special case here: no time.Time results in a nil Timestamp.
}
func TestTimestampString(t *testing.T) {
for _, test := range []struct {
ts *tspb.Timestamp
want string
}{
// Not much testing needed because presumably time.Format is
// well-tested.
{&tspb.Timestamp{Seconds: 0, Nanos: 0}, "1970-01-01T00:00:00Z"},
{&tspb.Timestamp{Seconds: minValidSeconds - 1, Nanos: 0}, "(timestamp: seconds:-62135596801 before 0001-01-01)"},
} {
got := TimestampString(test.ts)
if got != test.want {
t.Errorf("TimestampString(%v) = %q, want %q", test.ts, got, test.want)
}
}
}
func utcDate(year, month, day int) time.Time {
return time.Date(year, time.Month(month), day, 0, 0, 0, 0, time.UTC)
}
func TestTimestampNow(t *testing.T) {
// Bracket the expected time.
before := time.Now()
ts := TimestampNow()
after := time.Now()
tm, err := Timestamp(ts)
if err != nil {
t.Errorf("between %v and %v\nTimestampNow() = %v\nwhich is invalid (%v)", before, after, ts, err)
}
if tm.Before(before) || tm.After(after) {
t.Errorf("between %v and %v\nTimestamp(TimestampNow()) = %v", before, after, tm)
}
}

View file

@ -0,0 +1,9 @@
_output/
.idea
# Bazel.
bazel-bin
bazel-genfiles
bazel-grpc-gateway
bazel-out
bazel-testlogs

View file

@ -0,0 +1,81 @@
language: go
sudo: false
go:
- 1.9.x
- 1.10.x
- master
go_import_path: github.com/grpc-ecosystem/grpc-gateway
cache:
directories:
- $HOME/local
- ${TRAVIS_BUILD_DIR}/examples/browser/node_modules
- $HOME/.cache/_grpc_gateway_bazel
before_install:
- if [ "${USE_BAZEL}" = true ]; then ./.travis/install-bazel.sh $BAZEL_VERSION; fi
- test "${USE_BAZEL}" = true || ./.travis/install-protoc.sh $PROTOC_VERSION
- test "${USE_BAZEL}" = true || ./.travis/install-swagger-codegen.sh $SWAGGER_CODEGEN_VERSION
- test "${USE_BAZEL}" = true || (nvm install $NODE_VERSION && nvm use $NODE_VERSION && node --version)
- test "${USE_BAZEL}" = true || go get github.com/golang/lint/golint
- test "${USE_BAZEL}" = true || go get github.com/dghubble/sling
- test "${USE_BAZEL}" = true || go get github.com/go-resty/resty
install:
# Make sure externally referenced packages are go-gettable.
- test "${USE_BAZEL}" = true ||
go get github.com/grpc-ecosystem/grpc-gateway/protoc-gen-grpc-gateway
- test "${USE_BAZEL}" = true ||
go get github.com/grpc-ecosystem/grpc-gateway/protoc-gen-swagger
- test "${USE_BAZEL}" = true ||
go get github.com/grpc-ecosystem/grpc-gateway/runtime
- test "${USE_BAZEL}" = true ||
go get github.com/grpc-ecosystem/grpc-gateway/examples/cmd/example-grpc-server
- test "${USE_BAZEL}" = true ||
go get github.com/grpc-ecosystem/grpc-gateway/examples/cmd/example-gateway-server
# Just build if USE_BAZEL
- if [ "${USE_BAZEL}" = true ]; then ./.travis/bazel-build.sh; fi
before_script:
- test "${USE_BAZEL}" = true ||
(cd examples/browser && npm install)
script:
# Make sure examples of generated files are up-to-date
- test "${USE_BAZEL}" = true ||
(make realclean && make examples SWAGGER_CODEGEN="java -jar $HOME/local/swagger-codegen-cli.jar")
- if [ -z "${USE_BAZEL}" ] &&
(go version | grep -q "${GO_VERSION_TO_DIFF_TEST}") &&
[ -z "${GATEWAY_PLUGIN_FLAGS}" ]; then
test -z "$(git status --porcelain)" || (git status; git diff; exit 1);
fi
# Unit tests, integration tests and code health checks
- test "${USE_BAZEL}" = true ||
env GLOG_logtostderr=1 go test -race -v github.com/grpc-ecosystem/grpc-gateway/...
- test "${USE_BAZEL}" = true ||
make lint
- test "${USE_BAZEL}" = true ||
sh -c 'cd examples/browser && node ./node_modules/gulp/bin/gulp'
- if [ "${USE_BAZEL}" = true ]; then ./.travis/bazel-test.sh; fi
# test coverage
- if (go version | grep -q "${GO_VERSION_TO_DIFF_TEST}") &&
[ -z "${GATEWAY_PLUGIN_FLAGS}" ]; then
env GLOG_logtostderr=1 ./bin/coverage;
fi
after_success:
- bash <(curl -s https://codecov.io/bash)
env:
global:
- "PATH=$PATH:$HOME/local/bin"
- GO_VERSION_TO_DIFF_TEST="go version go1\.10\.[0-9]\+ linux/amd64"
- BAZEL_VERSION=0.12.0
- NODE_VERSION=v6.1
- PROTOC_VERSION=3.1.0
- SWAGGER_CODEGEN_VERSION=2.2.2
matrix:
- GATEWAY_PLUGIN_FLAGS=
- GATEWAY_PLUGIN_FLAGS=request_context=false
matrix:
include:
- go: master
env: USE_BAZEL=true

23
vendor/github.com/grpc-ecosystem/grpc-gateway/BUILD generated vendored Normal file
View file

@ -0,0 +1,23 @@
load("@bazel_gazelle//:def.bzl", "gazelle")
# gazelle:exclude third_party
gazelle(
name = "gazelle_diff",
mode = "diff",
prefix = "github.com/grpc-ecosystem/grpc-gateway",
)
gazelle(
name = "gazelle_fix",
mode = "fix",
prefix = "github.com/grpc-ecosystem/grpc-gateway",
)
package_group(
name = "generators",
packages = [
"//protoc-gen-grpc-gateway/...",
"//protoc-gen-swagger/...",
],
)

View file

@ -0,0 +1,590 @@
# Change Log
## [v1.4.1](https://grpc-ecosystem.github.io/grpc-gateway/grpc-ecosystem/grpc-gateway/tree/v1.4.1) (2018-05-23)
[Full Changelog](https://grpc-ecosystem.github.io/grpc-gateway/grpc-ecosystem/grpc-gateway/compare/v1.4.0...v1.4.1)
**Closed issues:**
- Next release ? [\#605](https://github.com/grpc-ecosystem/grpc-gateway/issues/605)
**Merged pull requests:**
- Translate gRPC FailedPrecondition as HTTP PreconditionFailed [\#657](https://github.com/grpc-ecosystem/grpc-gateway/pull/657) ([slomek](https://github.com/slomek))
## [v1.4.0](https://grpc-ecosystem.github.io/grpc-gateway/grpc-ecosystem/grpc-gateway/tree/v1.4.0) (2018-05-20)
[Full Changelog](https://grpc-ecosystem.github.io/grpc-gateway/grpc-ecosystem/grpc-gateway/compare/v1.3.1...v1.4.0)
**Implemented enhancements:**
- customize the error return [\#405](https://github.com/grpc-ecosystem/grpc-gateway/issues/405)
- Support map type in query string [\#316](https://github.com/grpc-ecosystem/grpc-gateway/issues/316)
- gRPC gateway Bazel build rules [\#66](https://github.com/grpc-ecosystem/grpc-gateway/issues/66)
- Support bytes fields in path parameter [\#5](https://github.com/grpc-ecosystem/grpc-gateway/issues/5)
**Closed issues:**
- the protoc\_gen\_swagger bazel rule generates non working import path. [\#633](https://github.com/grpc-ecosystem/grpc-gateway/issues/633)
- code.NotFound should return a 404 instead of a 405 [\#630](https://github.com/grpc-ecosystem/grpc-gateway/issues/630)
- field in query path not found [\#629](https://github.com/grpc-ecosystem/grpc-gateway/issues/629)
- how to use client pool in the gateway? [\#612](https://github.com/grpc-ecosystem/grpc-gateway/issues/612)
- pass http request uri to grpc server [\#587](https://github.com/grpc-ecosystem/grpc-gateway/issues/587)
- bidi streams have racy read caused by goroutine that closes over local variable [\#583](https://github.com/grpc-ecosystem/grpc-gateway/issues/583)
- Streamed response is not valid json \(or: is this the expected format?\) [\#581](https://github.com/grpc-ecosystem/grpc-gateway/issues/581)
- Import "google/api/annotations.proto" was not found or had errors. [\#574](https://github.com/grpc-ecosystem/grpc-gateway/issues/574)
- is there has a way to let grpc-gateway server support multiple endpoints [\#573](https://github.com/grpc-ecosystem/grpc-gateway/issues/573)
- would it be possible to avoid vendoring "third\_party/googleapis/" [\#572](https://github.com/grpc-ecosystem/grpc-gateway/issues/572)
- Path parameters can't have URL encoded values [\#566](https://github.com/grpc-ecosystem/grpc-gateway/issues/566)
- Is there anyway to output the access log of grpc gateway [\#556](https://github.com/grpc-ecosystem/grpc-gateway/issues/556)
- proto: no slice oenc for \*reflect.rtype = \[\]\*reflect.rtype [\#551](https://github.com/grpc-ecosystem/grpc-gateway/issues/551)
- autoreconf not found [\#549](https://github.com/grpc-ecosystem/grpc-gateway/issues/549)
- \[feature\]combine expvar into grpc-gateway [\#542](https://github.com/grpc-ecosystem/grpc-gateway/issues/542)
- Source code still imports "golang.org/x/net/context" [\#533](https://github.com/grpc-ecosystem/grpc-gateway/issues/533)
- Incorrect error message when execute protoc-gen-grpc-gateway to HTTP GET method with BODY [\#531](https://github.com/grpc-ecosystem/grpc-gateway/issues/531)
- add support for the google.api.HttpBody proto as a request [\#528](https://github.com/grpc-ecosystem/grpc-gateway/issues/528)
- Prefixed model names in generated swagger spec [\#525](https://github.com/grpc-ecosystem/grpc-gateway/issues/525)
- Better format for error.message in stream [\#519](https://github.com/grpc-ecosystem/grpc-gateway/issues/519)
- Getting this on go get . in the src directory: HelloService.pb.go:20:8 - no Go files in \go\src\google\api [\#518](https://github.com/grpc-ecosystem/grpc-gateway/issues/518)
- ci: set up codecov [\#513](https://github.com/grpc-ecosystem/grpc-gateway/issues/513)
- protoc-gen-swagger not using description field of info swagger object [\#511](https://github.com/grpc-ecosystem/grpc-gateway/issues/511)
- Cut a minor release for https://github.com/grpc-ecosystem/grpc-gateway/issues/495 [\#506](https://github.com/grpc-ecosystem/grpc-gateway/issues/506)
- bug: uncapitalized service name causes runtime error unknown function in service.pb.gw.go [\#484](https://github.com/grpc-ecosystem/grpc-gateway/issues/484)
- RESOURCE\_EXHAUSTED -\> 503 [\#431](https://github.com/grpc-ecosystem/grpc-gateway/issues/431)
- Adding authentication definitions to generated swagger files [\#428](https://github.com/grpc-ecosystem/grpc-gateway/issues/428)
- Move to stdlib context over x/net/context [\#326](https://github.com/grpc-ecosystem/grpc-gateway/issues/326)
- deprecate 1.6 and embrace \(\*http.Request\).Context by default [\#313](https://github.com/grpc-ecosystem/grpc-gateway/issues/313)
**Merged pull requests:**
- Generate a single swagger definition on demand [\#658](https://github.com/grpc-ecosystem/grpc-gateway/pull/658) ([achew22](https://github.com/achew22))
- Regenerate example files [\#656](https://github.com/grpc-ecosystem/grpc-gateway/pull/656) ([achew22](https://github.com/achew22))
- Add v1.4.0 changelog [\#655](https://github.com/grpc-ecosystem/grpc-gateway/pull/655) ([achew22](https://github.com/achew22))
- Add README.md for examples [\#645](https://github.com/grpc-ecosystem/grpc-gateway/pull/645) ([liukgg](https://github.com/liukgg))
- JSONPb marshaler panics if input is nil interface [\#639](https://github.com/grpc-ecosystem/grpc-gateway/pull/639) ([jhump](https://github.com/jhump))
- provide access to underlying \*json.Decoder from JSONPb.NewDecoder [\#637](https://github.com/grpc-ecosystem/grpc-gateway/pull/637) ([jhump](https://github.com/jhump))
- fix compile errors caused by protobuf finally merging their dev branch to master [\#636](https://github.com/grpc-ecosystem/grpc-gateway/pull/636) ([jhump](https://github.com/jhump))
- Generate import mappings. [\#635](https://github.com/grpc-ecosystem/grpc-gateway/pull/635) ([ensonic](https://github.com/ensonic))
- Add support for the grpc\_api\_configuration option in the bazel rule. [\#632](https://github.com/grpc-ecosystem/grpc-gateway/pull/632) ([ensonic](https://github.com/ensonic))
- Use repo relative labels in protoc-gen-swagger [\#631](https://github.com/grpc-ecosystem/grpc-gateway/pull/631) ([achew22](https://github.com/achew22))
- Correct dependencies in Makefile [\#626](https://github.com/grpc-ecosystem/grpc-gateway/pull/626) ([yugui](https://github.com/yugui))
- Avoid timing issues in the integration tests [\#624](https://github.com/grpc-ecosystem/grpc-gateway/pull/624) ([yugui](https://github.com/yugui))
- Fix typos in gRPC API Configuration usage documentation [\#623](https://github.com/grpc-ecosystem/grpc-gateway/pull/623) ([hacst](https://github.com/hacst))
- Skip unnecessary steps in USE\_BAZEL builds on TravisCI [\#622](https://github.com/grpc-ecosystem/grpc-gateway/pull/622) ([yugui](https://github.com/yugui))
- Support param for field from Oneof definition. [\#621](https://github.com/grpc-ecosystem/grpc-gateway/pull/621) ([bonafideyan](https://github.com/bonafideyan))
- Fixes file integrity errors on TravisCI [\#619](https://github.com/grpc-ecosystem/grpc-gateway/pull/619) ([yugui](https://github.com/yugui))
- Reorganize examples [\#618](https://github.com/grpc-ecosystem/grpc-gateway/pull/618) ([yugui](https://github.com/yugui))
- Update dependency declarations in the Makefile [\#617](https://github.com/grpc-ecosystem/grpc-gateway/pull/617) ([yugui](https://github.com/yugui))
- Support delete method in swagger generator [\#616](https://github.com/grpc-ecosystem/grpc-gateway/pull/616) ([blackdahila](https://github.com/blackdahila))
- feat\(bazel\): Add rule for generating .swagger.json files [\#613](https://github.com/grpc-ecosystem/grpc-gateway/pull/613) ([mrmeku](https://github.com/mrmeku))
- Support UNIX domain socket in the example servers [\#609](https://github.com/grpc-ecosystem/grpc-gateway/pull/609) ([yugui](https://github.com/yugui))
- misspelling [\#601](https://github.com/grpc-ecosystem/grpc-gateway/pull/601) ([chemidy](https://github.com/chemidy))
- Pulled out parseReq func into a generic package + tests [\#600](https://github.com/grpc-ecosystem/grpc-gateway/pull/600) ([f0rmiga](https://github.com/f0rmiga))
- Added Bazel support [\#599](https://github.com/grpc-ecosystem/grpc-gateway/pull/599) ([f0rmiga](https://github.com/f0rmiga))
- Add basic docs section [\#597](https://github.com/grpc-ecosystem/grpc-gateway/pull/597) ([achew22](https://github.com/achew22))
- Upgrade to go1.10 and regenerate [\#596](https://github.com/grpc-ecosystem/grpc-gateway/pull/596) ([achew22](https://github.com/achew22))
- Support cases where the request is done with transfer-encoding chunked [\#589](https://github.com/grpc-ecosystem/grpc-gateway/pull/589) ([jacksontj](https://github.com/jacksontj))
- Support multiple metadata annotators [\#586](https://github.com/grpc-ecosystem/grpc-gateway/pull/586) ([dmacthedestroyer](https://github.com/dmacthedestroyer))
- Changed to use more appropriate http status code for ResourceExhausted [\#580](https://github.com/grpc-ecosystem/grpc-gateway/pull/580) ([eleniums](https://github.com/eleniums))
- fix racy access of err variable [\#575](https://github.com/grpc-ecosystem/grpc-gateway/pull/575) ([jhump](https://github.com/jhump))
- runtime: return 503 not 403 with ResourceExhausted. [\#569](https://github.com/grpc-ecosystem/grpc-gateway/pull/569) ([hexfusion](https://github.com/hexfusion))
- \[\]byte in query now uses base64.StdEncoding [\#565](https://github.com/grpc-ecosystem/grpc-gateway/pull/565) ([lucasvo](https://github.com/lucasvo))
- Add 3rd party rpc protos in order to have access to status and error [\#563](https://github.com/grpc-ecosystem/grpc-gateway/pull/563) ([rvegas](https://github.com/rvegas))
- Add details to stream error response [\#561](https://github.com/grpc-ecosystem/grpc-gateway/pull/561) ([johanbrandhorst](https://github.com/johanbrandhorst))
- fix noenc error by fixing Details error field [\#557](https://github.com/grpc-ecosystem/grpc-gateway/pull/557) ([srenatus](https://github.com/srenatus))
- error details: add @type key by switching to any.Any [\#553](https://github.com/grpc-ecosystem/grpc-gateway/pull/553) ([srenatus](https://github.com/srenatus))
- Add a FAQ [\#550](https://github.com/grpc-ecosystem/grpc-gateway/pull/550) ([achew22](https://github.com/achew22))
- Add security fields support to protoc-gen-swagger [\#547](https://github.com/grpc-ecosystem/grpc-gateway/pull/547) ([ivucica](https://github.com/ivucica))
- Omit well-known type definitions from swagger output [\#541](https://github.com/grpc-ecosystem/grpc-gateway/pull/541) ([alexleigh](https://github.com/alexleigh))
- Use importPath to set package name rather than package path. [\#537](https://github.com/grpc-ecosystem/grpc-gateway/pull/537) ([rwlincoln](https://github.com/rwlincoln))
- Support for map type in query string [\#535](https://github.com/grpc-ecosystem/grpc-gateway/pull/535) ([adamstruck](https://github.com/adamstruck))
- Fix error message in protoc-gen-grpc-gateway \(for \#531\) [\#532](https://github.com/grpc-ecosystem/grpc-gateway/pull/532) ([budougumi0617](https://github.com/budougumi0617))
- runtime: support FieldMask as query param [\#529](https://github.com/grpc-ecosystem/grpc-gateway/pull/529) ([glerchundi](https://github.com/glerchundi))
- Fix decoding empty request body [\#527](https://github.com/grpc-ecosystem/grpc-gateway/pull/527) ([syhpoon](https://github.com/syhpoon))
- Add description, summary and tags fields in operationObject \(swagger\) [\#526](https://github.com/grpc-ecosystem/grpc-gateway/pull/526) ([devnull-](https://github.com/devnull-))
- Converts the first letter of service name to uppercase [\#522](https://github.com/grpc-ecosystem/grpc-gateway/pull/522) ([thurt](https://github.com/thurt))
- Add support for basic gRPC API Configuration YAML files [\#521](https://github.com/grpc-ecosystem/grpc-gateway/pull/521) ([hacst](https://github.com/hacst))
- Fix travis to only difftest on go 1.9 [\#520](https://github.com/grpc-ecosystem/grpc-gateway/pull/520) ([achew22](https://github.com/achew22))
- add error details to error json [\#515](https://github.com/grpc-ecosystem/grpc-gateway/pull/515) ([srenatus](https://github.com/srenatus))
- ci: add codecov [\#514](https://github.com/grpc-ecosystem/grpc-gateway/pull/514) ([tmc](https://github.com/tmc))
- Generate "Description" and "TermsOfService" fields [\#512](https://github.com/grpc-ecosystem/grpc-gateway/pull/512) ([lukasmalkmus](https://github.com/lukasmalkmus))
- Release 1.3.1 [\#509](https://github.com/grpc-ecosystem/grpc-gateway/pull/509) ([tmc](https://github.com/tmc))
- Support mapping bytes to \[\]byte [\#489](https://github.com/grpc-ecosystem/grpc-gateway/pull/489) ([loderunner](https://github.com/loderunner))
- properly respect file flag for protoc-gen-swagger [\#293](https://github.com/grpc-ecosystem/grpc-gateway/pull/293) ([tmc](https://github.com/tmc))
## [v1.3.1](https://grpc-ecosystem.github.io/grpc-gateway/grpc-ecosystem/grpc-gateway/tree/v1.3.1) (2017-12-23)
[Full Changelog](https://grpc-ecosystem.github.io/grpc-gateway/grpc-ecosystem/grpc-gateway/compare/v1.3.0...v1.3.1)
**Implemented enhancements:**
- Support import\_path? [\#443](https://github.com/grpc-ecosystem/grpc-gateway/issues/443)
**Closed issues:**
- protoc-gen-swagger missing definition issue [\#504](https://github.com/grpc-ecosystem/grpc-gateway/issues/504)
- Are gateway metrics available? [\#498](https://github.com/grpc-ecosystem/grpc-gateway/issues/498)
- Backwards incompatible change to chunked encoding [\#495](https://github.com/grpc-ecosystem/grpc-gateway/issues/495)
- Map of list [\#493](https://github.com/grpc-ecosystem/grpc-gateway/issues/493)
- Repeated nested messages doesn't work in GET requests queries. [\#492](https://github.com/grpc-ecosystem/grpc-gateway/issues/492)
- How to run `makefile` for this repo? [\#491](https://github.com/grpc-ecosystem/grpc-gateway/issues/491)
- all SubConns are in TransientFailure [\#490](https://github.com/grpc-ecosystem/grpc-gateway/issues/490)
- Appengine Standard Environment: "not an Appengine context" [\#487](https://github.com/grpc-ecosystem/grpc-gateway/issues/487)
- Enum Path Parameter to Swagger [\#486](https://github.com/grpc-ecosystem/grpc-gateway/issues/486)
- Should v1.3 be also tagged as v1.3.0? [\#483](https://github.com/grpc-ecosystem/grpc-gateway/issues/483)
- HTTP response is not correct json encoded if the grpc return stream of objects. [\#481](https://github.com/grpc-ecosystem/grpc-gateway/issues/481)
- Support JSON-RPCv2 [\#477](https://github.com/grpc-ecosystem/grpc-gateway/issues/477)
- Naming convention? [\#475](https://github.com/grpc-ecosystem/grpc-gateway/issues/475)
- Request context not being used [\#470](https://github.com/grpc-ecosystem/grpc-gateway/issues/470)
- Generate Swagger documentation [\#469](https://github.com/grpc-ecosystem/grpc-gateway/issues/469)
- Support Request | make: swagger-codegen: Command not found [\#468](https://github.com/grpc-ecosystem/grpc-gateway/issues/468)
- How do you generate a swagger yaml file instead of json? [\#467](https://github.com/grpc-ecosystem/grpc-gateway/issues/467)
- Add default support for proto over http [\#465](https://github.com/grpc-ecosystem/grpc-gateway/issues/465)
- Allow compiling the gateway code to a different go package [\#463](https://github.com/grpc-ecosystem/grpc-gateway/issues/463)
- support google.api.HttpBody [\#457](https://github.com/grpc-ecosystem/grpc-gateway/issues/457)
- \[swagger bug\] with google/protobuf/wrappers.proto [\#453](https://github.com/grpc-ecosystem/grpc-gateway/issues/453)
- The tensorflow serving support RESTful api{"error":"json: cannot unmarshal object into Go value of type \[\]json.RawMessage","code":3} [\#444](https://github.com/grpc-ecosystem/grpc-gateway/issues/444)
- choose some return fields omit or not omit by configure [\#439](https://github.com/grpc-ecosystem/grpc-gateway/issues/439)
- swagger title and version hardcoded [\#437](https://github.com/grpc-ecosystem/grpc-gateway/issues/437)
- Change the path though http header [\#424](https://github.com/grpc-ecosystem/grpc-gateway/issues/424)
- google/protobuf/descriptor.proto: File not found [\#422](https://github.com/grpc-ecosystem/grpc-gateway/issues/422)
- Output file will not compile if the .proto file does not contain a service with parameters in the url path [\#389](https://github.com/grpc-ecosystem/grpc-gateway/issues/389)
- Scaling support [\#381](https://github.com/grpc-ecosystem/grpc-gateway/issues/381)
- I cannot get the default value from client side [\#380](https://github.com/grpc-ecosystem/grpc-gateway/issues/380)
- Problem with Generated annotations.proto file [\#377](https://github.com/grpc-ecosystem/grpc-gateway/issues/377)
- Release 1.3.0 [\#357](https://github.com/grpc-ecosystem/grpc-gateway/issues/357)
- swagger: Unclear comments' parser behaviour [\#352](https://github.com/grpc-ecosystem/grpc-gateway/issues/352)
- Support semicolon syntax in go\_package protobuf option [\#341](https://github.com/grpc-ecosystem/grpc-gateway/issues/341)
- Add SOAP proxy [\#339](https://github.com/grpc-ecosystem/grpc-gateway/issues/339)
- Support combination of query params and body for POSTs [\#234](https://github.com/grpc-ecosystem/grpc-gateway/issues/234)
- Interceptor [\#221](https://github.com/grpc-ecosystem/grpc-gateway/issues/221)
**Merged pull requests:**
- Add support for --Import\_path [\#507](https://github.com/grpc-ecosystem/grpc-gateway/pull/507) ([achew22](https://github.com/achew22))
- Fix \#504 Missing Definitions [\#505](https://github.com/grpc-ecosystem/grpc-gateway/pull/505) ([warmans](https://github.com/warmans))
- Maintain default delimiter of newline [\#497](https://github.com/grpc-ecosystem/grpc-gateway/pull/497) ([jacksontj](https://github.com/jacksontj))
- Fix gen-swagger to support more well known types [\#496](https://github.com/grpc-ecosystem/grpc-gateway/pull/496) ([shouichi](https://github.com/shouichi))
- Use golang/protobuf instead of gogo/protobuf [\#494](https://github.com/grpc-ecosystem/grpc-gateway/pull/494) ([shouichi](https://github.com/shouichi))
- Fix stream delimiters [\#488](https://github.com/grpc-ecosystem/grpc-gateway/pull/488) ([afking](https://github.com/afking))
- ForwardResponseStream status code errors [\#482](https://github.com/grpc-ecosystem/grpc-gateway/pull/482) ([afking](https://github.com/afking))
- protoc-gen-grpc-gateway: flip request\_context default to true [\#474](https://github.com/grpc-ecosystem/grpc-gateway/pull/474) ([srenatus](https://github.com/srenatus))
- grpc-gateway/generator: respect full package [\#462](https://github.com/grpc-ecosystem/grpc-gateway/pull/462) ([glerchundi](https://github.com/glerchundi))
- Add proto marshaller for proto-over-http [\#459](https://github.com/grpc-ecosystem/grpc-gateway/pull/459) ([MatthewDolan](https://github.com/MatthewDolan))
## [v1.3.0](https://grpc-ecosystem.github.io/grpc-gateway/grpc-ecosystem/grpc-gateway/tree/v1.3.0) (2017-11-03)
[Full Changelog](https://grpc-ecosystem.github.io/grpc-gateway/grpc-ecosystem/grpc-gateway/compare/v1.3...v1.3.0)
## [v1.3](https://grpc-ecosystem.github.io/grpc-gateway/grpc-ecosystem/grpc-gateway/tree/v1.3) (2017-11-03)
[Full Changelog](https://grpc-ecosystem.github.io/grpc-gateway/grpc-ecosystem/grpc-gateway/compare/v1.2.2...v1.3)
**Closed issues:**
- Extract basic auth from URL [\#480](https://github.com/grpc-ecosystem/grpc-gateway/issues/480)
- Lack of "google/protobuf/descriptor.proto" [\#476](https://github.com/grpc-ecosystem/grpc-gateway/issues/476)
- question: how to indicate whether call is through grpc gateway [\#456](https://github.com/grpc-ecosystem/grpc-gateway/issues/456)
- How to define this restful api using pb? [\#452](https://github.com/grpc-ecosystem/grpc-gateway/issues/452)
- how to output field as an array of json values? [\#449](https://github.com/grpc-ecosystem/grpc-gateway/issues/449)
- How do I override maxMsgSize? [\#445](https://github.com/grpc-ecosystem/grpc-gateway/issues/445)
- OpenAPI spec is generated with duplicated operation IDs. [\#442](https://github.com/grpc-ecosystem/grpc-gateway/issues/442)
- This process seems to generate conflicting code with go-micro [\#440](https://github.com/grpc-ecosystem/grpc-gateway/issues/440)
- any way to let int64 marshal to int not string? [\#438](https://github.com/grpc-ecosystem/grpc-gateway/issues/438)
- Support streaming [\#435](https://github.com/grpc-ecosystem/grpc-gateway/issues/435)
- Update DO NOT EDIT header in generated files [\#433](https://github.com/grpc-ecosystem/grpc-gateway/issues/433)
- generate code use context not "golang.org/x/net/context" [\#430](https://github.com/grpc-ecosystem/grpc-gateway/issues/430)
- Replace \n with spaces in swagger definitions [\#426](https://github.com/grpc-ecosystem/grpc-gateway/issues/426)
- \[question\]Is there any example for http headers process? [\#420](https://github.com/grpc-ecosystem/grpc-gateway/issues/420)
- Is there any way to support a multipart form request? [\#410](https://github.com/grpc-ecosystem/grpc-gateway/issues/410)
- Not able to pass allow\_delete\_body to protoc-gen-grpc-gateway. [\#402](https://github.com/grpc-ecosystem/grpc-gateway/issues/402)
- returned errors should conform to google.rpc.Status [\#399](https://github.com/grpc-ecosystem/grpc-gateway/issues/399)
- Is there any way to generate python gateway code? [\#398](https://github.com/grpc-ecosystem/grpc-gateway/issues/398)
- how to handle arbitrary \(json\) structs [\#395](https://github.com/grpc-ecosystem/grpc-gateway/issues/395)
- \[question\]can give a url with query sting demo? [\#394](https://github.com/grpc-ecosystem/grpc-gateway/issues/394)
- \[question\]the swagger url generated is what? [\#393](https://github.com/grpc-ecosystem/grpc-gateway/issues/393)
- \[Question\] How do I use semantic versions? [\#392](https://github.com/grpc-ecosystem/grpc-gateway/issues/392)
- \[question\]how to run examples? [\#391](https://github.com/grpc-ecosystem/grpc-gateway/issues/391)
- Why does gateway use ServerMetadata? [\#388](https://github.com/grpc-ecosystem/grpc-gateway/issues/388)
- Can't generate code with last version [\#384](https://github.com/grpc-ecosystem/grpc-gateway/issues/384)
- is it ready for production use? [\#382](https://github.com/grpc-ecosystem/grpc-gateway/issues/382)
- Support Google Flatbuffers [\#376](https://github.com/grpc-ecosystem/grpc-gateway/issues/376)
- calling Enum by string name in requests using gogo/protobuf results in error. [\#372](https://github.com/grpc-ecosystem/grpc-gateway/issues/372)
- Definitions containing URLs with trailing slashes won't compile [\#370](https://github.com/grpc-ecosystem/grpc-gateway/issues/370)
- Should metadata annotator include the headers from incoming matcher? [\#368](https://github.com/grpc-ecosystem/grpc-gateway/issues/368)
- metadata.NewOutgoingContext is undefined [\#364](https://github.com/grpc-ecosystem/grpc-gateway/issues/364)
- Why does not gateway forward headers as-is? [\#311](https://github.com/grpc-ecosystem/grpc-gateway/issues/311)
- Question: Why passing context to RegisterMyServiceHandler is required? [\#301](https://github.com/grpc-ecosystem/grpc-gateway/issues/301)
- Allow whitelisting of particular HTTP headers to map to metadata. [\#253](https://github.com/grpc-ecosystem/grpc-gateway/issues/253)
- Swagger definitions don't handle parameters that are not explicitly required in the url [\#159](https://github.com/grpc-ecosystem/grpc-gateway/issues/159)
**Merged pull requests:**
- Fix wrong method names [\#603](https://github.com/grpc-ecosystem/grpc-gateway/pull/603) ([yugui](https://github.com/yugui))
- Streaming forward handler fix chunk encoding [\#479](https://github.com/grpc-ecosystem/grpc-gateway/pull/479) ([afking](https://github.com/afking))
- Fix logic handling primitive wrapper in URL params [\#478](https://github.com/grpc-ecosystem/grpc-gateway/pull/478) ([tgeng](https://github.com/tgeng))
- runtime: use r.Context\(\) [\#473](https://github.com/grpc-ecosystem/grpc-gateway/pull/473) ([srenatus](https://github.com/srenatus))
- Optional SourceCodeInfo [\#466](https://github.com/grpc-ecosystem/grpc-gateway/pull/466) ([afking](https://github.com/afking))
- Some steps to fix Travis CI [\#461](https://github.com/grpc-ecosystem/grpc-gateway/pull/461) ([AlekSi](https://github.com/AlekSi))
- fix 2 typos in Registry.SetPrefix's comment [\#455](https://github.com/grpc-ecosystem/grpc-gateway/pull/455) ([hectorj](https://github.com/hectorj))
- Add Handler method to pass in client [\#454](https://github.com/grpc-ecosystem/grpc-gateway/pull/454) ([jacksontj](https://github.com/jacksontj))
- Fallback to JSON name when matching URL parameter. [\#450](https://github.com/grpc-ecosystem/grpc-gateway/pull/450) ([tgeng](https://github.com/tgeng))
- Update DO NOT EDIT template. [\#434](https://github.com/grpc-ecosystem/grpc-gateway/pull/434) ([AlekSi](https://github.com/AlekSi))
- Memoise calls to fullyQualifiedNameToSwaggerName to speed it up for large registries [\#421](https://github.com/grpc-ecosystem/grpc-gateway/pull/421) ([peterebden](https://github.com/peterebden))
- Update Swagger Codegen from 2.1.6 to 2.2.2 [\#415](https://github.com/grpc-ecosystem/grpc-gateway/pull/415) ([yugui](https://github.com/yugui))
- Return codes.InvalidArgument to rather return HTTP 400 instead of HTTP 500 [\#409](https://github.com/grpc-ecosystem/grpc-gateway/pull/409) ([vaporz](https://github.com/vaporz))
- improve {incoming,outgoing}HeaderMatcher logic [\#408](https://github.com/grpc-ecosystem/grpc-gateway/pull/408) ([flisky](https://github.com/flisky))
- improve WKT handling in gateway and openapi output [\#404](https://github.com/grpc-ecosystem/grpc-gateway/pull/404) ([tmc](https://github.com/tmc))
- Return if runtime.AnnotateContext gave error [\#403](https://github.com/grpc-ecosystem/grpc-gateway/pull/403) ([tamalsaha](https://github.com/tamalsaha))
- jsonpb: update tests to reflect new jsonpb behavior [\#401](https://github.com/grpc-ecosystem/grpc-gateway/pull/401) ([tmc](https://github.com/tmc))
- Reference import grpc Status to suppress unused errors. [\#387](https://github.com/grpc-ecosystem/grpc-gateway/pull/387) ([tamalsaha](https://github.com/tamalsaha))
- ci: regen with current protoc-gen-go [\#385](https://github.com/grpc-ecosystem/grpc-gateway/pull/385) ([tmc](https://github.com/tmc))
- Use status package for error and introduce WithProtoErrorHandler option [\#378](https://github.com/grpc-ecosystem/grpc-gateway/pull/378) ([kazegusuri](https://github.com/kazegusuri))
- Return response headers from grpc server [\#374](https://github.com/grpc-ecosystem/grpc-gateway/pull/374) ([tamalsaha](https://github.com/tamalsaha))
- Skip unreferenced messages in definitions. [\#371](https://github.com/grpc-ecosystem/grpc-gateway/pull/371) ([Lantame](https://github.com/Lantame))
- Use canonical header form in default header matcher. [\#369](https://github.com/grpc-ecosystem/grpc-gateway/pull/369) ([tamalsaha](https://github.com/tamalsaha))
- support allow\_delete\_body for protoc-gen-grpc-gateway [\#318](https://github.com/grpc-ecosystem/grpc-gateway/pull/318) ([flisky](https://github.com/flisky))
- fixes package name override doesn't work [\#277](https://github.com/grpc-ecosystem/grpc-gateway/pull/277) ([favadi](https://github.com/favadi))
- add custom options to allow more control of swagger/openapi output [\#145](https://github.com/grpc-ecosystem/grpc-gateway/pull/145) ([ivucica](https://github.com/ivucica))
## [v1.2.2](https://grpc-ecosystem.github.io/grpc-gateway/grpc-ecosystem/grpc-gateway/tree/v1.2.2) (2017-04-17)
[Full Changelog](https://grpc-ecosystem.github.io/grpc-gateway/grpc-ecosystem/grpc-gateway/compare/v1.2.1...v1.2.2)
**Merged pull requests:**
- Add changelog for 1.2.2 [\#363](https://github.com/grpc-ecosystem/grpc-gateway/pull/363) ([tmc](https://github.com/tmc))
- metadata: fix properly and change to Outgoing [\#361](https://github.com/grpc-ecosystem/grpc-gateway/pull/361) ([tmc](https://github.com/tmc))
## [v1.2.1](https://grpc-ecosystem.github.io/grpc-gateway/grpc-ecosystem/grpc-gateway/tree/v1.2.1) (2017-04-17)
[Full Changelog](https://grpc-ecosystem.github.io/grpc-gateway/grpc-ecosystem/grpc-gateway/compare/v1.2.0...v1.2.1)
**Fixed bugs:**
- reflect upstream grpc metadata api change [\#358](https://github.com/grpc-ecosystem/grpc-gateway/issues/358)
**Closed issues:**
- Empty value omitted [\#355](https://github.com/grpc-ecosystem/grpc-gateway/issues/355)
- Must generate reverse proxy in same package? [\#353](https://github.com/grpc-ecosystem/grpc-gateway/issues/353)
- Release 1.2.0 [\#340](https://github.com/grpc-ecosystem/grpc-gateway/issues/340)
- Cut another release [\#278](https://github.com/grpc-ecosystem/grpc-gateway/issues/278)
**Merged pull requests:**
- Add changelog for 1.2.1 [\#360](https://github.com/grpc-ecosystem/grpc-gateway/pull/360) ([tmc](https://github.com/tmc))
- bugfix: reflect upstream api change. [\#359](https://github.com/grpc-ecosystem/grpc-gateway/pull/359) ([tmc](https://github.com/tmc))
## [v1.2.0](https://grpc-ecosystem.github.io/grpc-gateway/grpc-ecosystem/grpc-gateway/tree/v1.2.0) (2017-03-31)
[Full Changelog](https://grpc-ecosystem.github.io/grpc-gateway/grpc-ecosystem/grpc-gateway/compare/v1.2.0.rc1...v1.2.0)
**Closed issues:**
- Problem with \*.proto as "no buildable Go source files" [\#338](https://github.com/grpc-ecosystem/grpc-gateway/issues/338)
- Invalid import during code generation [\#337](https://github.com/grpc-ecosystem/grpc-gateway/issues/337)
**Merged pull requests:**
- Add changelog for 1.2.0 [\#342](https://github.com/grpc-ecosystem/grpc-gateway/pull/342) ([tmc](https://github.com/tmc))
## [v1.2.0.rc1](https://grpc-ecosystem.github.io/grpc-gateway/grpc-ecosystem/grpc-gateway/tree/v1.2.0.rc1) (2017-03-24)
[Full Changelog](https://grpc-ecosystem.github.io/grpc-gateway/grpc-ecosystem/grpc-gateway/compare/v1.1.0...v1.2.0.rc1)
**Implemented enhancements:**
- Support for Any types [\#80](https://github.com/grpc-ecosystem/grpc-gateway/issues/80)
- improve\(genswagger:template\):added support for google.protobuf.Timestamp [\#209](https://github.com/grpc-ecosystem/grpc-gateway/pull/209) ([EranAvidor](https://github.com/EranAvidor))
**Fixed bugs:**
- Support for multi-segment elements [\#122](https://github.com/grpc-ecosystem/grpc-gateway/issues/122)
**Closed issues:**
- Go get breaks with autogenerated code [\#331](https://github.com/grpc-ecosystem/grpc-gateway/issues/331)
- Fresh install no longer generates necessary `google/api/annotations.pb.go` & `google/api/http.pb.go` files. [\#327](https://github.com/grpc-ecosystem/grpc-gateway/issues/327)
- Panic with query parameters [\#324](https://github.com/grpc-ecosystem/grpc-gateway/issues/324)
- Swagger-UI query parameters for enum types are sent as strings [\#320](https://github.com/grpc-ecosystem/grpc-gateway/issues/320)
- hide the object name in the response [\#317](https://github.com/grpc-ecosystem/grpc-gateway/issues/317)
- Package imported but not used [\#310](https://github.com/grpc-ecosystem/grpc-gateway/issues/310)
- Authorization headers aren't specified in Swagger.json [\#309](https://github.com/grpc-ecosystem/grpc-gateway/issues/309)
- Generating swagger version, contact name etc in generated docs [\#303](https://github.com/grpc-ecosystem/grpc-gateway/issues/303)
- Feature request: custom content type per service and rpc [\#302](https://github.com/grpc-ecosystem/grpc-gateway/issues/302)
- Reference: another RESTful api-gateway [\#299](https://github.com/grpc-ecosystem/grpc-gateway/issues/299)
- Integration with other languages is partially broken [\#298](https://github.com/grpc-ecosystem/grpc-gateway/issues/298)
- jsonpb convert int64 to integer instead of string [\#296](https://github.com/grpc-ecosystem/grpc-gateway/issues/296)
- default enum value is omitted [\#294](https://github.com/grpc-ecosystem/grpc-gateway/issues/294)
- Advice: could we simplify the flow as the below [\#292](https://github.com/grpc-ecosystem/grpc-gateway/issues/292)
- examples/browser test failure: TypeError: undefined is not a function \(evaluating 'window.location.protocol.startsWith\('chrome-extension'\)'\) [\#287](https://github.com/grpc-ecosystem/grpc-gateway/issues/287)
- ./entrypoint.go:25: undefined: api.RegisterYourServiceHandlerFromEndpoint [\#285](https://github.com/grpc-ecosystem/grpc-gateway/issues/285)
- Query params not handled in swagger file [\#284](https://github.com/grpc-ecosystem/grpc-gateway/issues/284)
- Please help: google/api/annotations.proto: File not found. [\#283](https://github.com/grpc-ecosystem/grpc-gateway/issues/283)
- Option to Allow Swagger for DELETEs with a body [\#279](https://github.com/grpc-ecosystem/grpc-gateway/issues/279)
- client declared and not used compilation error, after recent upgrade [\#276](https://github.com/grpc-ecosystem/grpc-gateway/issues/276)
- feature request / idea: generating JSONRPC2 client proxies from GRPC [\#272](https://github.com/grpc-ecosystem/grpc-gateway/issues/272)
- protoc-swagger-generator messes up the comments if there is rpc method that does not have rest [\#263](https://github.com/grpc-ecosystem/grpc-gateway/issues/263)
- Swagger Gen: underscores -\> lowerCamelCase field names and refs [\#261](https://github.com/grpc-ecosystem/grpc-gateway/issues/261)
- Timestamp as URL param causes bad request error [\#260](https://github.com/grpc-ecosystem/grpc-gateway/issues/260)
- "proto: no coders for int" printed whenever a gRPC error is returned over grpc-gateway. [\#259](https://github.com/grpc-ecosystem/grpc-gateway/issues/259)
- Compatibility with grpc.SupportPackageIsVersion4 [\#258](https://github.com/grpc-ecosystem/grpc-gateway/issues/258)
- How to use circuit breaker in this grpc gateway? [\#257](https://github.com/grpc-ecosystem/grpc-gateway/issues/257)
- cannot use example code to generate [\#255](https://github.com/grpc-ecosystem/grpc-gateway/issues/255)
- tests fail on go tip due to importing of main packages in test [\#250](https://github.com/grpc-ecosystem/grpc-gateway/issues/250)
- Add NGINX support [\#249](https://github.com/grpc-ecosystem/grpc-gateway/issues/249)
- Error when reverse proxy to gRPC server \(which is impl with Node.js\) [\#246](https://github.com/grpc-ecosystem/grpc-gateway/issues/246)
- Error output titlecase instead of lowercase [\#243](https://github.com/grpc-ecosystem/grpc-gateway/issues/243)
- Option field "\(google.api.http\)" is not a field or extension of message "ServiceOptions" [\#241](https://github.com/grpc-ecosystem/grpc-gateway/issues/241)
- Implement credentials handler in-box [\#238](https://github.com/grpc-ecosystem/grpc-gateway/issues/238)
- Proposal: Support WKT structs for URL params [\#237](https://github.com/grpc-ecosystem/grpc-gateway/issues/237)
- Example of /} in path template [\#232](https://github.com/grpc-ecosystem/grpc-gateway/issues/232)
- Serving swagger.json from runtime mux? [\#230](https://github.com/grpc-ecosystem/grpc-gateway/issues/230)
- ETCDclientv3 build error with the latest changes - github.com/grpc-ecosystem/grpc-gateway/runtime/marshal\_jsonpb.go:114: undefined: jsonpb.Unmarshaler [\#226](https://github.com/grpc-ecosystem/grpc-gateway/issues/226)
- Map in GET request [\#223](https://github.com/grpc-ecosystem/grpc-gateway/issues/223)
- HTTPS no longer works [\#220](https://github.com/grpc-ecosystem/grpc-gateway/issues/220)
- --swagger\_out plugin translates proto type int64 to string in Swagger specification [\#219](https://github.com/grpc-ecosystem/grpc-gateway/issues/219)
- Response body as a single field [\#217](https://github.com/grpc-ecosystem/grpc-gateway/issues/217)
- documentation of semantics of endpoint declarations [\#212](https://github.com/grpc-ecosystem/grpc-gateway/issues/212)
- gen-swagger does not generate PATCH method endpoints [\#211](https://github.com/grpc-ecosystem/grpc-gateway/issues/211)
- protoc-gen-grpc-gateway doesn't work correctly with option go\_package [\#207](https://github.com/grpc-ecosystem/grpc-gateway/issues/207)
- Browser Side Streaming Best Practices [\#206](https://github.com/grpc-ecosystem/grpc-gateway/issues/206)
- Does grpc-gateway support App Engine? [\#204](https://github.com/grpc-ecosystem/grpc-gateway/issues/204)
- "use of internal package" error, after moving to grpc-ecosystem [\#203](https://github.com/grpc-ecosystem/grpc-gateway/issues/203)
- Move to google.golang.org/genproto instead of shipping annotations.proto. [\#202](https://github.com/grpc-ecosystem/grpc-gateway/issues/202)
- Release v1.1.0 [\#196](https://github.com/grpc-ecosystem/grpc-gateway/issues/196)
- marshaler runtime.Marshaler does not handle io.EOF when decoding [\#195](https://github.com/grpc-ecosystem/grpc-gateway/issues/195)
- protobuf enumerated values now returned as strings instead of numbers. [\#186](https://github.com/grpc-ecosystem/grpc-gateway/issues/186)
- support annotating fields as required \(in swagger/oapi generation\)? [\#175](https://github.com/grpc-ecosystem/grpc-gateway/issues/175)
- architectural question: Can i codegen the client code for talking to the server ? [\#167](https://github.com/grpc-ecosystem/grpc-gateway/issues/167)
- Passing ENUM value as URL parameter throws error [\#166](https://github.com/grpc-ecosystem/grpc-gateway/issues/166)
- Support specifying which schemes should be output in swagger.json [\#161](https://github.com/grpc-ecosystem/grpc-gateway/issues/161)
- Use headers for routing [\#157](https://github.com/grpc-ecosystem/grpc-gateway/issues/157)
- ENUM in swagger.json makes client code failed to parse response from gateway [\#153](https://github.com/grpc-ecosystem/grpc-gateway/issues/153)
- Support map types [\#140](https://github.com/grpc-ecosystem/grpc-gateway/issues/140)
- generate OpenAPI/swagger documentation at run time? [\#138](https://github.com/grpc-ecosystem/grpc-gateway/issues/138)
- After the 1.7 release, update .travis.yaml to check the compiled proto output [\#137](https://github.com/grpc-ecosystem/grpc-gateway/issues/137)
- Getting parsed runtime.Pattern from server mux [\#127](https://github.com/grpc-ecosystem/grpc-gateway/issues/127)
- REST API without proxying [\#46](https://github.com/grpc-ecosystem/grpc-gateway/issues/46)
**Merged pull requests:**
- Remove an obsolete custom option [\#604](https://github.com/grpc-ecosystem/grpc-gateway/pull/604) ([yugui](https://github.com/yugui))
- Support user configurable header forwarding & context metadata [\#336](https://github.com/grpc-ecosystem/grpc-gateway/pull/336) ([tamalsaha](https://github.com/tamalsaha))
- Update go\_out parameter to remove comma [\#333](https://github.com/grpc-ecosystem/grpc-gateway/pull/333) ([tmc](https://github.com/tmc))
- Update stale path in README [\#332](https://github.com/grpc-ecosystem/grpc-gateway/pull/332) ([tmc](https://github.com/tmc))
- improve documentation regarding external dependencies [\#330](https://github.com/grpc-ecosystem/grpc-gateway/pull/330) ([CaptTofu](https://github.com/CaptTofu))
- Return an error on invalid nested query parameters. [\#329](https://github.com/grpc-ecosystem/grpc-gateway/pull/329) ([fische](https://github.com/fische))
- Update upstream proto files and add google.golang.org/genproto support. [\#325](https://github.com/grpc-ecosystem/grpc-gateway/pull/325) ([tmc](https://github.com/tmc))
- Support oneof fields in query params [\#321](https://github.com/grpc-ecosystem/grpc-gateway/pull/321) ([nilium](https://github.com/nilium))
- Do not ignore the error coming from http.ListenAndServe in examples [\#319](https://github.com/grpc-ecosystem/grpc-gateway/pull/319) ([campoy](https://github.com/campoy))
- Look up enum value maps by their proto name [\#315](https://github.com/grpc-ecosystem/grpc-gateway/pull/315) ([nilium](https://github.com/nilium))
- enable parsing enums from query parameters [\#314](https://github.com/grpc-ecosystem/grpc-gateway/pull/314) ([tzneal](https://github.com/tzneal))
- Do not add imports from methods with no bindings. [\#312](https://github.com/grpc-ecosystem/grpc-gateway/pull/312) ([fische](https://github.com/fische))
- Convert the first letter of method name to upper [\#300](https://github.com/grpc-ecosystem/grpc-gateway/pull/300) ([lipixun](https://github.com/lipixun))
- write query parameters to swagger definition [\#297](https://github.com/grpc-ecosystem/grpc-gateway/pull/297) ([t-yuki](https://github.com/t-yuki))
- Bump swagger-client to 2.1.28 for examples/browser [\#290](https://github.com/grpc-ecosystem/grpc-gateway/pull/290) ([tmc](https://github.com/tmc))
- pin to version before es6ism [\#289](https://github.com/grpc-ecosystem/grpc-gateway/pull/289) ([tmc](https://github.com/tmc))
- Prevent lack of http bindings from generating non-building output [\#286](https://github.com/grpc-ecosystem/grpc-gateway/pull/286) ([tmc](https://github.com/tmc))
- Added support for Timestamp in URL. [\#281](https://github.com/grpc-ecosystem/grpc-gateway/pull/281) ([johansja](https://github.com/johansja))
- add plugin param 'allow\_delete\_body' [\#280](https://github.com/grpc-ecosystem/grpc-gateway/pull/280) ([msample](https://github.com/msample))
- Fix ruby gen command [\#275](https://github.com/grpc-ecosystem/grpc-gateway/pull/275) ([bluehallu](https://github.com/bluehallu))
- Make grpc-gateway support enum fields in path parameter [\#273](https://github.com/grpc-ecosystem/grpc-gateway/pull/273) ([linuxerwang](https://github.com/linuxerwang))
- remove unnecessary make\(\) [\#271](https://github.com/grpc-ecosystem/grpc-gateway/pull/271) ([tmc](https://github.com/tmc))
- preserve field order in swagger spec [\#270](https://github.com/grpc-ecosystem/grpc-gateway/pull/270) ([tmc](https://github.com/tmc))
- Merge \#228 [\#268](https://github.com/grpc-ecosystem/grpc-gateway/pull/268) ([tmc](https://github.com/tmc))
- Handle methods with no bindings more carefully [\#267](https://github.com/grpc-ecosystem/grpc-gateway/pull/267) ([tmc](https://github.com/tmc))
- describe default marshaler in README.md [\#266](https://github.com/grpc-ecosystem/grpc-gateway/pull/266) ([tmc](https://github.com/tmc))
- Add request\_context flag to utilize \(\*http.Request\).Context\(\) in handlers [\#265](https://github.com/grpc-ecosystem/grpc-gateway/pull/265) ([tmc](https://github.com/tmc))
- Regenerate examples [\#264](https://github.com/grpc-ecosystem/grpc-gateway/pull/264) ([tmc](https://github.com/tmc))
- Correct runtime.errorBody protobuf field tag [\#256](https://github.com/grpc-ecosystem/grpc-gateway/pull/256) ([tmc](https://github.com/tmc))
- Pass permanent HTTP request headers [\#252](https://github.com/grpc-ecosystem/grpc-gateway/pull/252) ([tmc](https://github.com/tmc))
- regenerate examples, fix tests for go tip [\#248](https://github.com/grpc-ecosystem/grpc-gateway/pull/248) ([tmc](https://github.com/tmc))
- Render the swagger request body properly [\#247](https://github.com/grpc-ecosystem/grpc-gateway/pull/247) ([dprotaso](https://github.com/dprotaso))
- Error output should have lowercase attribute names [\#244](https://github.com/grpc-ecosystem/grpc-gateway/pull/244) ([nathanborror](https://github.com/nathanborror))
- runtime - export prefix constants [\#236](https://github.com/grpc-ecosystem/grpc-gateway/pull/236) ([philipithomas](https://github.com/philipithomas))
- README - Add CoreOS example [\#231](https://github.com/grpc-ecosystem/grpc-gateway/pull/231) ([philipithomas](https://github.com/philipithomas))
- Docs - Add section about how HTTP maps to gRPC [\#227](https://github.com/grpc-ecosystem/grpc-gateway/pull/227) ([philipithomas](https://github.com/philipithomas))
- readme: added links to additional documentation [\#222](https://github.com/grpc-ecosystem/grpc-gateway/pull/222) ([sdemos](https://github.com/sdemos))
- Use a released version of protoc [\#216](https://github.com/grpc-ecosystem/grpc-gateway/pull/216) ([yugui](https://github.com/yugui))
- Add contribution guideline [\#210](https://github.com/grpc-ecosystem/grpc-gateway/pull/210) ([yugui](https://github.com/yugui))
- Allowing unknown fields to be dropped instead of returning error from… [\#208](https://github.com/grpc-ecosystem/grpc-gateway/pull/208) ([sriniven](https://github.com/sriniven))
- Avoid Internal Server Error on zero-length input for bidi streaming [\#200](https://github.com/grpc-ecosystem/grpc-gateway/pull/200) ([yugui](https://github.com/yugui))
## [v1.1.0](https://grpc-ecosystem.github.io/grpc-gateway/grpc-ecosystem/grpc-gateway/tree/v1.1.0) (2016-07-23)
[Full Changelog](https://grpc-ecosystem.github.io/grpc-gateway/grpc-ecosystem/grpc-gateway/compare/v1.0.0...v1.1.0)
**Implemented enhancements:**
- Support oneof types of fields [\#82](https://github.com/grpc-ecosystem/grpc-gateway/issues/82)
- allow use of jsonpb for marshaling [\#79](https://github.com/grpc-ecosystem/grpc-gateway/issues/79)
**Closed issues:**
- Generating a gRPC stub using Gateway generates a gRPC internal error [\#198](https://github.com/grpc-ecosystem/grpc-gateway/issues/198)
- Build fails with error: use of internal package not allowed [\#197](https://github.com/grpc-ecosystem/grpc-gateway/issues/197)
- google/protobuf/descriptor.proto: File not found. [\#194](https://github.com/grpc-ecosystem/grpc-gateway/issues/194)
- please tag releases [\#189](https://github.com/grpc-ecosystem/grpc-gateway/issues/189)
- Support for path collapsing for embedded structs? [\#187](https://github.com/grpc-ecosystem/grpc-gateway/issues/187)
- \[ACTION Required\] Moving to grpc-ecosystem [\#179](https://github.com/grpc-ecosystem/grpc-gateway/issues/179)
- Ading grpc-timeout support [\#107](https://github.com/grpc-ecosystem/grpc-gateway/issues/107)
- Generation of one swagger file out of multiple protos? [\#99](https://github.com/grpc-ecosystem/grpc-gateway/issues/99)
**Merged pull requests:**
- Rename packages to follow the repository transfer [\#192](https://github.com/grpc-ecosystem/grpc-gateway/pull/192) ([yugui](https://github.com/yugui))
- return err early if EOF to prevent logging in normal conditions [\#191](https://github.com/grpc-ecosystem/grpc-gateway/pull/191) ([tmc](https://github.com/tmc))
- send Trailer header on error [\#188](https://github.com/grpc-ecosystem/grpc-gateway/pull/188) ([kazegusuri](https://github.com/kazegusuri))
- generate swagger output for streaming endpoints with a basic note [\#183](https://github.com/grpc-ecosystem/grpc-gateway/pull/183) ([tmc](https://github.com/tmc))
## [v1.0.0](https://grpc-ecosystem.github.io/grpc-gateway/grpc-ecosystem/grpc-gateway/tree/v1.0.0) (2016-06-15)
**Implemented enhancements:**
- support protobuf-over-HTTP [\#124](https://github.com/grpc-ecosystem/grpc-gateway/issues/124)
- Static mapping from proto field names to golang field names [\#86](https://github.com/grpc-ecosystem/grpc-gateway/issues/86)
- Format Errors to JSON [\#25](https://github.com/grpc-ecosystem/grpc-gateway/issues/25)
- Emit API definition in Swagger schema format [\#9](https://github.com/grpc-ecosystem/grpc-gateway/issues/9)
- Method parameter in query string [\#6](https://github.com/grpc-ecosystem/grpc-gateway/issues/6)
- Integrate authentication [\#4](https://github.com/grpc-ecosystem/grpc-gateway/issues/4)
- Add swagger support [\#68](https://github.com/grpc-ecosystem/grpc-gateway/pull/68) ([achew22](https://github.com/achew22))
- Add runtime.WithForwardResponseOption [\#53](https://github.com/grpc-ecosystem/grpc-gateway/pull/53) ([peter-edge](https://github.com/peter-edge))
**Fixed bugs:**
- recent annotation change requires req.RemoteAddr to be populated [\#177](https://github.com/grpc-ecosystem/grpc-gateway/issues/177)
- Runtime panic with CloseNotify [\#115](https://github.com/grpc-ecosystem/grpc-gateway/issues/115)
- Gateway code generation broken when rpc method with a streaming response has an input paramter [\#35](https://github.com/grpc-ecosystem/grpc-gateway/issues/35)
- URL usage of nested messages causes nil pointer in proto3 [\#32](https://github.com/grpc-ecosystem/grpc-gateway/issues/32)
- Multiple .proto files generates invalid import statements. [\#22](https://github.com/grpc-ecosystem/grpc-gateway/issues/22)
**Closed issues:**
- remote peer address is lost in ctx - always resolves to localhost [\#173](https://github.com/grpc-ecosystem/grpc-gateway/issues/173)
- Bidirectional streams don't concurrently Send and Recv [\#169](https://github.com/grpc-ecosystem/grpc-gateway/issues/169)
- Error: failed to import google/api/annotations.proto [\#165](https://github.com/grpc-ecosystem/grpc-gateway/issues/165)
- Test datarace in controlapi [\#163](https://github.com/grpc-ecosystem/grpc-gateway/issues/163)
- not enough arguments in call to runtime.HTTPError [\#162](https://github.com/grpc-ecosystem/grpc-gateway/issues/162)
- String-values for Enums in request object are not recognized. [\#150](https://github.com/grpc-ecosystem/grpc-gateway/issues/150)
- Handling of import public "file.proto" [\#139](https://github.com/grpc-ecosystem/grpc-gateway/issues/139)
- Does grpc-gateway support http middleware? [\#132](https://github.com/grpc-ecosystem/grpc-gateway/issues/132)
- push to web clients using WS or SSE ? [\#131](https://github.com/grpc-ecosystem/grpc-gateway/issues/131)
- protoc-gen-swagger comment parsing for documentation gen [\#128](https://github.com/grpc-ecosystem/grpc-gateway/issues/128)
- generated code has a data race [\#123](https://github.com/grpc-ecosystem/grpc-gateway/issues/123)
- panic: net/http: CloseNotify called after ServeHTTP finished [\#121](https://github.com/grpc-ecosystem/grpc-gateway/issues/121)
- CloseNotify race with ServeHTTP [\#119](https://github.com/grpc-ecosystem/grpc-gateway/issues/119)
- echo service example does not compile [\#117](https://github.com/grpc-ecosystem/grpc-gateway/issues/117)
- go vet issues in template\_test.go [\#113](https://github.com/grpc-ecosystem/grpc-gateway/issues/113)
- undefined: proto.SizeVarint [\#103](https://github.com/grpc-ecosystem/grpc-gateway/issues/103)
- Closing the HTTP connection does not cancel the Context [\#101](https://github.com/grpc-ecosystem/grpc-gateway/issues/101)
- Logging [\#92](https://github.com/grpc-ecosystem/grpc-gateway/issues/92)
- Missing default values in JSON output? [\#91](https://github.com/grpc-ecosystem/grpc-gateway/issues/91)
- Better grpc error strings [\#87](https://github.com/grpc-ecosystem/grpc-gateway/issues/87)
- Fields aren't named in the same manner as golang/protobuf [\#84](https://github.com/grpc-ecosystem/grpc-gateway/issues/84)
- Header Forwarding from server. [\#73](https://github.com/grpc-ecosystem/grpc-gateway/issues/73)
- No pattern specified in google.api.HttpRule [\#70](https://github.com/grpc-ecosystem/grpc-gateway/issues/70)
- cannot find package "google/api" [\#67](https://github.com/grpc-ecosystem/grpc-gateway/issues/67)
- Generated .pb.go with services no longer works with latest version of grpc-go. [\#62](https://github.com/grpc-ecosystem/grpc-gateway/issues/62)
- JavaScript Proxy [\#61](https://github.com/grpc-ecosystem/grpc-gateway/issues/61)
- Add HTTP error code, error status to responseStreamChunk Error [\#58](https://github.com/grpc-ecosystem/grpc-gateway/issues/58)
- Reverse the code gen idea [\#44](https://github.com/grpc-ecosystem/grpc-gateway/issues/44)
- array of maps in json [\#43](https://github.com/grpc-ecosystem/grpc-gateway/issues/43)
- Examples break with 1.5 because of import of "main" examples package [\#37](https://github.com/grpc-ecosystem/grpc-gateway/issues/37)
- Breaks with 1.5rc1 due to "internal" package name. [\#36](https://github.com/grpc-ecosystem/grpc-gateway/issues/36)
- Feature Request: Support for non-nullable nested messages. [\#20](https://github.com/grpc-ecosystem/grpc-gateway/issues/20)
- Is PascalFromSnake the right conversion to be doing? [\#19](https://github.com/grpc-ecosystem/grpc-gateway/issues/19)
- Infinite loop in generator when package name conflicts [\#17](https://github.com/grpc-ecosystem/grpc-gateway/issues/17)
- google.api.http options in multi-line format not supported [\#16](https://github.com/grpc-ecosystem/grpc-gateway/issues/16)
- Is there any plan to developing a C++ version? [\#15](https://github.com/grpc-ecosystem/grpc-gateway/issues/15)
**Merged pull requests:**
- Regenerate files with the latest protoc-gen-go [\#185](https://github.com/grpc-ecosystem/grpc-gateway/pull/185) ([yugui](https://github.com/yugui))
- Add browser examples [\#184](https://github.com/grpc-ecosystem/grpc-gateway/pull/184) ([yugui](https://github.com/yugui))
- Fix golint and go vet errors [\#182](https://github.com/grpc-ecosystem/grpc-gateway/pull/182) ([yugui](https://github.com/yugui))
- Add integration with clients generated by swagger-codegen [\#181](https://github.com/grpc-ecosystem/grpc-gateway/pull/181) ([yugui](https://github.com/yugui))
- Simplify example services [\#180](https://github.com/grpc-ecosystem/grpc-gateway/pull/180) ([yugui](https://github.com/yugui))
- Avoid errors when req.RemoteAddr is empty [\#178](https://github.com/grpc-ecosystem/grpc-gateway/pull/178) ([yugui](https://github.com/yugui))
- Feature/headers [\#176](https://github.com/grpc-ecosystem/grpc-gateway/pull/176) ([yugui](https://github.com/yugui))
- Include HTTP req.remoteAddr in gRPC ctx [\#174](https://github.com/grpc-ecosystem/grpc-gateway/pull/174) ([mikeatlas](https://github.com/mikeatlas))
- Update dependencies [\#171](https://github.com/grpc-ecosystem/grpc-gateway/pull/171) ([yugui](https://github.com/yugui))
- Add bidirectional streaming support by running Send\(\) and Recv\(\) concurrently [\#170](https://github.com/grpc-ecosystem/grpc-gateway/pull/170) ([tmc](https://github.com/tmc))
- make Authorization header check case-insensitive to comply with RFC 2616 4.2 [\#164](https://github.com/grpc-ecosystem/grpc-gateway/pull/164) ([tmc](https://github.com/tmc))
- jsonpb: avoid duplicating upstream's struct [\#158](https://github.com/grpc-ecosystem/grpc-gateway/pull/158) ([tamird](https://github.com/tamird))
- Generate Swagger description for service methods using proto comments. [\#156](https://github.com/grpc-ecosystem/grpc-gateway/pull/156) ([t-yuki](https://github.com/t-yuki))
- Implement gRPC timeout support for inbound HTTP headers [\#155](https://github.com/grpc-ecosystem/grpc-gateway/pull/155) ([mwitkow](https://github.com/mwitkow))
- Add more examples to marshalers [\#154](https://github.com/grpc-ecosystem/grpc-gateway/pull/154) ([yugui](https://github.com/yugui))
- custom marshaler: handle `Accept` headers correctly [\#152](https://github.com/grpc-ecosystem/grpc-gateway/pull/152) ([tamird](https://github.com/tamird))
- Simplify custom marshaler API [\#151](https://github.com/grpc-ecosystem/grpc-gateway/pull/151) ([yugui](https://github.com/yugui))
- Fix camel case path parameter handling in swagger [\#149](https://github.com/grpc-ecosystem/grpc-gateway/pull/149) ([yugui](https://github.com/yugui))
- Swagger dot in path template [\#148](https://github.com/grpc-ecosystem/grpc-gateway/pull/148) ([yugui](https://github.com/yugui))
- Support map types in swagger generator [\#147](https://github.com/grpc-ecosystem/grpc-gateway/pull/147) ([yugui](https://github.com/yugui))
- Cleanup custom marshaler [\#146](https://github.com/grpc-ecosystem/grpc-gateway/pull/146) ([yugui](https://github.com/yugui))
- Implement custom Marshaler support, add jsonpb implemention. [\#144](https://github.com/grpc-ecosystem/grpc-gateway/pull/144) ([tmc](https://github.com/tmc))
- Allow period in path URL templates when generating Swagger templates. [\#143](https://github.com/grpc-ecosystem/grpc-gateway/pull/143) ([ivucica](https://github.com/ivucica))
- Link to LICENSE.txt [\#142](https://github.com/grpc-ecosystem/grpc-gateway/pull/142) ([sunkuet02](https://github.com/sunkuet02))
- Support map types in swagger generator [\#141](https://github.com/grpc-ecosystem/grpc-gateway/pull/141) ([t-yuki](https://github.com/t-yuki))
- Conditionally stops checking if generated file are up-to-date [\#136](https://github.com/grpc-ecosystem/grpc-gateway/pull/136) ([yugui](https://github.com/yugui))
- Generate Swagger description for service methods using proto comments. [\#134](https://github.com/grpc-ecosystem/grpc-gateway/pull/134) ([ivucica](https://github.com/ivucica))
- Swagger definitions now have `type` set to `object`. [\#133](https://github.com/grpc-ecosystem/grpc-gateway/pull/133) ([ivucica](https://github.com/ivucica))
- go\_package option as go import path [\#129](https://github.com/grpc-ecosystem/grpc-gateway/pull/129) ([kazegusuri](https://github.com/kazegusuri))
- Fix govet errors [\#126](https://github.com/grpc-ecosystem/grpc-gateway/pull/126) ([yugui](https://github.com/yugui))
- Fix data-race in generated codes [\#125](https://github.com/grpc-ecosystem/grpc-gateway/pull/125) ([yugui](https://github.com/yugui))
- Fix \#119 - CloseNotify race with ServeHTTP [\#120](https://github.com/grpc-ecosystem/grpc-gateway/pull/120) ([cuongdo](https://github.com/cuongdo))
- Replace glog with grpclog [\#118](https://github.com/grpc-ecosystem/grpc-gateway/pull/118) ([cuongdo](https://github.com/cuongdo))
- Fix a goroutine-leak in HTTP keep-alive [\#116](https://github.com/grpc-ecosystem/grpc-gateway/pull/116) ([yugui](https://github.com/yugui))
- Fix camel case path parameter handling in swagger [\#114](https://github.com/grpc-ecosystem/grpc-gateway/pull/114) ([t-yuki](https://github.com/t-yuki))
- gofmt -s [\#112](https://github.com/grpc-ecosystem/grpc-gateway/pull/112) ([shawnps](https://github.com/shawnps))
- fix typo [\#111](https://github.com/grpc-ecosystem/grpc-gateway/pull/111) ([shawnps](https://github.com/shawnps))
- fix typo [\#110](https://github.com/grpc-ecosystem/grpc-gateway/pull/110) ([shawnps](https://github.com/shawnps))
- fixes missing swagger operation objects [\#109](https://github.com/grpc-ecosystem/grpc-gateway/pull/109) ([t-yuki](https://github.com/t-yuki))
- Add parser and swagger support for enum, no gengateway yet [\#108](https://github.com/grpc-ecosystem/grpc-gateway/pull/108) ([t-yuki](https://github.com/t-yuki))
- README: add protoc-gen-swagger too [\#105](https://github.com/grpc-ecosystem/grpc-gateway/pull/105) ([philips](https://github.com/philips))
- README: Suggest go get -u by default. [\#104](https://github.com/grpc-ecosystem/grpc-gateway/pull/104) ([shurcooL](https://github.com/shurcooL))
- Cancel context when HTTP connection is closed [\#102](https://github.com/grpc-ecosystem/grpc-gateway/pull/102) ([floridoo](https://github.com/floridoo))
- wait test server up [\#100](https://github.com/grpc-ecosystem/grpc-gateway/pull/100) ([kazegusuri](https://github.com/kazegusuri))
- Fix the swagger section of the README.md [\#98](https://github.com/grpc-ecosystem/grpc-gateway/pull/98) ([naibaf0](https://github.com/naibaf0))
- Add documentation for using Swagger [\#97](https://github.com/grpc-ecosystem/grpc-gateway/pull/97) ([achew22](https://github.com/achew22))
- Better compatibility to field names generated by protoc-gen-go [\#96](https://github.com/grpc-ecosystem/grpc-gateway/pull/96) ([yugui](https://github.com/yugui))
- Update protoc from 3.0.0-beta1 to 3.0.0-beta2 [\#95](https://github.com/grpc-ecosystem/grpc-gateway/pull/95) ([yugui](https://github.com/yugui))
- Better grpc error strings [\#94](https://github.com/grpc-ecosystem/grpc-gateway/pull/94) ([floridoo](https://github.com/floridoo))
- make available header and trailer metadata [\#93](https://github.com/grpc-ecosystem/grpc-gateway/pull/93) ([kazegusuri](https://github.com/kazegusuri))
- make grpc.DialOption configurable [\#89](https://github.com/grpc-ecosystem/grpc-gateway/pull/89) ([kazegusuri](https://github.com/kazegusuri))
- Add request in error handlers [\#88](https://github.com/grpc-ecosystem/grpc-gateway/pull/88) ([daniellowtw](https://github.com/daniellowtw))
- Improve PascalFromSnake behavior [\#85](https://github.com/grpc-ecosystem/grpc-gateway/pull/85) ([tmc](https://github.com/tmc))
- Typo grcp -\> grpc [\#81](https://github.com/grpc-ecosystem/grpc-gateway/pull/81) ([daniellowtw](https://github.com/daniellowtw))
- Add abstraction of code generator implementation [\#78](https://github.com/grpc-ecosystem/grpc-gateway/pull/78) ([yugui](https://github.com/yugui))
- Support multivalue of metadata [\#77](https://github.com/grpc-ecosystem/grpc-gateway/pull/77) ([yugui](https://github.com/yugui))
- Fix broken test [\#76](https://github.com/grpc-ecosystem/grpc-gateway/pull/76) ([yugui](https://github.com/yugui))
- Added missing instruction line in README [\#75](https://github.com/grpc-ecosystem/grpc-gateway/pull/75) ([betrcode](https://github.com/betrcode))
- Fix a complie error in generated go files [\#71](https://github.com/grpc-ecosystem/grpc-gateway/pull/71) ([yugui](https://github.com/yugui))
- Update generated .pb.go files in third\_party [\#69](https://github.com/grpc-ecosystem/grpc-gateway/pull/69) ([peter-edge](https://github.com/peter-edge))
- Bugfix/handling headers for `Authorization` and `Host` [\#65](https://github.com/grpc-ecosystem/grpc-gateway/pull/65) ([mwitkow](https://github.com/mwitkow))
- Fix `error` field always in chunk response [\#64](https://github.com/grpc-ecosystem/grpc-gateway/pull/64) ([mwitkow](https://github.com/mwitkow))
- Update .pb.go to latest version. [\#63](https://github.com/grpc-ecosystem/grpc-gateway/pull/63) ([johansja](https://github.com/johansja))
- Run more tests in Travis CI [\#60](https://github.com/grpc-ecosystem/grpc-gateway/pull/60) ([yugui](https://github.com/yugui))
- Added http error code and error status for responseStreamChunk error [\#59](https://github.com/grpc-ecosystem/grpc-gateway/pull/59) ([kdima](https://github.com/kdima))
- Fix parsing of verb and final path component. [\#55](https://github.com/grpc-ecosystem/grpc-gateway/pull/55) ([hbchai](https://github.com/hbchai))
- add grpc.WithInsecure\(\) as option for grpc.Dial call in template [\#52](https://github.com/grpc-ecosystem/grpc-gateway/pull/52) ([peter-edge](https://github.com/peter-edge))
- update .pb.go files for latest golang proto generation [\#51](https://github.com/grpc-ecosystem/grpc-gateway/pull/51) ([peter-edge](https://github.com/peter-edge))
- Fix a build error with the latest protoc-gen-go [\#50](https://github.com/grpc-ecosystem/grpc-gateway/pull/50) ([yugui](https://github.com/yugui))
- Configure Travis CI [\#49](https://github.com/grpc-ecosystem/grpc-gateway/pull/49) ([yugui](https://github.com/yugui))
- Follow a change of go package name convention in protoc-gen-go [\#48](https://github.com/grpc-ecosystem/grpc-gateway/pull/48) ([yugui](https://github.com/yugui))
- Consider tail segments after deep wildcard [\#47](https://github.com/grpc-ecosystem/grpc-gateway/pull/47) ([yugui](https://github.com/yugui))
- Fix typo in README [\#45](https://github.com/grpc-ecosystem/grpc-gateway/pull/45) ([jonboulle](https://github.com/jonboulle))
- Fix undefined variable error in generated codes [\#42](https://github.com/grpc-ecosystem/grpc-gateway/pull/42) ([yugui](https://github.com/yugui))
- Follow changes in protoc-gen-go and grpc-go [\#41](https://github.com/grpc-ecosystem/grpc-gateway/pull/41) ([yugui](https://github.com/yugui))
- Fixes \#4 [\#40](https://github.com/grpc-ecosystem/grpc-gateway/pull/40) ([AmandaCameron](https://github.com/AmandaCameron))
- fix examples to work with go1.5 [\#39](https://github.com/grpc-ecosystem/grpc-gateway/pull/39) ([tmc](https://github.com/tmc))
- rename internal to utilties for 1.5 compatibility [\#38](https://github.com/grpc-ecosystem/grpc-gateway/pull/38) ([tmc](https://github.com/tmc))
- Reflection fix of proto3 nested messages. [\#34](https://github.com/grpc-ecosystem/grpc-gateway/pull/34) ([mwitkow](https://github.com/mwitkow))
- \[Experimental\] Make the response forwarder function customizable [\#31](https://github.com/grpc-ecosystem/grpc-gateway/pull/31) ([yugui](https://github.com/yugui))
- Add f.Flush\(\) to runtime.ForwardResponseStream [\#30](https://github.com/grpc-ecosystem/grpc-gateway/pull/30) ([vvakame](https://github.com/vvakame))
- Format error message in JSON [\#29](https://github.com/grpc-ecosystem/grpc-gateway/pull/29) ([yugui](https://github.com/yugui))
- Update examples with HTTP header context annotation [\#28](https://github.com/grpc-ecosystem/grpc-gateway/pull/28) ([yugui](https://github.com/yugui))
- Report semantic errors in the source to protoc [\#27](https://github.com/grpc-ecosystem/grpc-gateway/pull/27) ([yugui](https://github.com/yugui))
- Add support for non-nullable nested messages. [\#21](https://github.com/grpc-ecosystem/grpc-gateway/pull/21) ([shurcooL](https://github.com/shurcooL))
- Receive GRPC metadata from HTTP headers. [\#18](https://github.com/grpc-ecosystem/grpc-gateway/pull/18) ([crast](https://github.com/crast))
- Implement detailed specs of google.api.http [\#14](https://github.com/grpc-ecosystem/grpc-gateway/pull/14) ([yugui](https://github.com/yugui))
- Configure travis CI [\#13](https://github.com/grpc-ecosystem/grpc-gateway/pull/13) ([yugui](https://github.com/yugui))
- Replace our own custom option with the one defined by Google [\#12](https://github.com/grpc-ecosystem/grpc-gateway/pull/12) ([yugui](https://github.com/yugui))
- Remove useless context setup [\#11](https://github.com/grpc-ecosystem/grpc-gateway/pull/11) ([iamqizhao](https://github.com/iamqizhao))
- Fix typo, path, missing semicolon. [\#10](https://github.com/grpc-ecosystem/grpc-gateway/pull/10) ([shurcooL](https://github.com/shurcooL))
- Use a globally unique id for the custom option [\#3](https://github.com/grpc-ecosystem/grpc-gateway/pull/3) ([yugui](https://github.com/yugui))
- implement ABitOfEverythingService [\#2](https://github.com/grpc-ecosystem/grpc-gateway/pull/2) ([mattn](https://github.com/mattn))
- support streaming API calls [\#1](https://github.com/grpc-ecosystem/grpc-gateway/pull/1) ([yugui](https://github.com/yugui))
\* *This Change Log was automatically generated by [github_changelog_generator](https://github.com/skywinder/Github-Changelog-Generator)*

View file

@ -0,0 +1,20 @@
# How to contribute
Thank you for your contribution to grpc-gateway.
Here's the recommended process of contribution.
1. `go get github.com/grpc-ecosystem/grpc-gateway/protoc-gen-grpc-gateway`
2. `cd $GOPATH/src/github.com/grpc-ecosystem/grpc-gateway`
3. hack, hack, hack...
4. Make sure that your change follows best practices in Go
* [Effective Go](https://golang.org/doc/effective_go.html)
* [Go Code Review Comments](https://golang.org/wiki/CodeReviewComments)
5. Make sure that `make test` passes. (use swagger-codegen 2.2.2, not newer versions)
6. Sign [a Contributor License Agreement](https://cla.developers.google.com/clas)
7. Open a pull request in Github
When you work on a larger contribution, it is also recommended that you get in touch
with us through the issue tracker.
### Code reviews
All submissions, including submissions by project members, require review.

View file

@ -0,0 +1,41 @@
# Please follow the general troubleshooting steps first:
- [ ] Update your protoc to the [latest version](https://github.com/google/protobuf/releases)
- [ ] Update your copy of `grpc-gateway` to the latest version from github. with
`git fetch https://github.com/grpc-ecosystem/grpc-gateway master && git reset --hard FETCH_HEAD`
- [ ] Delete the `protoc-gen-grpc-gateway` and `protoc-gen-swagger` binary from your `PATH`,
and install locally built binaries.
### Bug reports:
Fill in the following sections with explanations of what's gone wrong.
Steps you follow to reproduce the error:
<!-- Example steps
1. I grab my catapult
2. I load it with lettuce
3. Press the fire button
4. It falls over
-->
Your steps here.
What did you expect to happen instead:
<!-- Example answer
1. It would have rained lettuce from the sky bringing forth a cuddly army of bunnies we could
play with
-->
Your answer here.
What's your theory on why it isn't working:
<!-- Example answer
Evil wizards are hoarding the bunnies and don't want to share. The wizards are casting
lettuce protection spells so the cattapult won't work.
-->
Your theory here.

View file

@ -0,0 +1,27 @@
Copyright (c) 2015, Gengo, Inc.
All rights reserved.
Redistribution and use in source and binary forms, with or without modification,
are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright notice,
this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
* Neither the name of Gengo, Inc. nor the names of its
contributors may be used to endorse or promote products derived from this
software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

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