Update c/image from the main branch

> go get github.com/containers/image/v5@main
> make vendor

Signed-off-by: Miloslav Trmač <mitr@redhat.com>
This commit is contained in:
Miloslav Trmač
2023-04-01 12:19:48 +02:00
parent 4f475bd4d2
commit bfe82593c8
285 changed files with 21881 additions and 4003 deletions

View File

@@ -2,7 +2,6 @@ package client
import (
"io"
"io/ioutil"
"net/http"
"sync/atomic"
)
@@ -50,7 +49,7 @@ func (d *drainingReadCloser) Close() error {
// some bytes, but the closer ignores them to keep the underling
// connection open.
//nolint:errcheck
io.Copy(ioutil.Discard, d.rdr)
io.Copy(io.Discard, d.rdr)
}
return d.rdr.Close()
}

View File

@@ -0,0 +1,207 @@
package client
import (
"fmt"
"net/http"
"strings"
"github.com/go-openapi/runtime"
"github.com/go-openapi/strfmt"
"go.opentelemetry.io/otel"
"go.opentelemetry.io/otel/attribute"
"go.opentelemetry.io/otel/codes"
"go.opentelemetry.io/otel/propagation"
semconv "go.opentelemetry.io/otel/semconv/v1.12.0"
"go.opentelemetry.io/otel/trace"
)
const (
instrumentationVersion = "1.0.0"
tracerName = "go-openapi"
)
type config struct {
Tracer trace.Tracer
Propagator propagation.TextMapPropagator
SpanStartOptions []trace.SpanStartOption
SpanNameFormatter func(*runtime.ClientOperation) string
TracerProvider trace.TracerProvider
}
type OpenTelemetryOpt interface {
apply(*config)
}
type optionFunc func(*config)
func (o optionFunc) apply(c *config) {
o(c)
}
// WithTracerProvider specifies a tracer provider to use for creating a tracer.
// If none is specified, the global provider is used.
func WithTracerProvider(provider trace.TracerProvider) OpenTelemetryOpt {
return optionFunc(func(c *config) {
if provider != nil {
c.TracerProvider = provider
}
})
}
// WithPropagators configures specific propagators. If this
// option isn't specified, then the global TextMapPropagator is used.
func WithPropagators(ps propagation.TextMapPropagator) OpenTelemetryOpt {
return optionFunc(func(c *config) {
if ps != nil {
c.Propagator = ps
}
})
}
// WithSpanOptions configures an additional set of
// trace.SpanOptions, which are applied to each new span.
func WithSpanOptions(opts ...trace.SpanStartOption) OpenTelemetryOpt {
return optionFunc(func(c *config) {
c.SpanStartOptions = append(c.SpanStartOptions, opts...)
})
}
// WithSpanNameFormatter takes a function that will be called on every
// request and the returned string will become the Span Name.
func WithSpanNameFormatter(f func(op *runtime.ClientOperation) string) OpenTelemetryOpt {
return optionFunc(func(c *config) {
c.SpanNameFormatter = f
})
}
func defaultTransportFormatter(op *runtime.ClientOperation) string {
if op.ID != "" {
return op.ID
}
return fmt.Sprintf("%s_%s", strings.ToLower(op.Method), op.PathPattern)
}
type openTelemetryTransport struct {
transport runtime.ClientTransport
host string
tracer trace.Tracer
config *config
}
func newOpenTelemetryTransport(transport runtime.ClientTransport, host string, opts []OpenTelemetryOpt) *openTelemetryTransport {
tr := &openTelemetryTransport{
transport: transport,
host: host,
}
defaultOpts := []OpenTelemetryOpt{
WithSpanOptions(trace.WithSpanKind(trace.SpanKindClient)),
WithSpanNameFormatter(defaultTransportFormatter),
WithPropagators(otel.GetTextMapPropagator()),
WithTracerProvider(otel.GetTracerProvider()),
}
c := newConfig(append(defaultOpts, opts...)...)
tr.config = c
return tr
}
func (t *openTelemetryTransport) Submit(op *runtime.ClientOperation) (interface{}, error) {
if op.Context == nil {
return t.transport.Submit(op)
}
params := op.Params
reader := op.Reader
var span trace.Span
defer func() {
if span != nil {
span.End()
}
}()
op.Params = runtime.ClientRequestWriterFunc(func(req runtime.ClientRequest, reg strfmt.Registry) error {
span = t.newOpenTelemetrySpan(op, req.GetHeaderParams())
return params.WriteToRequest(req, reg)
})
op.Reader = runtime.ClientResponseReaderFunc(func(response runtime.ClientResponse, consumer runtime.Consumer) (interface{}, error) {
if span != nil {
statusCode := response.Code()
span.SetAttributes(attribute.Int(string(semconv.HTTPStatusCodeKey), statusCode))
span.SetStatus(semconv.SpanStatusFromHTTPStatusCodeAndSpanKind(statusCode, trace.SpanKindClient))
}
return reader.ReadResponse(response, consumer)
})
submit, err := t.transport.Submit(op)
if err != nil && span != nil {
span.RecordError(err)
span.SetStatus(codes.Error, err.Error())
}
return submit, err
}
func (t *openTelemetryTransport) newOpenTelemetrySpan(op *runtime.ClientOperation, header http.Header) trace.Span {
ctx := op.Context
tracer := t.tracer
if tracer == nil {
if span := trace.SpanFromContext(ctx); span.SpanContext().IsValid() {
tracer = newTracer(span.TracerProvider())
} else {
tracer = newTracer(otel.GetTracerProvider())
}
}
ctx, span := tracer.Start(ctx, t.config.SpanNameFormatter(op), t.config.SpanStartOptions...)
var scheme string
if len(op.Schemes) > 0 {
scheme = op.Schemes[0]
}
span.SetAttributes(
attribute.String("net.peer.name", t.host),
attribute.String(string(semconv.HTTPRouteKey), op.PathPattern),
attribute.String(string(semconv.HTTPMethodKey), op.Method),
attribute.String("span.kind", trace.SpanKindClient.String()),
attribute.String("http.scheme", scheme),
)
carrier := propagation.HeaderCarrier(header)
t.config.Propagator.Inject(ctx, carrier)
return span
}
func newTracer(tp trace.TracerProvider) trace.Tracer {
return tp.Tracer(tracerName, trace.WithInstrumentationVersion(version()))
}
func newConfig(opts ...OpenTelemetryOpt) *config {
c := &config{
Propagator: otel.GetTextMapPropagator(),
}
for _, opt := range opts {
opt.apply(c)
}
// Tracer is only initialized if manually specified. Otherwise, can be passed with the tracing context.
if c.TracerProvider != nil {
c.Tracer = newTracer(c.TracerProvider)
}
return c
}
// Version is the current release version of the go-runtime instrumentation.
func version() string {
return instrumentationVersion
}

View File

@@ -23,6 +23,8 @@ import (
var _ runtime.ClientResponse = response{}
func newResponse(resp *http.Response) runtime.ClientResponse { return response{resp: resp} }
type response struct {
resp *http.Response
}

View File

@@ -23,21 +23,21 @@ import (
"crypto/x509"
"encoding/pem"
"fmt"
"io/ioutil"
"mime"
"net/http"
"net/http/httputil"
"os"
"strings"
"sync"
"time"
"github.com/go-openapi/strfmt"
"github.com/opentracing/opentracing-go"
"github.com/go-openapi/runtime"
"github.com/go-openapi/runtime/logger"
"github.com/go-openapi/runtime/middleware"
"github.com/go-openapi/runtime/yamlpc"
"github.com/go-openapi/strfmt"
)
// TLSClientOptions to configure client authentication with mutual TLS
@@ -164,7 +164,7 @@ func TLSClientAuth(opts TLSClientOptions) (*tls.Config, error) {
cfg.RootCAs = caCertPool
} else if opts.CA != "" {
// load ca cert
caCert, err := ioutil.ReadFile(opts.CA)
caCert, err := os.ReadFile(opts.CA)
if err != nil {
return nil, fmt.Errorf("tls client ca: %v", err)
}
@@ -181,8 +181,6 @@ func TLSClientAuth(opts TLSClientOptions) (*tls.Config, error) {
cfg.ServerName = opts.ServerName
}
cfg.BuildNameToCertificate()
return cfg, nil
}
@@ -225,7 +223,7 @@ type Runtime struct {
Transport http.RoundTripper
Jar http.CookieJar
//Spec *spec.Document
// Spec *spec.Document
Host string
BasePath string
Formats strfmt.Registry
@@ -237,6 +235,7 @@ type Runtime struct {
clientOnce *sync.Once
client *http.Client
schemes []string
response ClientResponseFunc
}
// New creates a new default runtime for a swagger api runtime.Client
@@ -275,6 +274,7 @@ func New(host, basePath string, schemes []string) *Runtime {
rt.Debug = logger.DebugEnabled()
rt.logger = logger.StandardLogger{}
rt.response = newResponse
if len(schemes) > 0 {
rt.schemes = schemes
@@ -301,6 +301,14 @@ func (r *Runtime) WithOpenTracing(opts ...opentracing.StartSpanOption) runtime.C
return newOpenTracingTransport(r, r.Host, opts)
}
// WithOpenTelemetry adds opentelemetry support to the provided runtime.
// A new client span is created for each request.
// If the context of the client operation does not contain an active span, no span is created.
// The provided opts are applied to each spans - for example to add global tags.
func (r *Runtime) WithOpenTelemetry(opts ...OpenTelemetryOpt) runtime.ClientTransport {
return newOpenTelemetryTransport(r, r.Host, opts)
}
func (r *Runtime) pickScheme(schemes []string) string {
if v := r.selectScheme(r.schemes); v != "" {
return v
@@ -329,6 +337,7 @@ func (r *Runtime) selectScheme(schemes []string) string {
}
return scheme
}
func transportOrDefault(left, right http.RoundTripper) http.RoundTripper {
if left == nil {
return right
@@ -381,7 +390,7 @@ func (r *Runtime) createHttpRequest(operation *runtime.ClientOperation) (*reques
return r.DefaultAuthentication.AuthenticateRequest(req, reg)
})
}
//if auth != nil {
// if auth != nil {
// if err := auth.AuthenticateRequest(request, r.Formats); err != nil {
// return nil, err
// }
@@ -500,7 +509,7 @@ func (r *Runtime) Submit(operation *runtime.ClientOperation) (interface{}, error
return nil, fmt.Errorf("no consumer: %q", ct)
}
}
return readResponse.ReadResponse(response{res}, cons)
return readResponse.ReadResponse(r.response(res), cons)
}
// SetDebug changes the debug flag.
@@ -516,3 +525,13 @@ func (r *Runtime) SetLogger(logger logger.Logger) {
r.logger = logger
middleware.Logger = logger
}
type ClientResponseFunc = func(*http.Response) runtime.ClientResponse
// SetResponseReader changes the response reader implementation.
func (r *Runtime) SetResponseReader(f ClientResponseFunc) {
if f == nil {
return
}
r.response = f
}

View File

@@ -16,7 +16,6 @@ package runtime
import (
"io"
"io/ioutil"
"net/http"
"net/url"
"time"
@@ -79,7 +78,7 @@ type NamedReadCloser interface {
func NamedReader(name string, rdr io.Reader) NamedReadCloser {
rc, ok := rdr.(io.ReadCloser)
if !ok {
rc = ioutil.NopCloser(rdr)
rc = io.NopCloser(rdr)
}
return &namedReadCloser{
name: name,

View File

@@ -195,6 +195,17 @@ func NewRoutableContext(spec *loads.Document, routableAPI RoutableAPI, routes Ro
if spec != nil {
an = analysis.New(spec.Spec())
}
return NewRoutableContextWithAnalyzedSpec(spec, an, routableAPI, routes)
}
// NewRoutableContextWithAnalyzedSpec is like NewRoutableContext but takes in input the analysed spec too
func NewRoutableContextWithAnalyzedSpec(spec *loads.Document, an *analysis.Spec, routableAPI RoutableAPI, routes Router) *Context {
// Either there are no spec doc and analysis, or both of them.
if !((spec == nil && an == nil) || (spec != nil && an != nil)) {
panic(errors.New(http.StatusInternalServerError, "routable context requires either both spec doc and analysis, or none of them"))
}
ctx := &Context{spec: spec, api: routableAPI, analyzer: an, router: routes}
return ctx
}
@@ -498,7 +509,9 @@ func (c *Context) Respond(rw http.ResponseWriter, r *http.Request, produces []st
if resp, ok := data.(Responder); ok {
producers := route.Producers
prod, ok := producers[format]
// producers contains keys with normalized format, if a format has MIME type parameter such as `text/plain; charset=utf-8`
// then you must provide `text/plain` to get the correct producer. HOWEVER, format here is not normalized.
prod, ok := producers[normalizeOffer(format)]
if !ok {
prods := c.api.ProducersFor(normalizeOffers([]string{c.api.DefaultProduces()}))
pr, ok := prods[c.api.DefaultProduces()]

View File

@@ -206,7 +206,11 @@ func (p *untypedParamBinder) Bind(request *http.Request, routeParams RouteParams
if p.parameter.Type == "file" {
file, header, ffErr := request.FormFile(p.parameter.Name)
if ffErr != nil {
return errors.NewParseError(p.Name, p.parameter.In, "", ffErr)
if p.parameter.Required {
return errors.NewParseError(p.Name, p.parameter.In, "", ffErr)
} else {
return nil
}
}
target.Set(reflect.ValueOf(runtime.File{Data: file, Header: header}))
return nil

View File

@@ -16,6 +16,8 @@ type SwaggerUIOpts struct {
Path string
// SpecURL the url to find the spec for
SpecURL string
// OAuthCallbackURL the url called after OAuth2 login
OAuthCallbackURL string
// The three components needed to embed swagger-ui
SwaggerURL string
@@ -40,6 +42,9 @@ func (r *SwaggerUIOpts) EnsureDefaults() {
if r.SpecURL == "" {
r.SpecURL = "/swagger.json"
}
if r.OAuthCallbackURL == "" {
r.OAuthCallbackURL = path.Join(r.BasePath, r.Path, "oauth2-callback")
}
if r.SwaggerURL == "" {
r.SwaggerURL = swaggerLatest
}
@@ -149,7 +154,8 @@ const (
plugins: [
SwaggerUIBundle.plugins.DownloadUrl
],
layout: "StandaloneLayout"
layout: "StandaloneLayout",
oauth2RedirectUrl: '{{ .OAuthCallbackURL }}'
})
// End Swagger UI call region

View File

@@ -0,0 +1,122 @@
package middleware
import (
"bytes"
"fmt"
"net/http"
"path"
"text/template"
)
func SwaggerUIOAuth2Callback(opts SwaggerUIOpts, next http.Handler) http.Handler {
opts.EnsureDefaults()
pth := opts.OAuthCallbackURL
tmpl := template.Must(template.New("swaggeroauth").Parse(swaggerOAuthTemplate))
buf := bytes.NewBuffer(nil)
_ = tmpl.Execute(buf, &opts)
b := buf.Bytes()
return http.HandlerFunc(func(rw http.ResponseWriter, r *http.Request) {
if path.Join(r.URL.Path) == pth {
rw.Header().Set("Content-Type", "text/html; charset=utf-8")
rw.WriteHeader(http.StatusOK)
_, _ = rw.Write(b)
return
}
if next == nil {
rw.Header().Set("Content-Type", "text/plain")
rw.WriteHeader(http.StatusNotFound)
_, _ = rw.Write([]byte(fmt.Sprintf("%q not found", pth)))
return
}
next.ServeHTTP(rw, r)
})
}
const (
swaggerOAuthTemplate = `
<!DOCTYPE html>
<html lang="en">
<head>
<title>{{ .Title }}</title>
</head>
<body>
<script>
'use strict';
function run () {
var oauth2 = window.opener.swaggerUIRedirectOauth2;
var sentState = oauth2.state;
var redirectUrl = oauth2.redirectUrl;
var isValid, qp, arr;
if (/code|token|error/.test(window.location.hash)) {
qp = window.location.hash.substring(1).replace('?', '&');
} else {
qp = location.search.substring(1);
}
arr = qp.split("&");
arr.forEach(function (v,i,_arr) { _arr[i] = '"' + v.replace('=', '":"') + '"';});
qp = qp ? JSON.parse('{' + arr.join() + '}',
function (key, value) {
return key === "" ? value : decodeURIComponent(value);
}
) : {};
isValid = qp.state === sentState;
if ((
oauth2.auth.schema.get("flow") === "accessCode" ||
oauth2.auth.schema.get("flow") === "authorizationCode" ||
oauth2.auth.schema.get("flow") === "authorization_code"
) && !oauth2.auth.code) {
if (!isValid) {
oauth2.errCb({
authId: oauth2.auth.name,
source: "auth",
level: "warning",
message: "Authorization may be unsafe, passed state was changed in server. The passed state wasn't returned from auth server."
});
}
if (qp.code) {
delete oauth2.state;
oauth2.auth.code = qp.code;
oauth2.callback({auth: oauth2.auth, redirectUrl: redirectUrl});
} else {
let oauthErrorMsg;
if (qp.error) {
oauthErrorMsg = "["+qp.error+"]: " +
(qp.error_description ? qp.error_description+ ". " : "no accessCode received from the server. ") +
(qp.error_uri ? "More info: "+qp.error_uri : "");
}
oauth2.errCb({
authId: oauth2.auth.name,
source: "auth",
level: "error",
message: oauthErrorMsg || "[Authorization failed]: no accessCode received from the server."
});
}
} else {
oauth2.callback({auth: oauth2.auth, token: qp, isValid: isValid, redirectUrl: redirectUrl});
}
window.close();
}
if (document.readyState !== 'loading') {
run();
} else {
document.addEventListener('DOMContentLoaded', function () {
run();
});
}
</script>
</body>
</html>
`
)

View File

@@ -14,31 +14,40 @@ linters-settings:
min-occurrences: 4
linters:
enable-all: true
disable:
- maligned
- lll
- gochecknoinits
- gochecknoglobals
- godox
- gocognit
- whitespace
- wsl
- funlen
- wrapcheck
- testpackage
- nlreturn
- gofumpt
- goerr113
- gci
- gomnd
- godot
- exhaustivestruct
- paralleltest
- varnamelen
- ireturn
- exhaustruct
#- thelper
enable:
- revive
- goimports
- gosec
- unparam
- unconvert
- predeclared
- prealloc
- misspell
# disable:
# - maligned
# - lll
# - gochecknoinits
# - gochecknoglobals
# - godox
# - gocognit
# - whitespace
# - wsl
# - funlen
# - wrapcheck
# - testpackage
# - nlreturn
# - gofumpt
# - goerr113
# - gci
# - gomnd
# - godot
# - exhaustivestruct
# - paralleltest
# - varnamelen
# - ireturn
# - exhaustruct
# #- thelper
issues:
exclude-rules:

View File

@@ -142,7 +142,7 @@ func (id ObjectId) MarshalBSONValue() (bsontype.Type, []byte, error) {
// BSON value representation of themselves. The BSON bytes and type can be
// assumed to be valid. UnmarshalBSONValue must copy the BSON value bytes if it
// wishes to retain the data after returning.
func (id *ObjectId) UnmarshalBSONValue(tpe bsontype.Type, data []byte) error {
func (id *ObjectId) UnmarshalBSONValue(_ bsontype.Type, data []byte) error {
var oid bsonprim.ObjectID
copy(oid[:], data)
*id = ObjectId(oid)

View File

@@ -57,7 +57,7 @@ func (d *Date) UnmarshalText(text []byte) error {
if len(text) == 0 {
return nil
}
dd, err := time.Parse(RFC3339FullDate, string(text))
dd, err := time.ParseInLocation(RFC3339FullDate, string(text), DefaultTimeLocation)
if err != nil {
return err
}
@@ -107,7 +107,7 @@ func (d *Date) UnmarshalJSON(data []byte) error {
if err := json.Unmarshal(data, &strdate); err != nil {
return err
}
tt, err := time.Parse(RFC3339FullDate, strdate)
tt, err := time.ParseInLocation(RFC3339FullDate, strdate, DefaultTimeLocation)
if err != nil {
return err
}
@@ -126,7 +126,7 @@ func (d *Date) UnmarshalBSON(data []byte) error {
}
if data, ok := m["data"].(string); ok {
rd, err := time.Parse(RFC3339FullDate, data)
rd, err := time.ParseInLocation(RFC3339FullDate, data, DefaultTimeLocation)
if err != nil {
return err
}

View File

@@ -109,7 +109,7 @@ func (f *defaultFormats) MapStructureHookFunc() mapstructure.DecodeHookFunc { //
if to == tpe {
switch v.Name {
case "date":
d, err := time.Parse(RFC3339FullDate, data)
d, err := time.ParseInLocation(RFC3339FullDate, data, DefaultTimeLocation)
if err != nil {
return nil, err
}

View File

@@ -29,6 +29,12 @@ import (
"go.mongodb.org/mongo-driver/bson/bsontype"
)
var (
// UnixZero sets the zero unix timestamp we want to compare against.
// Unix 0 for an EST timezone is not equivalent to a UTC timezone.
UnixZero = time.Unix(0, 0).UTC()
)
func init() {
dt := DateTime{}
Default.Add("datetime", &dt, IsDateTime)
@@ -86,6 +92,9 @@ var (
// NormalizeTimeForMarshal provides a normalization function on time befeore marshalling (e.g. time.UTC).
// By default, the time value is not changed.
NormalizeTimeForMarshal = func(t time.Time) time.Time { return t }
// DefaultTimeLocation provides a location for a time when the time zone is not encoded in the string (ex: ISO8601 Local variants).
DefaultTimeLocation = time.UTC
)
// ParseDateTime parses a string that represents an ISO8601 time or a unix epoch
@@ -95,7 +104,7 @@ func ParseDateTime(data string) (DateTime, error) {
}
var lastError error
for _, layout := range DateTimeFormats {
dd, err := time.Parse(layout, data)
dd, err := time.ParseInLocation(layout, data, DefaultTimeLocation)
if err != nil {
lastError = err
continue
@@ -123,6 +132,22 @@ func (t DateTime) String() string {
return NormalizeTimeForMarshal(time.Time(t)).Format(MarshalFormat)
}
// IsZero returns whether the date time is a zero value
func (t *DateTime) IsZero() bool {
if t == nil {
return true
}
return time.Time(*t).IsZero()
}
// IsUnixZerom returns whether the date time is equivalent to time.Unix(0, 0).UTC().
func (t *DateTime) IsUnixZero() bool {
if t == nil {
return true
}
return time.Time(*t).Equal(UnixZero)
}
// MarshalText implements the text marshaller interface
func (t DateTime) MarshalText() ([]byte, error) {
return []byte(t.String()), nil

View File

@@ -15,9 +15,12 @@ import (
// ULID represents a ulid string format
// ref:
// https://github.com/ulid/spec
//
// https://github.com/ulid/spec
//
// impl:
// https://github.com/oklog/ulid
//
// https://github.com/oklog/ulid
//
// swagger:strfmt ulid
type ULID struct {
@@ -89,7 +92,9 @@ func NewULIDZero() ULID {
}
// NewULID generates new unique ULID value and a error if any
func NewULID() (u ULID, err error) {
func NewULID() (ULID, error) {
var u ULID
obj := ulidEntropyPool.Get()
entropy, ok := obj.(io.Reader)
if !ok {

View File

@@ -248,7 +248,7 @@ func MinimumUint(path, in string, data, min uint64, exclusive bool) *errors.Vali
// MultipleOf validates if the provided number is a multiple of the factor
func MultipleOf(path, in string, data, factor float64) *errors.Validation {
// multipleOf factor must be positive
if factor < 0 {
if factor <= 0 {
return errors.MultipleOfMustBePositive(path, in, factor)
}
var mult float64
@@ -266,7 +266,7 @@ func MultipleOf(path, in string, data, factor float64) *errors.Validation {
// MultipleOfInt validates if the provided integer is a multiple of the factor
func MultipleOfInt(path, in string, data int64, factor int64) *errors.Validation {
// multipleOf factor must be positive
if factor < 0 {
if factor <= 0 {
return errors.MultipleOfMustBePositive(path, in, factor)
}
mult := data / factor
@@ -278,6 +278,10 @@ func MultipleOfInt(path, in string, data int64, factor int64) *errors.Validation
// MultipleOfUint validates if the provided unsigned integer is a multiple of the factor
func MultipleOfUint(path, in string, data, factor uint64) *errors.Validation {
// multipleOf factor must be positive
if factor == 0 {
return errors.MultipleOfMustBePositive(path, in, factor)
}
mult := data / factor
if mult*factor != data {
return errors.NotMultipleOf(path, in, factor, data)