auth: OpenID/OAUth2 middleware
2 configurations for the listeners are now possible: - enableJWT=false with client ssl auth - enableJWT=true with https Actual verification of the tokens is handled by https://github.com/openshift-online/ocm-sdk-go. An authentication handler is run as the top level handler, before any routing is done. Routes which do not require authentication should be listed as exceptions. Authentication can be restricted using an ACL file which allows filtering based on JWT claims. For more information see the inline comments in ocm-sdk/authentication. As an added quirk the `-v` flag for the osbuild-composer executable was changed to `-verbose` to avoid flag collision with glog which declares the `-v` flag in the package `init()` function. The ocm-sdk depends on glog and pulls it in.
This commit is contained in:
parent
58613788bc
commit
4a057bf3d5
192 changed files with 25042 additions and 110 deletions
177
vendor/github.com/openshift-online/ocm-sdk-go/LICENSE.txt
generated
vendored
Normal file
177
vendor/github.com/openshift-online/ocm-sdk-go/LICENSE.txt
generated
vendored
Normal file
|
|
@ -0,0 +1,177 @@
|
|||
|
||||
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
|
||||
67
vendor/github.com/openshift-online/ocm-sdk-go/authentication/context.go
generated
vendored
Normal file
67
vendor/github.com/openshift-online/ocm-sdk-go/authentication/context.go
generated
vendored
Normal file
|
|
@ -0,0 +1,67 @@
|
|||
/*
|
||||
Copyright (c) 2019 Red Hat, Inc.
|
||||
|
||||
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.
|
||||
*/
|
||||
|
||||
// This file contains functions that extract information from the context.
|
||||
|
||||
package authentication
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
|
||||
"github.com/dgrijalva/jwt-go"
|
||||
)
|
||||
|
||||
// ContextWithToken creates a new context containing the given token.
|
||||
func ContextWithToken(parent context.Context, token *jwt.Token) context.Context {
|
||||
return context.WithValue(parent, tokenKeyValue, token)
|
||||
}
|
||||
|
||||
// TokenFromContext extracts the JSON web token of the user from the context. If no token is found
|
||||
// in the context then the result will be nil.
|
||||
func TokenFromContext(ctx context.Context) (result *jwt.Token, err error) {
|
||||
switch token := ctx.Value(tokenKeyValue).(type) {
|
||||
case nil:
|
||||
case *jwt.Token:
|
||||
result = token
|
||||
default:
|
||||
err = fmt.Errorf(
|
||||
"expected a token in the '%s' context value, but got '%T'",
|
||||
tokenKeyValue, token,
|
||||
)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// BearerFromContext extracts the bearer token of the user from the context. If no user is found in
|
||||
// the context then the result will be the empty string.
|
||||
func BearerFromContext(ctx context.Context) (result string, err error) {
|
||||
token, err := TokenFromContext(ctx)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
if token == nil {
|
||||
return
|
||||
}
|
||||
result = token.Raw
|
||||
return
|
||||
}
|
||||
|
||||
// tokenKeyType is the type of the key used to store the token in the context.
|
||||
type tokenKeyType string
|
||||
|
||||
// tokenKeyValue is the key used to store the token in the context:
|
||||
const tokenKeyValue tokenKeyType = "token"
|
||||
1011
vendor/github.com/openshift-online/ocm-sdk-go/authentication/handler.go
generated
vendored
Normal file
1011
vendor/github.com/openshift-online/ocm-sdk-go/authentication/handler.go
generated
vendored
Normal file
File diff suppressed because it is too large
Load diff
57
vendor/github.com/openshift-online/ocm-sdk-go/authentication/helpers.go
generated
vendored
Normal file
57
vendor/github.com/openshift-online/ocm-sdk-go/authentication/helpers.go
generated
vendored
Normal file
|
|
@ -0,0 +1,57 @@
|
|||
/*
|
||||
Copyright (c) 2021 Red Hat, Inc.
|
||||
|
||||
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.
|
||||
*/
|
||||
|
||||
// This file contains helper functions used in several places in the package.
|
||||
|
||||
package authentication
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
"github.com/dgrijalva/jwt-go"
|
||||
)
|
||||
|
||||
// tokenRemaining determines if the given token will eventually expire (offile access tokens, for
|
||||
// example, never expire) and the time till it expires. That time will be positive if the token
|
||||
// isn't expired, and negative if the token has already expired.
|
||||
//
|
||||
// For tokens that don't have the `exp` claim, or that have it with value zero (typical for offline
|
||||
// access tokens) the result will always be `false` and zero.
|
||||
func tokenRemaining(token *jwt.Token, now time.Time) (expires bool, duration time.Duration,
|
||||
err error) {
|
||||
claims, ok := token.Claims.(jwt.MapClaims)
|
||||
if !ok {
|
||||
err = fmt.Errorf("expected map claims but got %T", claims)
|
||||
return
|
||||
}
|
||||
var exp float64
|
||||
claim, ok := claims["exp"]
|
||||
if !ok {
|
||||
return
|
||||
}
|
||||
exp, ok = claim.(float64)
|
||||
if !ok {
|
||||
err = fmt.Errorf("expected floating point 'exp' but got %T", claim)
|
||||
return
|
||||
}
|
||||
if exp == 0 {
|
||||
return
|
||||
}
|
||||
duration = time.Unix(int64(exp), 0).Sub(now)
|
||||
expires = true
|
||||
return
|
||||
}
|
||||
1013
vendor/github.com/openshift-online/ocm-sdk-go/authentication/transport_wrapper.go
generated
vendored
Normal file
1013
vendor/github.com/openshift-online/ocm-sdk-go/authentication/transport_wrapper.go
generated
vendored
Normal file
File diff suppressed because it is too large
Load diff
416
vendor/github.com/openshift-online/ocm-sdk-go/errors/errors.go
generated
vendored
Normal file
416
vendor/github.com/openshift-online/ocm-sdk-go/errors/errors.go
generated
vendored
Normal file
|
|
@ -0,0 +1,416 @@
|
|||
/*
|
||||
Copyright (c) 2020 Red Hat, Inc.
|
||||
|
||||
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.
|
||||
*/
|
||||
|
||||
// IMPORTANT: This file has been generated automatically, refrain from modifying it manually as all
|
||||
// your changes will be lost when the file is generated again.
|
||||
|
||||
package errors // github.com/openshift-online/ocm-sdk-go/errors
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io"
|
||||
"net/http"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"github.com/golang/glog"
|
||||
jsoniter "github.com/json-iterator/go"
|
||||
"github.com/openshift-online/ocm-sdk-go/helpers"
|
||||
)
|
||||
|
||||
// Error kind is the name of the type used to represent errors.
|
||||
const ErrorKind = "Error"
|
||||
|
||||
// ErrorNilKind is the name of the type used to nil errors.
|
||||
const ErrorNilKind = "ErrorNil"
|
||||
|
||||
// ErrorBuilder is a builder for the error type.
|
||||
type ErrorBuilder struct {
|
||||
bitmap_ uint32
|
||||
id string
|
||||
href string
|
||||
code string
|
||||
reason string
|
||||
operationID string
|
||||
}
|
||||
|
||||
// Error represents errors.
|
||||
type Error struct {
|
||||
bitmap_ uint32
|
||||
id string
|
||||
href string
|
||||
code string
|
||||
reason string
|
||||
operationID string
|
||||
}
|
||||
|
||||
// NewError creates a new builder that can then be used to create error objects.
|
||||
func NewError() *ErrorBuilder {
|
||||
return &ErrorBuilder{}
|
||||
}
|
||||
|
||||
// ID sets the identifier of the error.
|
||||
func (b *ErrorBuilder) ID(value string) *ErrorBuilder {
|
||||
b.id = value
|
||||
b.bitmap_ |= 1
|
||||
return b
|
||||
}
|
||||
|
||||
// HREF sets the link of the error.
|
||||
func (b *ErrorBuilder) HREF(value string) *ErrorBuilder {
|
||||
b.href = value
|
||||
b.bitmap_ |= 2
|
||||
return b
|
||||
}
|
||||
|
||||
// Code sets the code of the error.
|
||||
func (b *ErrorBuilder) Code(value string) *ErrorBuilder {
|
||||
b.code = value
|
||||
b.bitmap_ |= 4
|
||||
return b
|
||||
}
|
||||
|
||||
// Reason sets the reason of the error.
|
||||
func (b *ErrorBuilder) Reason(value string) *ErrorBuilder {
|
||||
b.reason = value
|
||||
b.bitmap_ |= 8
|
||||
return b
|
||||
}
|
||||
|
||||
// OperationID sets the identifier of the operation that caused the error.
|
||||
func (b *ErrorBuilder) OperationID(value string) *ErrorBuilder {
|
||||
b.operationID = value
|
||||
b.bitmap_ |= 16
|
||||
return b
|
||||
}
|
||||
|
||||
// Build uses the information stored in the builder to create a new error object.
|
||||
func (b *ErrorBuilder) Build() (result *Error, err error) {
|
||||
result = &Error{
|
||||
id: b.id,
|
||||
href: b.href,
|
||||
code: b.code,
|
||||
reason: b.reason,
|
||||
operationID: b.operationID,
|
||||
bitmap_: b.bitmap_,
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// Kind returns the name of the type of the error.
|
||||
func (e *Error) Kind() string {
|
||||
if e == nil {
|
||||
return ErrorNilKind
|
||||
}
|
||||
return ErrorKind
|
||||
}
|
||||
|
||||
// ID returns the identifier of the error.
|
||||
func (e *Error) ID() string {
|
||||
if e != nil && e.bitmap_&1 != 0 {
|
||||
return e.id
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
// GetID returns the identifier of the error and a flag indicating if the
|
||||
// identifier has a value.
|
||||
func (e *Error) GetID() (value string, ok bool) {
|
||||
ok = e != nil && e.bitmap_&1 != 0
|
||||
if ok {
|
||||
value = e.id
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// HREF returns the link to the error.
|
||||
func (e *Error) HREF() string {
|
||||
if e != nil && e.bitmap_&2 != 0 {
|
||||
return e.href
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
// GetHREF returns the link of the error and a flag indicating if the
|
||||
// link has a value.
|
||||
func (e *Error) GetHREF() (value string, ok bool) {
|
||||
ok = e != nil && e.bitmap_&2 != 0
|
||||
if ok {
|
||||
value = e.href
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// Code returns the code of the error.
|
||||
func (e *Error) Code() string {
|
||||
if e != nil && e.bitmap_&4 != 0 {
|
||||
return e.code
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
// GetCode returns the link of the error and a flag indicating if the
|
||||
// code has a value.
|
||||
func (e *Error) GetCode() (value string, ok bool) {
|
||||
ok = e != nil && e.bitmap_&4 != 0
|
||||
if ok {
|
||||
value = e.code
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// Reason returns the reason of the error.
|
||||
func (e *Error) Reason() string {
|
||||
if e != nil && e.bitmap_&8 != 0 {
|
||||
return e.reason
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
// GetReason returns the link of the error and a flag indicating if the
|
||||
// reason has a value.
|
||||
func (e *Error) GetReason() (value string, ok bool) {
|
||||
ok = e != nil && e.bitmap_&8 != 0
|
||||
if ok {
|
||||
value = e.reason
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// OperationID returns the identifier of the operation that caused the error.
|
||||
func (e *Error) OperationID() string {
|
||||
if e != nil && e.bitmap_&16 != 0 {
|
||||
return e.operationID
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
// GetOperationID returns the identifier of the operation that caused the error and
|
||||
// a flag indicating if that identifier does have a value.
|
||||
func (e *Error) GetOperationID() (value string, ok bool) {
|
||||
ok = e != nil && e.bitmap_&16 != 0
|
||||
if ok {
|
||||
value = e.operationID
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// Error is the implementation of the error interface.
|
||||
func (e *Error) Error() string {
|
||||
chunks := make([]string, 0, 3)
|
||||
if e.id != "" {
|
||||
chunks = append(chunks, fmt.Sprintf("identifier is '%s'", e.id))
|
||||
}
|
||||
if e.code != "" {
|
||||
chunks = append(chunks, fmt.Sprintf("code is '%s'", e.code))
|
||||
}
|
||||
if e.operationID != "" {
|
||||
chunks = append(chunks, fmt.Sprintf("operation identifier is '%s'", e.operationID))
|
||||
}
|
||||
var result string
|
||||
size := len(chunks)
|
||||
if size == 1 {
|
||||
result = chunks[0]
|
||||
} else if size > 1 {
|
||||
result = strings.Join(chunks[0:size-1], ", ") + " and " + chunks[size-1]
|
||||
}
|
||||
if e.reason != "" {
|
||||
if result != "" {
|
||||
result = result + ": "
|
||||
}
|
||||
result = result + e.reason
|
||||
}
|
||||
if result == "" {
|
||||
result = "unknown error"
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
// String returns a string representing the error.
|
||||
func (e *Error) String() string {
|
||||
return e.Error()
|
||||
}
|
||||
|
||||
// UnmarshalError reads an error from the given source which can be an slice of
|
||||
// bytes, a string, a reader or a JSON decoder.
|
||||
func UnmarshalError(source interface{}) (object *Error, err error) {
|
||||
iterator, err := helpers.NewIterator(source)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
object = readError(iterator)
|
||||
err = iterator.Error
|
||||
return
|
||||
}
|
||||
func readError(iterator *jsoniter.Iterator) *Error {
|
||||
object := &Error{}
|
||||
for {
|
||||
field := iterator.ReadObject()
|
||||
if field == "" {
|
||||
break
|
||||
}
|
||||
switch field {
|
||||
case "id":
|
||||
object.id = iterator.ReadString()
|
||||
object.bitmap_ |= 1
|
||||
case "href":
|
||||
object.href = iterator.ReadString()
|
||||
object.bitmap_ |= 2
|
||||
case "code":
|
||||
object.code = iterator.ReadString()
|
||||
object.bitmap_ |= 4
|
||||
case "reason":
|
||||
object.reason = iterator.ReadString()
|
||||
object.bitmap_ |= 8
|
||||
case "operation_id":
|
||||
object.operationID = iterator.ReadString()
|
||||
object.bitmap_ |= 16
|
||||
default:
|
||||
iterator.ReadAny()
|
||||
}
|
||||
}
|
||||
return object
|
||||
}
|
||||
|
||||
// MarshalError writes an error to the given writer.
|
||||
func MarshalError(e *Error, writer io.Writer) error {
|
||||
stream := helpers.NewStream(writer)
|
||||
writeError(e, stream)
|
||||
stream.Flush()
|
||||
return stream.Error
|
||||
}
|
||||
func writeError(e *Error, stream *jsoniter.Stream) {
|
||||
stream.WriteObjectStart()
|
||||
stream.WriteObjectField("kind")
|
||||
stream.WriteString(ErrorKind)
|
||||
if e.bitmap_&1 != 0 {
|
||||
stream.WriteMore()
|
||||
stream.WriteObjectField("id")
|
||||
stream.WriteString(e.id)
|
||||
}
|
||||
if e.bitmap_&2 != 0 {
|
||||
stream.WriteMore()
|
||||
stream.WriteObjectField("href")
|
||||
stream.WriteString(e.href)
|
||||
}
|
||||
if e.bitmap_&4 != 0 {
|
||||
stream.WriteMore()
|
||||
stream.WriteObjectField("code")
|
||||
stream.WriteString(e.code)
|
||||
}
|
||||
if e.bitmap_&8 != 0 {
|
||||
stream.WriteMore()
|
||||
stream.WriteObjectField("reason")
|
||||
stream.WriteString(e.reason)
|
||||
}
|
||||
if e.bitmap_&16 != 0 {
|
||||
stream.WriteMore()
|
||||
stream.WriteObjectField("operation_id")
|
||||
stream.WriteString(e.operationID)
|
||||
}
|
||||
stream.WriteObjectEnd()
|
||||
}
|
||||
|
||||
var panicID = "1000"
|
||||
var panicError, _ = NewError().
|
||||
ID(panicID).
|
||||
Reason("An unexpected error happened, please check the log of the service " +
|
||||
"for details").
|
||||
Build()
|
||||
|
||||
// SendError writes a given error and status code to a response writer.
|
||||
// if an error occurred it will log the error and exit.
|
||||
// This methods is used internaly and no backwards compatibily is guaranteed.
|
||||
func SendError(w http.ResponseWriter, r *http.Request, object *Error) {
|
||||
status, err := strconv.Atoi(object.ID())
|
||||
if err != nil {
|
||||
SendPanic(w, r)
|
||||
return
|
||||
}
|
||||
w.Header().Set("Content-Type", "application/json")
|
||||
w.WriteHeader(status)
|
||||
err = MarshalError(object, w)
|
||||
if err != nil {
|
||||
glog.Errorf("Can't send response body for request '%s'", r.URL.Path)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
// SendPanic sends a panic error response to the client, but it doesn't end the process.
|
||||
// This methods is used internaly and no backwards compatibily is guaranteed.
|
||||
func SendPanic(w http.ResponseWriter, r *http.Request) {
|
||||
w.Header().Set("Content-Type", "application/json")
|
||||
err := MarshalError(panicError, w)
|
||||
if err != nil {
|
||||
glog.Errorf(
|
||||
"Can't send panic response for request '%s': %s",
|
||||
r.URL.Path,
|
||||
err.Error(),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
// SendNotFound sends a generic 404 error.
|
||||
func SendNotFound(w http.ResponseWriter, r *http.Request) {
|
||||
reason := fmt.Sprintf(
|
||||
"Can't find resource for path '%s'",
|
||||
r.URL.Path,
|
||||
)
|
||||
body, err := NewError().
|
||||
ID("404").
|
||||
Reason(reason).
|
||||
Build()
|
||||
if err != nil {
|
||||
SendPanic(w, r)
|
||||
return
|
||||
}
|
||||
SendError(w, r, body)
|
||||
}
|
||||
|
||||
// SendMethodNotAllowed sends a generic 405 error.
|
||||
func SendMethodNotAllowed(w http.ResponseWriter, r *http.Request) {
|
||||
reason := fmt.Sprintf(
|
||||
"Method '%s' isn't supported for path '%s'",
|
||||
r.Method, r.URL.Path,
|
||||
)
|
||||
body, err := NewError().
|
||||
ID("405").
|
||||
Reason(reason).
|
||||
Build()
|
||||
if err != nil {
|
||||
SendPanic(w, r)
|
||||
return
|
||||
}
|
||||
SendError(w, r, body)
|
||||
}
|
||||
|
||||
// SendInternalServerError sends a generic 500 error.
|
||||
func SendInternalServerError(w http.ResponseWriter, r *http.Request) {
|
||||
reason := fmt.Sprintf(
|
||||
"Can't process '%s' request for path '%s' due to an internal"+
|
||||
"server error",
|
||||
r.Method, r.URL.Path,
|
||||
)
|
||||
body, err := NewError().
|
||||
ID("500").
|
||||
Reason(reason).
|
||||
Build()
|
||||
if err != nil {
|
||||
SendPanic(w, r)
|
||||
return
|
||||
}
|
||||
SendError(w, r, body)
|
||||
}
|
||||
170
vendor/github.com/openshift-online/ocm-sdk-go/helpers/helpers.go
generated
vendored
Normal file
170
vendor/github.com/openshift-online/ocm-sdk-go/helpers/helpers.go
generated
vendored
Normal file
|
|
@ -0,0 +1,170 @@
|
|||
/*
|
||||
Copyright (c) 2020 Red Hat, Inc.
|
||||
|
||||
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.
|
||||
*/
|
||||
|
||||
// IMPORTANT: This file has been generated automatically, refrain from modifying it manually as all
|
||||
// your changes will be lost when the file is generated again.
|
||||
|
||||
package helpers // github.com/openshift-online/ocm-sdk-go/helpers
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"strings"
|
||||
"time"
|
||||
)
|
||||
|
||||
// AddValue creates the given set of query parameters if needed, an then adds
|
||||
// the given parameter.
|
||||
func AddValue(query *url.Values, name string, value interface{}) {
|
||||
if *query == nil {
|
||||
*query = make(url.Values)
|
||||
}
|
||||
query.Add(name, fmt.Sprintf("%v", value))
|
||||
}
|
||||
|
||||
// CopyQuery creates a copy of the given set of query parameters.
|
||||
func CopyQuery(query url.Values) url.Values {
|
||||
if query == nil {
|
||||
return nil
|
||||
}
|
||||
result := make(url.Values)
|
||||
for name, values := range query {
|
||||
result[name] = CopyValues(values)
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
// AddHeader creates the given set of headers if needed, and then adds the given
|
||||
// header:
|
||||
func AddHeader(header *http.Header, name string, value interface{}) {
|
||||
if *header == nil {
|
||||
*header = make(http.Header)
|
||||
}
|
||||
header.Add(name, fmt.Sprintf("%v", value))
|
||||
}
|
||||
|
||||
// CopyHeader creates a copy of the given set of headers.
|
||||
func CopyHeader(header http.Header) http.Header {
|
||||
result := make(http.Header)
|
||||
for name, values := range header {
|
||||
result[name] = CopyValues(values)
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
// CopyValues copies a slice of strings.
|
||||
func CopyValues(values []string) []string {
|
||||
if values == nil {
|
||||
return nil
|
||||
}
|
||||
result := make([]string, len(values))
|
||||
copy(result, values)
|
||||
return result
|
||||
}
|
||||
|
||||
// Segments calculates the path segments for the given path.
|
||||
func Segments(path string) []string {
|
||||
for strings.HasPrefix(path, "/") {
|
||||
path = path[1:]
|
||||
}
|
||||
for strings.HasSuffix(path, "/") {
|
||||
path = path[0 : len(path)-1]
|
||||
}
|
||||
return strings.Split(path, "/")
|
||||
}
|
||||
|
||||
// PollContext repeatedly executes a task till it returns one of the given statuses and till the result
|
||||
// satisfies all the given predicates.
|
||||
func PollContext(
|
||||
ctx context.Context,
|
||||
interval time.Duration,
|
||||
statuses []int,
|
||||
predicates []func(interface{}) bool,
|
||||
task func(context.Context) (int, interface{}, error),
|
||||
) (result interface{}, err error) {
|
||||
// Check the deadline:
|
||||
deadline, ok := ctx.Deadline()
|
||||
if !ok {
|
||||
err = fmt.Errorf("context deadline is mandatory")
|
||||
return
|
||||
}
|
||||
|
||||
// Check the interval:
|
||||
if interval <= 0 {
|
||||
err = fmt.Errorf("interval must be greater than zero")
|
||||
return
|
||||
}
|
||||
|
||||
// Create a cancellable context so that we can explicitly cancel it when we know that the next
|
||||
// iteration of the loop will be after the deadline:
|
||||
ctx, cancel := context.WithCancel(ctx)
|
||||
|
||||
// If no expected status has been explicitly specified then add the default:
|
||||
if len(statuses) == 0 {
|
||||
statuses = []int{http.StatusOK}
|
||||
}
|
||||
for {
|
||||
// Execute the task. If this produces an error and the status code is zero it means that
|
||||
// there was an error like a timeout, or a low level communications problem. In that
|
||||
// case we want to immediately stop waiting.
|
||||
var status int
|
||||
status, result, err = task(ctx)
|
||||
if err != nil && status == 0 {
|
||||
break
|
||||
}
|
||||
|
||||
// Evaluate the status and the predicates:
|
||||
statusOK := evalStatus(statuses, status)
|
||||
predicatesOK := evalPredicates(predicates, result)
|
||||
if statusOK && predicatesOK {
|
||||
break
|
||||
}
|
||||
|
||||
// If either the status or the predicates aren't acceptable then we need to check if we
|
||||
// have enough time for another iteration before the deadline:
|
||||
if time.Now().Add(interval).After(deadline) {
|
||||
cancel()
|
||||
break
|
||||
}
|
||||
time.Sleep(interval)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// evalStatus checks if the actual status is one of the expected ones.
|
||||
func evalStatus(expected []int, actual int) bool {
|
||||
for _, current := range expected {
|
||||
if actual == current {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// evalPredicates checks if the object satisfies all the predicates.
|
||||
func evalPredicates(predicates []func(interface{}) bool, object interface{}) bool {
|
||||
if len(predicates) > 0 && object == nil {
|
||||
return false
|
||||
}
|
||||
for _, predicate := range predicates {
|
||||
if !predicate(object) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
208
vendor/github.com/openshift-online/ocm-sdk-go/helpers/json_helpers.go
generated
vendored
Normal file
208
vendor/github.com/openshift-online/ocm-sdk-go/helpers/json_helpers.go
generated
vendored
Normal file
|
|
@ -0,0 +1,208 @@
|
|||
/*
|
||||
Copyright (c) 2020 Red Hat, Inc.
|
||||
|
||||
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.
|
||||
*/
|
||||
|
||||
// IMPORTANT: This file has been generated automatically, refrain from modifying it manually as all
|
||||
// your changes will be lost when the file is generated again.
|
||||
|
||||
package helpers // github.com/openshift-online/ocm-sdk-go/helpers
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io"
|
||||
"net/url"
|
||||
"strconv"
|
||||
"time"
|
||||
|
||||
jsoniter "github.com/json-iterator/go"
|
||||
)
|
||||
|
||||
// NewIterator creates a new JSON iterator that will read to the given source, which
|
||||
// can be a slice of bytes, a string or a reader.
|
||||
func NewIterator(source interface{}) (iterator *jsoniter.Iterator, err error) {
|
||||
config := jsoniter.Config{}
|
||||
api := config.Froze()
|
||||
switch typed := source.(type) {
|
||||
case []byte:
|
||||
iterator = jsoniter.ParseBytes(api, typed)
|
||||
case string:
|
||||
iterator = jsoniter.ParseString(api, typed)
|
||||
case io.Reader:
|
||||
iterator = jsoniter.Parse(api, typed, 4096)
|
||||
default:
|
||||
err = fmt.Errorf(
|
||||
"expected slice of bytes, string or reader but got '%T'",
|
||||
source,
|
||||
)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// NewStream creates a new JSON stream that will write to the given writer.
|
||||
func NewStream(writer io.Writer) *jsoniter.Stream {
|
||||
config := jsoniter.Config{
|
||||
IndentionStep: 2,
|
||||
}
|
||||
api := config.Froze()
|
||||
return jsoniter.NewStream(api, writer, 0)
|
||||
}
|
||||
|
||||
// NewBoolean allocates a new bool in the heap and returns a pointer to it.
|
||||
func NewBoolean(value bool) *bool {
|
||||
return &value
|
||||
}
|
||||
|
||||
// NewInteger allocates a new integer in the heap and returns a pointer to it.
|
||||
func NewInteger(value int) *int {
|
||||
return &value
|
||||
}
|
||||
|
||||
// NewFloat allocates a new floating point value in the heap and returns an pointer
|
||||
// to it.
|
||||
func NewFloat(value float64) *float64 {
|
||||
return &value
|
||||
}
|
||||
|
||||
// NewString allocates a new string in the heap and returns a pointer to it.
|
||||
func NewString(value string) *string {
|
||||
return &value
|
||||
}
|
||||
|
||||
// NewDate allocates a new date in the heap and returns a pointer to it.
|
||||
func NewDate(value time.Time) *time.Time {
|
||||
return &value
|
||||
}
|
||||
|
||||
// ParseInteger reads a string and parses it to integer,
|
||||
// if an error occurred it returns a non-nil error.
|
||||
func ParseInteger(query url.Values, parameterName string) (*int, error) {
|
||||
values := query[parameterName]
|
||||
count := len(values)
|
||||
if count == 0 {
|
||||
return nil, nil
|
||||
}
|
||||
if count > 1 {
|
||||
err := fmt.Errorf(
|
||||
"expected at most one value for parameter '%s' but got %d",
|
||||
parameterName, count,
|
||||
)
|
||||
return nil, err
|
||||
}
|
||||
value := values[0]
|
||||
parsedInt64, err := strconv.ParseInt(value, 10, 64)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf(
|
||||
"value '%s' isn't valid for the '%s' parameter because it isn't an integer: %v",
|
||||
value, parameterName, err,
|
||||
)
|
||||
}
|
||||
parsedInt := int(parsedInt64)
|
||||
return &parsedInt, nil
|
||||
}
|
||||
|
||||
// ParseFloat reads a string and parses it to float,
|
||||
// if an error occurred it returns a non-nil error.
|
||||
func ParseFloat(query url.Values, parameterName string) (*float64, error) {
|
||||
values := query[parameterName]
|
||||
count := len(values)
|
||||
if count == 0 {
|
||||
return nil, nil
|
||||
}
|
||||
if count > 1 {
|
||||
err := fmt.Errorf(
|
||||
"expected at most one value for parameter '%s' but got %d",
|
||||
parameterName, count,
|
||||
)
|
||||
return nil, err
|
||||
}
|
||||
value := values[0]
|
||||
parsedFloat, err := strconv.ParseFloat(value, 64)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf(
|
||||
"value '%s' isn't valid for the '%s' parameter because it isn't a float: %v",
|
||||
value, parameterName, err,
|
||||
)
|
||||
}
|
||||
return &parsedFloat, nil
|
||||
}
|
||||
|
||||
// ParseString returns a pointer to the string and nil error.
|
||||
func ParseString(query url.Values, parameterName string) (*string, error) {
|
||||
values := query[parameterName]
|
||||
count := len(values)
|
||||
if count == 0 {
|
||||
return nil, nil
|
||||
}
|
||||
if count > 1 {
|
||||
err := fmt.Errorf(
|
||||
"expected at most one value for parameter '%s' but got %d",
|
||||
parameterName, count,
|
||||
)
|
||||
return nil, err
|
||||
}
|
||||
return &values[0], nil
|
||||
}
|
||||
|
||||
// ParseBoolean reads a string and parses it to boolean,
|
||||
// if an error occurred it returns a non-nil error.
|
||||
func ParseBoolean(query url.Values, parameterName string) (*bool, error) {
|
||||
values := query[parameterName]
|
||||
count := len(values)
|
||||
if count == 0 {
|
||||
return nil, nil
|
||||
}
|
||||
if count > 1 {
|
||||
err := fmt.Errorf(
|
||||
"expected at most one value for parameter '%s' but got %d",
|
||||
parameterName, count,
|
||||
)
|
||||
return nil, err
|
||||
}
|
||||
value := values[0]
|
||||
parsedBool, err := strconv.ParseBool(value)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf(
|
||||
"value '%s' isn't valid for the '%s' parameter because it isn't a boolean: %v",
|
||||
value, parameterName, err,
|
||||
)
|
||||
}
|
||||
return &parsedBool, nil
|
||||
}
|
||||
|
||||
// ParseDate reads a string and parses it to a time.Time,
|
||||
// if an error occurred it returns a non-nil error.
|
||||
func ParseDate(query url.Values, parameterName string) (*time.Time, error) {
|
||||
values := query[parameterName]
|
||||
count := len(values)
|
||||
if count == 0 {
|
||||
return nil, nil
|
||||
}
|
||||
if count > 1 {
|
||||
err := fmt.Errorf(
|
||||
"expected at most one value for parameter '%s' but got %d",
|
||||
parameterName, count,
|
||||
)
|
||||
return nil, err
|
||||
}
|
||||
value := values[0]
|
||||
parsedTime, err := time.Parse(time.RFC3339, value)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf(
|
||||
"value '%s' isn't valid for the '%s' parameter because it isn't a date: %v",
|
||||
value, parameterName, err,
|
||||
)
|
||||
}
|
||||
return &parsedTime, nil
|
||||
}
|
||||
91
vendor/github.com/openshift-online/ocm-sdk-go/internal/check_content_type.go
generated
vendored
Normal file
91
vendor/github.com/openshift-online/ocm-sdk-go/internal/check_content_type.go
generated
vendored
Normal file
|
|
@ -0,0 +1,91 @@
|
|||
/*
|
||||
Copyright (c) 2021 Red Hat, Inc.
|
||||
|
||||
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.
|
||||
*/
|
||||
|
||||
// This file contains the functions used to check content types.
|
||||
|
||||
package internal
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"html"
|
||||
"io/ioutil"
|
||||
"mime"
|
||||
"net/http"
|
||||
"regexp"
|
||||
"strings"
|
||||
|
||||
strip "github.com/grokify/html-strip-tags-go"
|
||||
)
|
||||
|
||||
var wsRegex = regexp.MustCompile(`\s+`)
|
||||
|
||||
// CheckContentType checks that the content type of the given response is JSON. Note that if the
|
||||
// content type isn't JSON this method will consume the complete body in order to generate an error
|
||||
// message containing a summary of the content.
|
||||
func CheckContentType(response *http.Response) error {
|
||||
var err error
|
||||
var mediaType string
|
||||
contentType := response.Header.Get("Content-Type")
|
||||
if contentType != "" {
|
||||
mediaType, _, err = mime.ParseMediaType(contentType)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
} else {
|
||||
mediaType = contentType
|
||||
}
|
||||
if !strings.EqualFold(mediaType, "application/json") {
|
||||
var summary string
|
||||
summary, err = contentSummary(mediaType, response)
|
||||
if err != nil {
|
||||
return fmt.Errorf(
|
||||
"expected response content type 'application/json' but received "+
|
||||
"'%s' and couldn't obtain content summary: %w",
|
||||
mediaType, err,
|
||||
)
|
||||
}
|
||||
return fmt.Errorf(
|
||||
"expected response content type 'application/json' but received '%s' and "+
|
||||
"content '%s'",
|
||||
mediaType, summary,
|
||||
)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// contentSummary reads the body of the given response and returns a summary it. The summary will
|
||||
// be the complete body if it isn't too log. If it is too long then the summary will be the
|
||||
// beginning of the content followed by ellipsis.
|
||||
func contentSummary(mediaType string, response *http.Response) (summary string, err error) {
|
||||
var body []byte
|
||||
body, err = ioutil.ReadAll(response.Body)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
limit := 250
|
||||
runes := []rune(string(body))
|
||||
if strings.EqualFold(mediaType, "text/html") && len(runes) > limit {
|
||||
content := html.UnescapeString(strip.StripTags(string(body)))
|
||||
content = wsRegex.ReplaceAllString(strings.TrimSpace(content), " ")
|
||||
runes = []rune(content)
|
||||
}
|
||||
if len(runes) > limit {
|
||||
summary = fmt.Sprintf("%s...", string(runes[:limit]))
|
||||
} else {
|
||||
summary = string(runes)
|
||||
}
|
||||
return
|
||||
}
|
||||
403
vendor/github.com/openshift-online/ocm-sdk-go/internal/client_selector.go
generated
vendored
Normal file
403
vendor/github.com/openshift-online/ocm-sdk-go/internal/client_selector.go
generated
vendored
Normal file
|
|
@ -0,0 +1,403 @@
|
|||
/*
|
||||
Copyright (c) 2021 Red Hat, Inc.
|
||||
|
||||
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.
|
||||
*/
|
||||
|
||||
// This file contains the implementation of the object that selects the HTTP client to use to
|
||||
// connect to servers using TCP or Unix sockets.
|
||||
|
||||
package internal
|
||||
|
||||
import (
|
||||
"context"
|
||||
"crypto/tls"
|
||||
"crypto/x509"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"net"
|
||||
"net/http"
|
||||
"net/http/cookiejar"
|
||||
"sync"
|
||||
|
||||
"golang.org/x/net/http2"
|
||||
|
||||
"github.com/openshift-online/ocm-sdk-go/logging"
|
||||
)
|
||||
|
||||
// ClientSelectorBuilder contains the information and logic needed to create an HTTP client
|
||||
// selector. Don't create instances of this type directly, use the NewClientSelector function.
|
||||
type ClientSelectorBuilder struct {
|
||||
logger logging.Logger
|
||||
trustedCAs []interface{}
|
||||
insecure bool
|
||||
disableKeepAlives bool
|
||||
transportWrappers []func(http.RoundTripper) http.RoundTripper
|
||||
}
|
||||
|
||||
// ClientSelector contains the information needed to create select the HTTP client to use to connect
|
||||
// to servers using TCP or Unix sockets.
|
||||
type ClientSelector struct {
|
||||
logger logging.Logger
|
||||
trustedCAs *x509.CertPool
|
||||
insecure bool
|
||||
disableKeepAlives bool
|
||||
transportWrappers []func(http.RoundTripper) http.RoundTripper
|
||||
cookieJar http.CookieJar
|
||||
clientsMutex *sync.Mutex
|
||||
clientsTable map[string]*http.Client
|
||||
}
|
||||
|
||||
// NewClientSelector creates a builder that can then be used to configure and create an HTTP client
|
||||
// selector.
|
||||
func NewClientSelector() *ClientSelectorBuilder {
|
||||
return &ClientSelectorBuilder{}
|
||||
}
|
||||
|
||||
// Logger sets the logger that will be used by the selector and by the created HTTP clients to write
|
||||
// messages to the log. This is mandatory.
|
||||
func (b *ClientSelectorBuilder) Logger(value logging.Logger) *ClientSelectorBuilder {
|
||||
b.logger = value
|
||||
return b
|
||||
}
|
||||
|
||||
// TrustedCA sets a source that contains he certificate authorities that will be trusted by the HTTP
|
||||
// clients. If this isn't explicitly specified then the clients will trust the certificate
|
||||
// authorities trusted by default by the system. The value can be a *x509.CertPool or a string,
|
||||
// anything else will cause an error when Build method is called. If it is a *x509.CertPool then the
|
||||
// value will replace any other source given before. If it is a string then it should be the name of
|
||||
// a PEM file. The contents of that file will be added to the previously given sources.
|
||||
func (b *ClientSelectorBuilder) TrustedCA(value interface{}) *ClientSelectorBuilder {
|
||||
if value != nil {
|
||||
b.trustedCAs = append(b.trustedCAs, value)
|
||||
}
|
||||
return b
|
||||
}
|
||||
|
||||
// TrustedCAs sets a list of sources that contains he certificate authorities that will be trusted
|
||||
// by the HTTP clients. See the documentation of the TrustedCA method for more information about the
|
||||
// accepted values.
|
||||
func (b *ClientSelectorBuilder) TrustedCAs(values ...interface{}) *ClientSelectorBuilder {
|
||||
for _, value := range values {
|
||||
b.TrustedCA(value)
|
||||
}
|
||||
return b
|
||||
}
|
||||
|
||||
// Insecure enables insecure communication with the servers. This disables verification of TLS
|
||||
// certificates and host names and it isn't recommended for a production environment.
|
||||
func (b *ClientSelectorBuilder) Insecure(flag bool) *ClientSelectorBuilder {
|
||||
b.insecure = flag
|
||||
return b
|
||||
}
|
||||
|
||||
// DisableKeepAlives disables HTTP keep-alives with the serviers. This is unrelated to similarly
|
||||
// named TCP keep-alives.
|
||||
func (b *ClientSelectorBuilder) DisableKeepAlives(flag bool) *ClientSelectorBuilder {
|
||||
b.disableKeepAlives = flag
|
||||
return b
|
||||
}
|
||||
|
||||
// TransportWrapper adds a function that will be used to wrap the transports of the HTTP clients. If
|
||||
// used multiple times the transport wrappers will be called in the same order that they are added.
|
||||
func (b *ClientSelectorBuilder) TransportWrapper(
|
||||
value func(http.RoundTripper) http.RoundTripper) *ClientSelectorBuilder {
|
||||
if value != nil {
|
||||
b.transportWrappers = append(b.transportWrappers, value)
|
||||
}
|
||||
return b
|
||||
}
|
||||
|
||||
// TransportWrappers adds a list of functions that will be used to wrap the transports of the HTTP clients.
|
||||
func (b *ClientSelectorBuilder) TransportWrappers(
|
||||
values ...func(http.RoundTripper) http.RoundTripper) *ClientSelectorBuilder {
|
||||
for _, value := range values {
|
||||
b.TransportWrapper(value)
|
||||
}
|
||||
return b
|
||||
}
|
||||
|
||||
// Build uses the information stored in the builder to create a new HTTP client selector.
|
||||
func (b *ClientSelectorBuilder) Build(ctx context.Context) (result *ClientSelector, err error) {
|
||||
// Check parameters:
|
||||
if b.logger == nil {
|
||||
err = fmt.Errorf("logger is mandatory")
|
||||
return
|
||||
}
|
||||
|
||||
// Create the cookie jar:
|
||||
cookieJar, err := b.createCookieJar()
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
// Load trusted CAs:
|
||||
trustedCAs, err := b.loadTrustedCAs(ctx)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
// Create and populate the object:
|
||||
result = &ClientSelector{
|
||||
logger: b.logger,
|
||||
trustedCAs: trustedCAs,
|
||||
insecure: b.insecure,
|
||||
disableKeepAlives: b.disableKeepAlives,
|
||||
transportWrappers: b.transportWrappers,
|
||||
cookieJar: cookieJar,
|
||||
clientsMutex: &sync.Mutex{},
|
||||
clientsTable: map[string]*http.Client{},
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
func (b *ClientSelectorBuilder) loadTrustedCAs(ctx context.Context) (result *x509.CertPool,
|
||||
err error) {
|
||||
result, err = loadSystemCAs()
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
for _, ca := range b.trustedCAs {
|
||||
switch source := ca.(type) {
|
||||
case *x509.CertPool:
|
||||
b.logger.Debug(
|
||||
ctx,
|
||||
"Default trusted CA certificates have been explicitly replaced",
|
||||
)
|
||||
result = source
|
||||
case string:
|
||||
b.logger.Debug(
|
||||
ctx,
|
||||
"Loading trusted CA certificates from file '%s'",
|
||||
source,
|
||||
)
|
||||
var buffer []byte
|
||||
buffer, err = ioutil.ReadFile(source) // #nosec G304
|
||||
if err != nil {
|
||||
result = nil
|
||||
err = fmt.Errorf(
|
||||
"can't read trusted CA certificates from file '%s': %w",
|
||||
source, err,
|
||||
)
|
||||
return
|
||||
}
|
||||
if !result.AppendCertsFromPEM(buffer) {
|
||||
result = nil
|
||||
err = fmt.Errorf(
|
||||
"file '%s' doesn't contain any certificate",
|
||||
source,
|
||||
)
|
||||
return
|
||||
}
|
||||
default:
|
||||
result = nil
|
||||
err = fmt.Errorf(
|
||||
"don't know how to load trusted CA from source of type '%T'",
|
||||
source,
|
||||
)
|
||||
return
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func (b *ClientSelectorBuilder) createCookieJar() (result http.CookieJar, err error) {
|
||||
result, err = cookiejar.New(nil)
|
||||
return
|
||||
}
|
||||
|
||||
// Select returns an HTTP client to use to connect to the given server address. If a client has been
|
||||
// created previously for the server address it will be reused, otherwise it will be created.
|
||||
func (s *ClientSelector) Select(ctx context.Context, address *ServerAddress) (client *http.Client,
|
||||
err error) {
|
||||
// We need to use a different client for each TCP host name and each Unix socket because we
|
||||
// explicitly set the TLS server name to the host name. For example, if the first request is
|
||||
// for the SSO service (it will usually be) then we would set the TLS server name to
|
||||
// `sso.redhat.com`. The next API request would then use the same client and therefore it
|
||||
// will use `sso.redhat.com` as the TLS server name. If the server uses SNI to select the
|
||||
// certificates it will then fail because the API server doesn't have any certificate for
|
||||
// `sso.redhat.com`, it will return the default certificates, and then the validation would
|
||||
// fail with an error message like this:
|
||||
//
|
||||
// x509: certificate is valid for *.apps.app-sre-prod-04.i5h0.p1.openshiftapps.com,
|
||||
// api.app-sre-prod-04.i5h0.p1.openshiftapps.com,
|
||||
// rh-api.app-sre-prod-04.i5h0.p1.openshiftapps.com, not sso.redhat.com
|
||||
//
|
||||
// To avoid this we add the host name or socket path as a suffix to the key.
|
||||
key := address.Network
|
||||
switch address.Network {
|
||||
case UnixNetwork:
|
||||
key = fmt.Sprintf("%s:%s", key, address.Socket)
|
||||
case TCPNetwork:
|
||||
key = fmt.Sprintf("%s:%s", key, address.Host)
|
||||
}
|
||||
|
||||
// We will be modifiying the clients table so we need to acquire the lock before proceeding:
|
||||
s.clientsMutex.Lock()
|
||||
defer s.clientsMutex.Unlock()
|
||||
|
||||
// Get an existing client, or create a new one if it doesn't exist yet:
|
||||
client, ok := s.clientsTable[key]
|
||||
if ok {
|
||||
return
|
||||
}
|
||||
s.logger.Debug(ctx, "Client for key '%s' doesn't exist, will create it", key)
|
||||
client, err = s.create(ctx, address)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
s.clientsTable[key] = client
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
// create creates a new HTTP client to use to connect to the given address.
|
||||
func (s *ClientSelector) create(ctx context.Context, address *ServerAddress) (result *http.Client,
|
||||
err error) {
|
||||
// Create the transport:
|
||||
transport, err := s.createTransport(ctx, address)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
// Create the client:
|
||||
result = &http.Client{
|
||||
Jar: s.cookieJar,
|
||||
Transport: transport,
|
||||
}
|
||||
if s.logger.DebugEnabled() {
|
||||
result.CheckRedirect = func(request *http.Request, via []*http.Request) error {
|
||||
s.logger.Info(
|
||||
request.Context(),
|
||||
"Following redirect from '%s' to '%s'",
|
||||
via[0].URL,
|
||||
request.URL,
|
||||
)
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
// createTransport creates a new HTTP transport to use to connect to the given server address.
|
||||
func (s *ClientSelector) createTransport(ctx context.Context,
|
||||
address *ServerAddress) (result http.RoundTripper, err error) {
|
||||
// Prepare the TLS configuration:
|
||||
// #nosec 402
|
||||
config := &tls.Config{
|
||||
ServerName: address.Host,
|
||||
InsecureSkipVerify: s.insecure,
|
||||
RootCAs: s.trustedCAs,
|
||||
}
|
||||
|
||||
// Create the transport:
|
||||
if address.Protocol != H2CProtocol {
|
||||
// Create a regular transport. Note that this does support HTTP/2 with TLS, but
|
||||
// not h2c:
|
||||
transport := &http.Transport{
|
||||
TLSClientConfig: config,
|
||||
Proxy: http.ProxyFromEnvironment,
|
||||
DisableKeepAlives: s.disableKeepAlives,
|
||||
DisableCompression: false,
|
||||
ForceAttemptHTTP2: true,
|
||||
}
|
||||
|
||||
// In order to use Unix sockets we need to explicitly set dialers that use `unix` as
|
||||
// network and the socket file as address, otherwise the HTTP client will always use
|
||||
// `tcp` as the network and the host name from the request as the address:
|
||||
if address.Network == UnixNetwork {
|
||||
transport.DialContext = func(ctx context.Context, _, _ string) (net.Conn,
|
||||
error) {
|
||||
dialer := net.Dialer{}
|
||||
return dialer.DialContext(ctx, UnixNetwork, address.Socket)
|
||||
}
|
||||
transport.DialTLS = func(_, _ string) (net.Conn, error) {
|
||||
// TODO: This ignores the passed context because it isn't currently
|
||||
// supported. Once we migrate to Go 1.15 it should be done like
|
||||
// this:
|
||||
//
|
||||
// transport.DialTLSContext = func(ctx context.Context,
|
||||
// _, _ string) (net.Conn, error) {
|
||||
// dialer := tls.Dialer{
|
||||
// Config: config,
|
||||
// }
|
||||
// return dialer.DialContext(ctx, network, address.Socket)
|
||||
// }
|
||||
//
|
||||
// This will only have a negative impact in applications that
|
||||
// specify a deadline or timeout in the passed context, as it
|
||||
// will be ignored.
|
||||
return tls.Dial(UnixNetwork, address.Socket, config)
|
||||
}
|
||||
}
|
||||
|
||||
// Prepare the result:
|
||||
result = transport
|
||||
} else {
|
||||
// In order to use h2c we need to tell the transport to allow the `http` scheme:
|
||||
transport := &http2.Transport{
|
||||
AllowHTTP: true,
|
||||
DisableCompression: false,
|
||||
}
|
||||
|
||||
// We also need to ignore TLS configuration when dialing, and explicitly set the
|
||||
// network and socket when using Unix sockets:
|
||||
if address.Network == UnixNetwork {
|
||||
transport.DialTLS = func(_, _ string, cfg *tls.Config) (net.Conn, error) {
|
||||
return net.Dial(UnixNetwork, address.Socket)
|
||||
}
|
||||
} else {
|
||||
transport.DialTLS = func(network, addr string, cfg *tls.Config) (net.Conn,
|
||||
error) {
|
||||
return net.Dial(network, addr)
|
||||
}
|
||||
}
|
||||
|
||||
// Prepare the result:
|
||||
result = transport
|
||||
}
|
||||
|
||||
// Transport wrappers are stored in the order that the round trippers that they create
|
||||
// should be called. That means that we need to call them in reverse order.
|
||||
for i := len(s.transportWrappers) - 1; i >= 0; i-- {
|
||||
result = s.transportWrappers[i](result)
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
// TrustedCAs sets returns the certificate pool that contains the certificate authorities that are
|
||||
// trusted by the HTTP clients.
|
||||
func (s *ClientSelector) TrustedCAs() *x509.CertPool {
|
||||
return s.trustedCAs
|
||||
}
|
||||
|
||||
// Insecure returns the flag that indicates if insecure communication with the server is enabled.
|
||||
func (s *ClientSelector) Insecure() bool {
|
||||
return s.insecure
|
||||
}
|
||||
|
||||
// DisableKeepAlives retursnt the flag that indicates if HTTP keep alive is disabled.
|
||||
func (s *ClientSelector) DisableKeepAlives() bool {
|
||||
return s.disableKeepAlives
|
||||
}
|
||||
|
||||
// Close closes all the connections used by all the clients created by the selector.
|
||||
func (s *ClientSelector) Close() error {
|
||||
for _, client := range s.clientsTable {
|
||||
client.CloseIdleConnections()
|
||||
}
|
||||
return nil
|
||||
}
|
||||
26
vendor/github.com/openshift-online/ocm-sdk-go/internal/data.go
generated
vendored
Normal file
26
vendor/github.com/openshift-online/ocm-sdk-go/internal/data.go
generated
vendored
Normal file
|
|
@ -0,0 +1,26 @@
|
|||
/*
|
||||
Copyright (c) 2018 Red Hat, Inc.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package internal
|
||||
|
||||
// TokenResponse is used to unmarshal the sub-set of properties JSON token responses that we need.
|
||||
type TokenResponse struct {
|
||||
AccessToken *string `json:"access_token,omitempty"`
|
||||
Error *string `json:"error,omitempty"`
|
||||
ErrorDescription *string `json:"error_description,omitempty"`
|
||||
RefreshToken *string `json:"refresh_token,omitempty"`
|
||||
TokenType *string `json:"token_type,omitempty"`
|
||||
}
|
||||
93
vendor/github.com/openshift-online/ocm-sdk-go/internal/helpers.go
generated
vendored
Normal file
93
vendor/github.com/openshift-online/ocm-sdk-go/internal/helpers.go
generated
vendored
Normal file
|
|
@ -0,0 +1,93 @@
|
|||
/*
|
||||
Copyright (c) 2018 Red Hat, Inc.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package internal
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"time"
|
||||
)
|
||||
|
||||
// AddValue creates the given set of query parameters if needed, an then adds
|
||||
// the given parameter.
|
||||
func AddValue(query *url.Values, name string, value interface{}) {
|
||||
if *query == nil {
|
||||
*query = make(url.Values)
|
||||
}
|
||||
query.Add(name, fmt.Sprintf("%v", value))
|
||||
}
|
||||
|
||||
// CopyQuery creates a copy of the given set of query parameters.
|
||||
func CopyQuery(query url.Values) url.Values {
|
||||
if query == nil {
|
||||
return nil
|
||||
}
|
||||
result := make(url.Values)
|
||||
for name, values := range query {
|
||||
result[name] = CopyValues(values)
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
// AddHeader creates the given set of headers if needed, and then adds the given
|
||||
// header:
|
||||
func AddHeader(header *http.Header, name string, value interface{}) {
|
||||
if *header == nil {
|
||||
*header = make(http.Header)
|
||||
}
|
||||
header.Add(name, fmt.Sprintf("%v", value))
|
||||
}
|
||||
|
||||
// CopyHeader creates a copy of the given set of headers.
|
||||
func CopyHeader(header http.Header) http.Header {
|
||||
if header == nil {
|
||||
return nil
|
||||
}
|
||||
result := make(http.Header)
|
||||
for name, values := range header {
|
||||
result[name] = CopyValues(values)
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
// CopyValues copies a slice of strings.
|
||||
func CopyValues(values []string) []string {
|
||||
if values == nil {
|
||||
return nil
|
||||
}
|
||||
result := make([]string, len(values))
|
||||
copy(result, values)
|
||||
return result
|
||||
}
|
||||
|
||||
// SetTimeout creates the given context, if needed, and sets the given timeout.
|
||||
func SetTimeout(ctx *context.Context, cancel *context.CancelFunc, timeout time.Duration) {
|
||||
if *ctx == nil {
|
||||
*ctx = context.Background()
|
||||
}
|
||||
*ctx, *cancel = context.WithTimeout(*ctx, timeout)
|
||||
}
|
||||
|
||||
// SetDeadline creates the given context, if needed, and sets the given deadline.
|
||||
func SetDeadline(ctx *context.Context, cancel *context.CancelFunc, deadline time.Time) {
|
||||
if *ctx == nil {
|
||||
*ctx = context.Background()
|
||||
}
|
||||
*ctx, *cancel = context.WithDeadline(*ctx, deadline)
|
||||
}
|
||||
325
vendor/github.com/openshift-online/ocm-sdk-go/internal/server_address.go
generated
vendored
Normal file
325
vendor/github.com/openshift-online/ocm-sdk-go/internal/server_address.go
generated
vendored
Normal file
|
|
@ -0,0 +1,325 @@
|
|||
/*
|
||||
Copyright (c) 2021 Red Hat, Inc.
|
||||
|
||||
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.
|
||||
*/
|
||||
|
||||
// This file contains the implementation of the server address parser.
|
||||
|
||||
package internal
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
neturl "net/url"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// ServerAddress contains a parsed URL and additional information extracted from int, like the
|
||||
// network (tcp or unix) and the socket name (for Unix sockets).
|
||||
type ServerAddress struct {
|
||||
// Text is the original text that was passed to the ParseServerAddress function to create
|
||||
// this server address.
|
||||
Text string
|
||||
|
||||
// Network is the network that should be used to connect to the server. Possible values are
|
||||
// `tcp` and `unix`.
|
||||
Network string
|
||||
|
||||
// Protocol is the application protocol used to connect to the server. Possible values are
|
||||
// `http`, `https` and `h2c`.
|
||||
Protocol string
|
||||
|
||||
// Host is the name of the host used to connect to the server. This will be populated only
|
||||
// even when using Unix sockets, because clients will need it in order to populate the
|
||||
// `Host` header.
|
||||
Host string
|
||||
|
||||
// Port is the port number used to connect to the server. This will only be populated when
|
||||
// using TCP. When using Unix sockets it will be zero.
|
||||
Port string
|
||||
|
||||
// Socket is tha nem of the path of the Unix socket used to connect to the server.
|
||||
Socket string
|
||||
|
||||
// URL is the regular URL calculated from this server address. The scheme will be `http` if
|
||||
// the protocol is `http` or `h2c` and will be `https` if the protocol is https.
|
||||
URL *neturl.URL
|
||||
}
|
||||
|
||||
// ParseServerAddress parses the given text as a server address. Server addresses should be URLs
|
||||
// with this format:
|
||||
//
|
||||
// network+protocol://host:port/path?network=...&protocol=...&socket=...
|
||||
//
|
||||
// The `network` and `protocol` parts of the scheme are optional.
|
||||
//
|
||||
// Valid values for the `network` part of the scheme are `unix` and `tcp`. If not specified the
|
||||
// default value is `tcp`.
|
||||
//
|
||||
// Valid values for the `protocol` part of the scheme are `http`, `https` and `h2c`. If not
|
||||
// specified the default value is `http`.
|
||||
//
|
||||
// The `host` is mandatory even when using Unix sockets, because it is necessary to populate the
|
||||
// `Host` header.
|
||||
//
|
||||
// The `port` part is optional. If not specified it will be 80 for HTTP and H2C and 443 for HTTPS.
|
||||
//
|
||||
// When using Unix sockets the `path` part will be used as the name of the Unix socket.
|
||||
//
|
||||
// The network protocol and Unix socket can alternatively be specified using the `network`,
|
||||
// `protocol` and `socket` query parameters. This is useful specially for specifying the Unix
|
||||
// sockets when the path of the URL has some other meaning. For example, in order to specify
|
||||
// the OpenID token URL it is usually necessary to include a path, so to use a Unix socket it
|
||||
// is necessary to put it in the `socket` parameter instead:
|
||||
//
|
||||
// unix://my.sso.com/my/token/path?socket=/sockets/my.socket
|
||||
//
|
||||
// When the Unix socket is specified in the `socket` query parameter as in the above example
|
||||
// the URL path will be ignored.
|
||||
//
|
||||
// Some examples of valid server addresses:
|
||||
//
|
||||
// - http://my.server.com - HTTP on top of TCP.
|
||||
// - https://my.server.com - HTTPS on top of TCP.
|
||||
// - unix://my.server.com/sockets/my.socket - HTTP on top Unix socket.
|
||||
// - unix+https://my.server.com/sockets/my.socket - HTTPS on top of Unix socket.
|
||||
// - h2c+unix://my.server.com?socket=/sockets/my.socket - H2C on top of Unix.
|
||||
func ParseServerAddress(ctx context.Context, text string) (result *ServerAddress, err error) {
|
||||
// Parse the URL:
|
||||
parsed, err := neturl.Parse(text)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
query := parsed.Query()
|
||||
|
||||
// Extract the network and protocol from the scheme:
|
||||
networkFromScheme, protocolFromScheme, err := parseScheme(ctx, parsed.Scheme)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
// Check if the network is also specified with a query parameter. If it is it should not be
|
||||
// conflicting with the value specified in the scheme.
|
||||
var network string
|
||||
networkValues, ok := query["network"]
|
||||
if ok {
|
||||
if len(networkValues) != 1 {
|
||||
err = fmt.Errorf(
|
||||
"expected exactly one value for the 'network' query parameter "+
|
||||
"but found %d",
|
||||
len(networkValues),
|
||||
)
|
||||
return
|
||||
}
|
||||
networkFromQuery := strings.TrimSpace(strings.ToLower(networkValues[0]))
|
||||
err = checkNetwork(networkFromQuery)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
if networkFromScheme != "" && networkFromScheme != networkFromQuery {
|
||||
err = fmt.Errorf(
|
||||
"network '%s' from query parameter isn't compatible with "+
|
||||
"network '%s' from scheme",
|
||||
networkFromQuery, networkFromScheme,
|
||||
)
|
||||
return
|
||||
}
|
||||
network = networkFromQuery
|
||||
} else {
|
||||
network = networkFromScheme
|
||||
}
|
||||
|
||||
// Check if the protocol is also specified with a query parameter. If it is it should not be
|
||||
// conflicting with the value specified in the scheme.
|
||||
var protocol string
|
||||
protocolValues, ok := query["protocol"]
|
||||
if ok {
|
||||
if len(protocolValues) != 1 {
|
||||
err = fmt.Errorf(
|
||||
"expected exactly one value for the 'protocol' query parameter "+
|
||||
"but found %d",
|
||||
len(protocolValues),
|
||||
)
|
||||
return
|
||||
}
|
||||
protocolFromQuery := strings.TrimSpace(strings.ToLower(protocolValues[0]))
|
||||
err = checkProtocol(protocolFromQuery)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
if protocolFromScheme != "" && protocolFromScheme != protocolFromQuery {
|
||||
err = fmt.Errorf(
|
||||
"protocol '%s' from query parameter isn't compatible with "+
|
||||
"protocol '%s' from scheme",
|
||||
protocolFromQuery, protocolFromScheme,
|
||||
)
|
||||
return
|
||||
}
|
||||
protocol = protocolFromQuery
|
||||
} else {
|
||||
protocol = protocolFromScheme
|
||||
}
|
||||
|
||||
// Set default values for the network and protocol if needed:
|
||||
if network == "" {
|
||||
network = TCPNetwork
|
||||
}
|
||||
if protocol == "" {
|
||||
protocol = HTTPProtocol
|
||||
}
|
||||
|
||||
// Get the host name. Note that the host name is mandatory even when using Unix sockets,
|
||||
// because it is used to populate the `Host` header.
|
||||
host := parsed.Hostname()
|
||||
if host == "" {
|
||||
err = fmt.Errorf("host name is mandatory, but it is empty")
|
||||
return
|
||||
}
|
||||
|
||||
// Get the port number:
|
||||
port := parsed.Port()
|
||||
if port == "" {
|
||||
switch protocol {
|
||||
case HTTPProtocol, H2CProtocol:
|
||||
port = "80"
|
||||
case HTTPSProtocol:
|
||||
port = "443"
|
||||
}
|
||||
}
|
||||
|
||||
// Get the socket from the `socket` query parameter or from the path:
|
||||
var socket string
|
||||
if network == UnixNetwork {
|
||||
socketValues, ok := query["socket"]
|
||||
if ok {
|
||||
if len(socketValues) != 1 {
|
||||
err = fmt.Errorf(
|
||||
"expected exactly one value for the 'socket' query "+
|
||||
"parameter but found %d",
|
||||
len(socketValues),
|
||||
)
|
||||
return
|
||||
}
|
||||
socket = socketValues[0]
|
||||
} else {
|
||||
socket = parsed.Path
|
||||
}
|
||||
if socket == "" {
|
||||
err = fmt.Errorf(
|
||||
"expected socket name in the 'socket' query parameter or in " +
|
||||
"the path but both are empty",
|
||||
)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
// Calculate the URL:
|
||||
url := &neturl.URL{
|
||||
Host: host,
|
||||
}
|
||||
switch protocol {
|
||||
case HTTPProtocol, H2CProtocol:
|
||||
url.Scheme = "http"
|
||||
if port != "80" {
|
||||
url.Host = fmt.Sprintf("%s:%s", url.Host, port)
|
||||
}
|
||||
case HTTPSProtocol:
|
||||
url.Scheme = "https"
|
||||
if port != "443" {
|
||||
url.Host = fmt.Sprintf("%s:%s", url.Host, port)
|
||||
}
|
||||
}
|
||||
|
||||
// Create and populate the result:
|
||||
result = &ServerAddress{
|
||||
Text: text,
|
||||
Network: network,
|
||||
Protocol: protocol,
|
||||
Host: host,
|
||||
Port: port,
|
||||
Socket: socket,
|
||||
URL: url,
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
func parseScheme(ctx context.Context, scheme string) (network, protocol string,
|
||||
err error) {
|
||||
components := strings.Split(strings.ToLower(scheme), "+")
|
||||
if len(components) > 2 {
|
||||
err = fmt.Errorf(
|
||||
"scheme '%s' should have at most two components separated by '+', "+
|
||||
"but it has %d",
|
||||
scheme, len(components),
|
||||
)
|
||||
return
|
||||
}
|
||||
for _, component := range components {
|
||||
switch strings.TrimSpace(component) {
|
||||
case TCPNetwork, UnixNetwork:
|
||||
network = component
|
||||
case HTTPProtocol, HTTPSProtocol, H2CProtocol:
|
||||
protocol = component
|
||||
default:
|
||||
err = fmt.Errorf(
|
||||
"component '%s' of scheme '%s' doesn't correspond to any "+
|
||||
"supported network or protocol, supported networks "+
|
||||
"are 'tcp' and 'unix', supported protocols are 'http', "+
|
||||
"'https' and 'h2c'",
|
||||
component, scheme,
|
||||
)
|
||||
return
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func checkNetwork(value string) error {
|
||||
switch value {
|
||||
case UnixNetwork, TCPNetwork:
|
||||
return nil
|
||||
default:
|
||||
return fmt.Errorf(
|
||||
"network '%s' isn't valid, valid values are 'unix' and 'tcp'",
|
||||
value,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
func checkProtocol(value string) error {
|
||||
switch value {
|
||||
case HTTPProtocol, HTTPSProtocol, H2CProtocol:
|
||||
return nil
|
||||
default:
|
||||
return fmt.Errorf(
|
||||
"protocol '%s' isn't valid, valid values are 'http', 'https' "+
|
||||
"and 'h2c'",
|
||||
value,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
// Network names:
|
||||
const (
|
||||
UnixNetwork = "unix"
|
||||
TCPNetwork = "tcp"
|
||||
)
|
||||
|
||||
// Protocol names:
|
||||
const (
|
||||
HTTPProtocol = "http"
|
||||
HTTPSProtocol = "https"
|
||||
H2CProtocol = "h2c"
|
||||
)
|
||||
32
vendor/github.com/openshift-online/ocm-sdk-go/internal/system_cas_other.go
generated
vendored
Normal file
32
vendor/github.com/openshift-online/ocm-sdk-go/internal/system_cas_other.go
generated
vendored
Normal file
|
|
@ -0,0 +1,32 @@
|
|||
// +build !windows
|
||||
|
||||
/*
|
||||
Copyright (c) 2021 Red Hat, Inc.
|
||||
|
||||
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.
|
||||
*/
|
||||
|
||||
// This file contains the function that returns the trusted CA certificates for operating systems
|
||||
// other than Windows, where Go knows how to load the system trusted CA store.
|
||||
|
||||
package internal
|
||||
|
||||
import (
|
||||
"crypto/x509"
|
||||
)
|
||||
|
||||
// loadSystemCAs loads the trusted CA certifites from the system trusted CA store.
|
||||
func loadSystemCAs() (pool *x509.CertPool, err error) {
|
||||
pool, err = x509.SystemCertPool()
|
||||
return
|
||||
}
|
||||
110
vendor/github.com/openshift-online/ocm-sdk-go/internal/system_cas_windows.go
generated
vendored
Normal file
110
vendor/github.com/openshift-online/ocm-sdk-go/internal/system_cas_windows.go
generated
vendored
Normal file
|
|
@ -0,0 +1,110 @@
|
|||
// +build windows
|
||||
|
||||
/*
|
||||
Copyright (c) 2021 Red Hat, Inc.
|
||||
|
||||
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.
|
||||
*/
|
||||
|
||||
// This file contains the function that returns the trusted CA certificates for Windows. This is
|
||||
// needed because currently Go doesn't know how to load the Windows trusted CA store. See the
|
||||
// following issues for more information:
|
||||
//
|
||||
// https://github.com/golang/go/issues/16736
|
||||
// https://github.com/golang/go/issues/18609
|
||||
|
||||
package internal
|
||||
|
||||
import (
|
||||
"crypto/x509"
|
||||
)
|
||||
|
||||
// loadSystemCAs loads the certificates of the CAs that we will trust. Currently this uses a fixed
|
||||
// set of CA certificates, which is obviusly going to break in the future, but there is not much we
|
||||
// can do (or know to do) till Go learns to read the Windows CA trust store.
|
||||
func loadSystemCAs() (pool *x509.CertPool, err error) {
|
||||
pool = x509.NewCertPool()
|
||||
pool.AppendCertsFromPEM(ssoCA)
|
||||
pool.AppendCertsFromPEM(apiCA)
|
||||
return
|
||||
}
|
||||
|
||||
// This certificate has been obtained with the following command:
|
||||
//
|
||||
// $ openssl s_client \
|
||||
// -connect sso.redhat.com:443 \
|
||||
// -showcerts
|
||||
var ssoCA = []byte(`
|
||||
-----BEGIN CERTIFICATE-----
|
||||
MIIEtjCCA56gAwIBAgIQDHmpRLCMEZUgkmFf4msdgzANBgkqhkiG9w0BAQsFADBs
|
||||
MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3
|
||||
d3cuZGlnaWNlcnQuY29tMSswKQYDVQQDEyJEaWdpQ2VydCBIaWdoIEFzc3VyYW5j
|
||||
ZSBFViBSb290IENBMB4XDTEzMTAyMjEyMDAwMFoXDTI4MTAyMjEyMDAwMFowdTEL
|
||||
MAkGA1UEBhMCVVMxFTATBgNVBAoTDERpZ2lDZXJ0IEluYzEZMBcGA1UECxMQd3d3
|
||||
LmRpZ2ljZXJ0LmNvbTE0MDIGA1UEAxMrRGlnaUNlcnQgU0hBMiBFeHRlbmRlZCBW
|
||||
YWxpZGF0aW9uIFNlcnZlciBDQTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoC
|
||||
ggEBANdTpARR+JmmFkhLZyeqk0nQOe0MsLAAh/FnKIaFjI5j2ryxQDji0/XspQUY
|
||||
uD0+xZkXMuwYjPrxDKZkIYXLBxA0sFKIKx9om9KxjxKws9LniB8f7zh3VFNfgHk/
|
||||
LhqqqB5LKw2rt2O5Nbd9FLxZS99RStKh4gzikIKHaq7q12TWmFXo/a8aUGxUvBHy
|
||||
/Urynbt/DvTVvo4WiRJV2MBxNO723C3sxIclho3YIeSwTQyJ3DkmF93215SF2AQh
|
||||
cJ1vb/9cuhnhRctWVyh+HA1BV6q3uCe7seT6Ku8hI3UarS2bhjWMnHe1c63YlC3k
|
||||
8wyd7sFOYn4XwHGeLN7x+RAoGTMCAwEAAaOCAUkwggFFMBIGA1UdEwEB/wQIMAYB
|
||||
Af8CAQAwDgYDVR0PAQH/BAQDAgGGMB0GA1UdJQQWMBQGCCsGAQUFBwMBBggrBgEF
|
||||
BQcDAjA0BggrBgEFBQcBAQQoMCYwJAYIKwYBBQUHMAGGGGh0dHA6Ly9vY3NwLmRp
|
||||
Z2ljZXJ0LmNvbTBLBgNVHR8ERDBCMECgPqA8hjpodHRwOi8vY3JsNC5kaWdpY2Vy
|
||||
dC5jb20vRGlnaUNlcnRIaWdoQXNzdXJhbmNlRVZSb290Q0EuY3JsMD0GA1UdIAQ2
|
||||
MDQwMgYEVR0gADAqMCgGCCsGAQUFBwIBFhxodHRwczovL3d3dy5kaWdpY2VydC5j
|
||||
b20vQ1BTMB0GA1UdDgQWBBQ901Cl1qCt7vNKYApl0yHU+PjWDzAfBgNVHSMEGDAW
|
||||
gBSxPsNpA/i/RwHUmCYaCALvY2QrwzANBgkqhkiG9w0BAQsFAAOCAQEAnbbQkIbh
|
||||
hgLtxaDwNBx0wY12zIYKqPBKikLWP8ipTa18CK3mtlC4ohpNiAexKSHc59rGPCHg
|
||||
4xFJcKx6HQGkyhE6V6t9VypAdP3THYUYUN9XR3WhfVUgLkc3UHKMf4Ib0mKPLQNa
|
||||
2sPIoc4sUqIAY+tzunHISScjl2SFnjgOrWNoPLpSgVh5oywM395t6zHyuqB8bPEs
|
||||
1OG9d4Q3A84ytciagRpKkk47RpqF/oOi+Z6Mo8wNXrM9zwR4jxQUezKcxwCmXMS1
|
||||
oVWNWlZopCJwqjyBcdmdqEU79OX2olHdx3ti6G8MdOu42vi/hw15UJGQmxg7kVkn
|
||||
8TUoE6smftX3eg==
|
||||
-----END CERTIFICATE-----
|
||||
`)
|
||||
|
||||
// This certificate has been obtained with the following command:
|
||||
//
|
||||
// $ openssl s_client \
|
||||
// -connect api.openshift.com:443 \
|
||||
// -showcerts
|
||||
var apiCA = []byte(`
|
||||
-----BEGIN CERTIFICATE-----
|
||||
MIIEZTCCA02gAwIBAgIQQAF1BIMUpMghjISpDBbN3zANBgkqhkiG9w0BAQsFADA/
|
||||
MSQwIgYDVQQKExtEaWdpdGFsIFNpZ25hdHVyZSBUcnVzdCBDby4xFzAVBgNVBAMT
|
||||
DkRTVCBSb290IENBIFgzMB4XDTIwMTAwNzE5MjE0MFoXDTIxMDkyOTE5MjE0MFow
|
||||
MjELMAkGA1UEBhMCVVMxFjAUBgNVBAoTDUxldCdzIEVuY3J5cHQxCzAJBgNVBAMT
|
||||
AlIzMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAuwIVKMz2oJTTDxLs
|
||||
jVWSw/iC8ZmmekKIp10mqrUrucVMsa+Oa/l1yKPXD0eUFFU1V4yeqKI5GfWCPEKp
|
||||
Tm71O8Mu243AsFzzWTjn7c9p8FoLG77AlCQlh/o3cbMT5xys4Zvv2+Q7RVJFlqnB
|
||||
U840yFLuta7tj95gcOKlVKu2bQ6XpUA0ayvTvGbrZjR8+muLj1cpmfgwF126cm/7
|
||||
gcWt0oZYPRfH5wm78Sv3htzB2nFd1EbjzK0lwYi8YGd1ZrPxGPeiXOZT/zqItkel
|
||||
/xMY6pgJdz+dU/nPAeX1pnAXFK9jpP+Zs5Od3FOnBv5IhR2haa4ldbsTzFID9e1R
|
||||
oYvbFQIDAQABo4IBaDCCAWQwEgYDVR0TAQH/BAgwBgEB/wIBADAOBgNVHQ8BAf8E
|
||||
BAMCAYYwSwYIKwYBBQUHAQEEPzA9MDsGCCsGAQUFBzAChi9odHRwOi8vYXBwcy5p
|
||||
ZGVudHJ1c3QuY29tL3Jvb3RzL2RzdHJvb3RjYXgzLnA3YzAfBgNVHSMEGDAWgBTE
|
||||
p7Gkeyxx+tvhS5B1/8QVYIWJEDBUBgNVHSAETTBLMAgGBmeBDAECATA/BgsrBgEE
|
||||
AYLfEwEBATAwMC4GCCsGAQUFBwIBFiJodHRwOi8vY3BzLnJvb3QteDEubGV0c2Vu
|
||||
Y3J5cHQub3JnMDwGA1UdHwQ1MDMwMaAvoC2GK2h0dHA6Ly9jcmwuaWRlbnRydXN0
|
||||
LmNvbS9EU1RST09UQ0FYM0NSTC5jcmwwHQYDVR0OBBYEFBQusxe3WFbLrlAJQOYf
|
||||
r52LFMLGMB0GA1UdJQQWMBQGCCsGAQUFBwMBBggrBgEFBQcDAjANBgkqhkiG9w0B
|
||||
AQsFAAOCAQEA2UzgyfWEiDcx27sT4rP8i2tiEmxYt0l+PAK3qB8oYevO4C5z70kH
|
||||
ejWEHx2taPDY/laBL21/WKZuNTYQHHPD5b1tXgHXbnL7KqC401dk5VvCadTQsvd8
|
||||
S8MXjohyc9z9/G2948kLjmE6Flh9dDYrVYA9x2O+hEPGOaEOa1eePynBgPayvUfL
|
||||
qjBstzLhWVQLGAkXXmNs+5ZnPBxzDJOLxhF2JIbeQAcH5H0tZrUlo5ZYyOqA7s9p
|
||||
O5b85o3AM/OJ+CktFBQtfvBhcJVd9wvlwPsk+uyOy2HI7mNxKKgsBTt375teA2Tw
|
||||
UdHkhVNcsAKX1H7GNNLOEADksd86wuoXvg==
|
||||
-----END CERTIFICATE-----
|
||||
`)
|
||||
175
vendor/github.com/openshift-online/ocm-sdk-go/logging/glog_logger.go
generated
vendored
Normal file
175
vendor/github.com/openshift-online/ocm-sdk-go/logging/glog_logger.go
generated
vendored
Normal file
|
|
@ -0,0 +1,175 @@
|
|||
/*
|
||||
Copyright (c) 2018 Red Hat, Inc.
|
||||
|
||||
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.
|
||||
*/
|
||||
|
||||
// This file contains a logger that uses the `glog` package.
|
||||
|
||||
package logging
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"os"
|
||||
|
||||
"github.com/golang/glog"
|
||||
)
|
||||
|
||||
// GlogLoggerBuilder contains the configuration and logic needed to build a logger that uses the
|
||||
// glog V mechanism. Don't create instances of this type directly, use the NewGlogLoggerBuilder
|
||||
// function instead.
|
||||
type GlogLoggerBuilder struct {
|
||||
debugV glog.Level
|
||||
infoV glog.Level
|
||||
warnV glog.Level
|
||||
errorV glog.Level
|
||||
}
|
||||
|
||||
// GlogLogger is a logger that uses the glog V mechanism.
|
||||
type GlogLogger struct {
|
||||
debugV glog.Level
|
||||
infoV glog.Level
|
||||
warnV glog.Level
|
||||
errorV glog.Level
|
||||
}
|
||||
|
||||
// NewGlogLoggerBuilder creates a builder that uses the glog V mechanism. By default errors,
|
||||
// warnings and information messages will be written to the log if the level is 0 or greater, and
|
||||
// debug messages will be written if the level is 1 or greater. This can be changed using the
|
||||
// ErrorV, WarnV, InfoV and DebugV methods of the builder. For example, to write errors and warnings
|
||||
// for level 0, information messages for level 1, and debug messages for level 2, you can create the
|
||||
// logger like this:
|
||||
//
|
||||
// logger, err := client.NewGlobLoggerBuilder().
|
||||
// ErrorV(0).
|
||||
// WarnV(0).
|
||||
// InfoV(1).
|
||||
// DebugV(2).
|
||||
// Build()
|
||||
//
|
||||
// Once the logger is created these settings can't be changed.
|
||||
func NewGlogLoggerBuilder() *GlogLoggerBuilder {
|
||||
// Allocate the object:
|
||||
builder := new(GlogLoggerBuilder)
|
||||
|
||||
// Set default values:
|
||||
builder.debugV = 1
|
||||
builder.infoV = 0
|
||||
builder.warnV = 0
|
||||
builder.errorV = 0
|
||||
|
||||
return builder
|
||||
}
|
||||
|
||||
// DebugV sets the V value that will be used for debug messages.
|
||||
func (b *GlogLoggerBuilder) DebugV(v glog.Level) *GlogLoggerBuilder {
|
||||
b.debugV = v
|
||||
return b
|
||||
}
|
||||
|
||||
// InfoV sets the V value that will be used for info messages.
|
||||
func (b *GlogLoggerBuilder) InfoV(v glog.Level) *GlogLoggerBuilder {
|
||||
b.infoV = v
|
||||
return b
|
||||
}
|
||||
|
||||
// WarnV sets the V value that will be used for warn messages.
|
||||
func (b *GlogLoggerBuilder) WarnV(v glog.Level) *GlogLoggerBuilder {
|
||||
b.warnV = v
|
||||
return b
|
||||
}
|
||||
|
||||
// ErrorV sets the V value that will be used for error messages.
|
||||
func (b *GlogLoggerBuilder) ErrorV(v glog.Level) *GlogLoggerBuilder {
|
||||
b.errorV = v
|
||||
return b
|
||||
}
|
||||
|
||||
// Build creates a new logger using the configuration stored in the builder.
|
||||
func (b *GlogLoggerBuilder) Build() (logger *GlogLogger, err error) {
|
||||
// Allocate and populate the object:
|
||||
logger = new(GlogLogger)
|
||||
logger.debugV = b.debugV
|
||||
logger.infoV = b.infoV
|
||||
logger.warnV = b.warnV
|
||||
logger.errorV = b.errorV
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
// DebugEnabled returns true iff the debug level is enabled.
|
||||
func (l *GlogLogger) DebugEnabled() bool {
|
||||
return bool(glog.V(l.debugV))
|
||||
}
|
||||
|
||||
// InfoEnabled returns true iff the information level is enabled.
|
||||
func (l *GlogLogger) InfoEnabled() bool {
|
||||
return bool(glog.V(l.infoV))
|
||||
}
|
||||
|
||||
// WarnEnabled returns true iff the warning level is enabled.
|
||||
func (l *GlogLogger) WarnEnabled() bool {
|
||||
return bool(glog.V(l.warnV))
|
||||
}
|
||||
|
||||
// ErrorEnabled returns true iff the error level is enabled.
|
||||
func (l *GlogLogger) ErrorEnabled() bool {
|
||||
return bool(glog.V(l.errorV))
|
||||
}
|
||||
|
||||
// Debug sends to the log a debug message formatted using the fmt.Sprintf function and the given
|
||||
// format and arguments.
|
||||
func (l *GlogLogger) Debug(ctx context.Context, format string, args ...interface{}) {
|
||||
if glog.V(l.debugV) {
|
||||
msg := fmt.Sprintf(format, args...)
|
||||
glog.InfoDepth(1, msg)
|
||||
}
|
||||
}
|
||||
|
||||
// Info sends to the log an information message formatted using the fmt.Sprintf function and the
|
||||
// given format and arguments.
|
||||
func (l *GlogLogger) Info(ctx context.Context, format string, args ...interface{}) {
|
||||
if glog.V(l.infoV) {
|
||||
msg := fmt.Sprintf(format, args...)
|
||||
glog.InfoDepth(1, msg)
|
||||
}
|
||||
}
|
||||
|
||||
// Warn sends to the log a warning message formatted using the fmt.Sprintf function and the given
|
||||
// format and arguments.
|
||||
func (l *GlogLogger) Warn(ctx context.Context, format string, args ...interface{}) {
|
||||
if glog.V(l.warnV) {
|
||||
msg := fmt.Sprintf(format, args...)
|
||||
glog.WarningDepth(1, msg)
|
||||
}
|
||||
}
|
||||
|
||||
// Error sends to the log an error message formatted using the fmt.Sprintf function and the given
|
||||
// format and arguments.
|
||||
func (l *GlogLogger) Error(ctx context.Context, format string, args ...interface{}) {
|
||||
if glog.V(l.errorV) {
|
||||
msg := fmt.Sprintf(format, args...)
|
||||
glog.ErrorDepth(1, msg)
|
||||
}
|
||||
}
|
||||
|
||||
// Fatal sends to the log an error message formatted using the fmt.Sprintf function and the given
|
||||
// format and arguments. After that it will os.Exit(1)
|
||||
// This level is always enabled
|
||||
func (l *GlogLogger) Fatal(ctx context.Context, format string, args ...interface{}) {
|
||||
msg := fmt.Sprintf(format, args...)
|
||||
// #nosec G104
|
||||
glog.ErrorDepth(1, msg)
|
||||
os.Exit(1)
|
||||
}
|
||||
165
vendor/github.com/openshift-online/ocm-sdk-go/logging/go_logger.go
generated
vendored
Normal file
165
vendor/github.com/openshift-online/ocm-sdk-go/logging/go_logger.go
generated
vendored
Normal file
|
|
@ -0,0 +1,165 @@
|
|||
/*
|
||||
Copyright (c) 2018 Red Hat, Inc.
|
||||
|
||||
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.
|
||||
*/
|
||||
|
||||
// This file contains a logger that uses the Go `log` package.
|
||||
|
||||
package logging
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"log"
|
||||
"os"
|
||||
)
|
||||
|
||||
// GoLoggerBuilder contains the configuration and logic needed to build a logger that uses the Go
|
||||
// `log` package. Don't create instances of this type directly, use the NewGoLoggerBuilder function
|
||||
// instead.
|
||||
type GoLoggerBuilder struct {
|
||||
debugEnabled bool
|
||||
infoEnabled bool
|
||||
warnEnabled bool
|
||||
errorEnabled bool
|
||||
}
|
||||
|
||||
// GoLogger is a logger that uses the Go `log` package.
|
||||
type GoLogger struct {
|
||||
debugEnabled bool
|
||||
infoEnabled bool
|
||||
warnEnabled bool
|
||||
errorEnabled bool
|
||||
}
|
||||
|
||||
// NewGoLoggerBuilder creates a builder that knows how to build a logger that uses the Go `log`
|
||||
// package. By default these loggers will have enabled the information, warning and error levels
|
||||
func NewGoLoggerBuilder() *GoLoggerBuilder {
|
||||
// Allocate the object:
|
||||
builder := new(GoLoggerBuilder)
|
||||
|
||||
// Set default values:
|
||||
builder.debugEnabled = false
|
||||
builder.infoEnabled = true
|
||||
builder.warnEnabled = true
|
||||
builder.errorEnabled = true
|
||||
|
||||
return builder
|
||||
}
|
||||
|
||||
// Debug enables or disables the debug level.
|
||||
func (b *GoLoggerBuilder) Debug(flag bool) *GoLoggerBuilder {
|
||||
b.debugEnabled = flag
|
||||
return b
|
||||
}
|
||||
|
||||
// Info enables or disables the information level.
|
||||
func (b *GoLoggerBuilder) Info(flag bool) *GoLoggerBuilder {
|
||||
b.infoEnabled = flag
|
||||
return b
|
||||
}
|
||||
|
||||
// Warn enables or disables the warning level.
|
||||
func (b *GoLoggerBuilder) Warn(flag bool) *GoLoggerBuilder {
|
||||
b.warnEnabled = flag
|
||||
return b
|
||||
}
|
||||
|
||||
// Error enables or disables the error level.
|
||||
func (b *GoLoggerBuilder) Error(flag bool) *GoLoggerBuilder {
|
||||
b.errorEnabled = flag
|
||||
return b
|
||||
}
|
||||
|
||||
// Build creates a new logger using the configuration stored in the builder.
|
||||
func (b *GoLoggerBuilder) Build() (logger *GoLogger, err error) {
|
||||
// Allocate and populate the object:
|
||||
logger = new(GoLogger)
|
||||
logger.debugEnabled = b.debugEnabled
|
||||
logger.infoEnabled = b.infoEnabled
|
||||
logger.warnEnabled = b.warnEnabled
|
||||
logger.errorEnabled = b.errorEnabled
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
// DebugEnabled returns true iff the debug level is enabled.
|
||||
func (l *GoLogger) DebugEnabled() bool {
|
||||
return l.debugEnabled
|
||||
}
|
||||
|
||||
// InfoEnabled returns true iff the information level is enabled.
|
||||
func (l *GoLogger) InfoEnabled() bool {
|
||||
return l.infoEnabled
|
||||
}
|
||||
|
||||
// WarnEnabled returns true iff the warning level is enabled.
|
||||
func (l *GoLogger) WarnEnabled() bool {
|
||||
return l.warnEnabled
|
||||
}
|
||||
|
||||
// ErrorEnabled returns true iff the error level is enabled.
|
||||
func (l *GoLogger) ErrorEnabled() bool {
|
||||
return l.errorEnabled
|
||||
}
|
||||
|
||||
// Debug sends to the log a debug message formatted using the fmt.Sprintf function and the given
|
||||
// format and arguments.
|
||||
func (l *GoLogger) Debug(ctx context.Context, format string, args ...interface{}) {
|
||||
if l.debugEnabled {
|
||||
msg := fmt.Sprintf(format, args...)
|
||||
// #nosec G104
|
||||
log.Output(1, msg)
|
||||
}
|
||||
}
|
||||
|
||||
// Info sends to the log an information message formatted using the fmt.Sprintf function and the
|
||||
// given format and arguments.
|
||||
func (l *GoLogger) Info(ctx context.Context, format string, args ...interface{}) {
|
||||
if l.infoEnabled {
|
||||
msg := fmt.Sprintf(format, args...)
|
||||
// #nosec G104
|
||||
log.Output(1, msg)
|
||||
}
|
||||
}
|
||||
|
||||
// Warn sends to the log a warning message formatted using the fmt.Sprintf function and the given
|
||||
// format and arguments.
|
||||
func (l *GoLogger) Warn(ctx context.Context, format string, args ...interface{}) {
|
||||
if l.warnEnabled {
|
||||
msg := fmt.Sprintf(format, args...)
|
||||
// #nosec G104
|
||||
log.Output(1, msg)
|
||||
}
|
||||
}
|
||||
|
||||
// Error sends to the log an error message formatted using the fmt.Sprintf function and the given
|
||||
// format and arguments.
|
||||
func (l *GoLogger) Error(ctx context.Context, format string, args ...interface{}) {
|
||||
if l.errorEnabled {
|
||||
msg := fmt.Sprintf(format, args...)
|
||||
// #nosec G104
|
||||
log.Output(1, msg)
|
||||
}
|
||||
}
|
||||
|
||||
// Fatal sends to the log an error message formatted using the fmt.Sprintf function and the given
|
||||
// format and arguments. After that it will os.Exit(1)
|
||||
// This level is always enabled
|
||||
func (l *GoLogger) Fatal(ctx context.Context, format string, args ...interface{}) {
|
||||
msg := fmt.Sprintf(format, args...)
|
||||
// #nosec G104
|
||||
log.Output(1, msg)
|
||||
os.Exit(1)
|
||||
}
|
||||
56
vendor/github.com/openshift-online/ocm-sdk-go/logging/list.go
generated
vendored
Normal file
56
vendor/github.com/openshift-online/ocm-sdk-go/logging/list.go
generated
vendored
Normal file
|
|
@ -0,0 +1,56 @@
|
|||
/*
|
||||
Copyright (c) 2021 Red Hat, Inc.
|
||||
|
||||
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.
|
||||
*/
|
||||
|
||||
// This file contains functions useful for printing lists in a format that is easy to read for
|
||||
// humans in log files.
|
||||
|
||||
package logging
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// All generates a human readable representation of the given list of strings, for use in a log
|
||||
// file. It puts quotes around each item, separates the first items with commas and the last with
|
||||
// the word 'and'.
|
||||
func All(items []string) string {
|
||||
return list(items, "and")
|
||||
}
|
||||
|
||||
// any generates a human readable representation of the given list of strings, for use in a log
|
||||
// file. It puts quotes around each item, separates the first items with commas and the last with
|
||||
// the word 'or'.
|
||||
func Any(items []string) string {
|
||||
return list(items, "or")
|
||||
}
|
||||
|
||||
func list(items []string, conjunction string) string {
|
||||
count := len(items)
|
||||
if count == 0 {
|
||||
return ""
|
||||
}
|
||||
quoted := make([]string, len(items))
|
||||
for i, item := range items {
|
||||
quoted[i] = fmt.Sprintf("'%s'", item)
|
||||
}
|
||||
if count == 1 {
|
||||
return quoted[0]
|
||||
}
|
||||
head := quoted[0 : count-1]
|
||||
tail := quoted[count-1]
|
||||
return fmt.Sprintf("%s %s %s", strings.Join(head, ", "), conjunction, tail)
|
||||
}
|
||||
65
vendor/github.com/openshift-online/ocm-sdk-go/logging/logger.go
generated
vendored
Normal file
65
vendor/github.com/openshift-online/ocm-sdk-go/logging/logger.go
generated
vendored
Normal file
|
|
@ -0,0 +1,65 @@
|
|||
/*
|
||||
Copyright (c) 2018 Red Hat, Inc.
|
||||
|
||||
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.
|
||||
*/
|
||||
|
||||
// This file contains the definition of the logger interface that is used by the client.
|
||||
|
||||
package logging
|
||||
|
||||
import (
|
||||
"context"
|
||||
)
|
||||
|
||||
// Logger is the interface that must be implemented by objects that are used for logging by the
|
||||
// client. By default the client uses a logger based on the `glog` package, but that can be changed
|
||||
// using the `Logger` method of the builder.
|
||||
//
|
||||
// Note that the context is optional in most of the methods of the SDK, so implementations of this
|
||||
// interface must accept and handle smoothly calls to the Debug, Info, Warn and Error methods where
|
||||
// the ctx parameter is nil.
|
||||
type Logger interface {
|
||||
// DebugEnabled returns true if the debug level is enabled.
|
||||
DebugEnabled() bool
|
||||
|
||||
// InfoEnabled returns true if the information level is enabled.
|
||||
InfoEnabled() bool
|
||||
|
||||
// WarnEnabled returns true if the warning level is enabled.
|
||||
WarnEnabled() bool
|
||||
|
||||
// ErrorEnabled returns true if the error level is enabled.
|
||||
ErrorEnabled() bool
|
||||
|
||||
// Debug sends to the log a debug message formatted using the fmt.Sprintf function and the
|
||||
// given format and arguments.
|
||||
Debug(ctx context.Context, format string, args ...interface{})
|
||||
|
||||
// Info sends to the log an information message formatted using the fmt.Sprintf function and
|
||||
// the given format and arguments.
|
||||
Info(ctx context.Context, format string, args ...interface{})
|
||||
|
||||
// Warn sends to the log a warning message formatted using the fmt.Sprintf function and the
|
||||
// given format and arguments.
|
||||
Warn(ctx context.Context, format string, args ...interface{})
|
||||
|
||||
// Error sends to the log an error message formatted using the fmt.Sprintf function and the
|
||||
// given format and arguments.
|
||||
Error(ctx context.Context, format string, args ...interface{})
|
||||
|
||||
// Fatal sends to the log an error message formatted using the fmt.Sprintf function and the
|
||||
// given format and arguments; and then executes an os.Exit(1)
|
||||
// Fatal level is always enabled
|
||||
Fatal(ctx context.Context, format string, args ...interface{})
|
||||
}
|
||||
175
vendor/github.com/openshift-online/ocm-sdk-go/logging/std_logger.go
generated
vendored
Normal file
175
vendor/github.com/openshift-online/ocm-sdk-go/logging/std_logger.go
generated
vendored
Normal file
|
|
@ -0,0 +1,175 @@
|
|||
/*
|
||||
Copyright (c) 2018 Red Hat, Inc.
|
||||
|
||||
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.
|
||||
*/
|
||||
|
||||
// This file contains a logger that uses the standard output and error streams, or custom writers.
|
||||
|
||||
package logging
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"io"
|
||||
"os"
|
||||
)
|
||||
|
||||
// StdLoggerBuilder contains the configuration and logic needed to build a logger that uses the
|
||||
// standard output and error streams, or custom writers.
|
||||
type StdLoggerBuilder struct {
|
||||
debugEnabled bool
|
||||
infoEnabled bool
|
||||
warnEnabled bool
|
||||
errorEnabled bool
|
||||
outStream io.Writer
|
||||
errStream io.Writer
|
||||
}
|
||||
|
||||
// StdLogger is a logger that uses the standard output and error streams, or custom writers.
|
||||
type StdLogger struct {
|
||||
debugEnabled bool
|
||||
infoEnabled bool
|
||||
warnEnabled bool
|
||||
errorEnabled bool
|
||||
outStream io.Writer
|
||||
errStream io.Writer
|
||||
}
|
||||
|
||||
// NewStdLoggerBuilder creates a builder that knows how to build a logger that uses the standard
|
||||
// output and error streams, or custom writers. By default these loggers will have enabled the
|
||||
// information, warning and error levels
|
||||
func NewStdLoggerBuilder() *StdLoggerBuilder {
|
||||
// Allocate the object:
|
||||
builder := new(StdLoggerBuilder)
|
||||
|
||||
// Set default values:
|
||||
builder.debugEnabled = false
|
||||
builder.infoEnabled = true
|
||||
builder.warnEnabled = true
|
||||
builder.errorEnabled = true
|
||||
|
||||
return builder
|
||||
}
|
||||
|
||||
// Streams sets the standard output and error streams to use. If not used then the logger will use
|
||||
// os.Stdout and os.Stderr.
|
||||
func (b *StdLoggerBuilder) Streams(out io.Writer, err io.Writer) *StdLoggerBuilder {
|
||||
b.outStream = out
|
||||
b.errStream = err
|
||||
return b
|
||||
}
|
||||
|
||||
// Debug enables or disables the debug level.
|
||||
func (b *StdLoggerBuilder) Debug(flag bool) *StdLoggerBuilder {
|
||||
b.debugEnabled = flag
|
||||
return b
|
||||
}
|
||||
|
||||
// Info enables or disables the information level.
|
||||
func (b *StdLoggerBuilder) Info(flag bool) *StdLoggerBuilder {
|
||||
b.infoEnabled = flag
|
||||
return b
|
||||
}
|
||||
|
||||
// Warn enables or disables the warning level.
|
||||
func (b *StdLoggerBuilder) Warn(flag bool) *StdLoggerBuilder {
|
||||
b.warnEnabled = flag
|
||||
return b
|
||||
}
|
||||
|
||||
// Error enables or disables the error level.
|
||||
func (b *StdLoggerBuilder) Error(flag bool) *StdLoggerBuilder {
|
||||
b.errorEnabled = flag
|
||||
return b
|
||||
}
|
||||
|
||||
// Build creates a new logger using the configuration stored in the builder.
|
||||
func (b *StdLoggerBuilder) Build() (logger *StdLogger, err error) {
|
||||
// Allocate and populate the object:
|
||||
logger = new(StdLogger)
|
||||
logger.debugEnabled = b.debugEnabled
|
||||
logger.infoEnabled = b.infoEnabled
|
||||
logger.warnEnabled = b.warnEnabled
|
||||
logger.errorEnabled = b.errorEnabled
|
||||
logger.outStream = b.outStream
|
||||
logger.errStream = b.errStream
|
||||
if logger.outStream == nil {
|
||||
logger.outStream = os.Stdout
|
||||
}
|
||||
if logger.errStream == nil {
|
||||
logger.errStream = os.Stderr
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
// DebugEnabled returns true iff the debug level is enabled.
|
||||
func (l *StdLogger) DebugEnabled() bool {
|
||||
return l.debugEnabled
|
||||
}
|
||||
|
||||
// InfoEnabled returns true iff the information level is enabled.
|
||||
func (l *StdLogger) InfoEnabled() bool {
|
||||
return l.infoEnabled
|
||||
}
|
||||
|
||||
// WarnEnabled returns true iff the warning level is enabled.
|
||||
func (l *StdLogger) WarnEnabled() bool {
|
||||
return l.warnEnabled
|
||||
}
|
||||
|
||||
// ErrorEnabled returns true iff the error level is enabled.
|
||||
func (l *StdLogger) ErrorEnabled() bool {
|
||||
return l.errorEnabled
|
||||
}
|
||||
|
||||
// Debug sends to the log a debug message formatted using the fmt.Sprintf function and the given
|
||||
// format and arguments.
|
||||
func (l *StdLogger) Debug(ctx context.Context, format string, args ...interface{}) {
|
||||
if l.debugEnabled {
|
||||
fmt.Fprintf(l.outStream, format+"\n", args...)
|
||||
}
|
||||
}
|
||||
|
||||
// Info sends to the log an information message formatted using the fmt.Sprintf function and the
|
||||
// given format and arguments.
|
||||
func (l *StdLogger) Info(ctx context.Context, format string, args ...interface{}) {
|
||||
if l.infoEnabled {
|
||||
fmt.Fprintf(l.outStream, format+"\n", args...)
|
||||
}
|
||||
}
|
||||
|
||||
// Warn sends to the log a warning message formatted using the fmt.Sprintf function and the given
|
||||
// format and arguments.
|
||||
func (l *StdLogger) Warn(ctx context.Context, format string, args ...interface{}) {
|
||||
if l.warnEnabled {
|
||||
fmt.Fprintf(l.outStream, format+"\n", args...)
|
||||
}
|
||||
}
|
||||
|
||||
// Error sends to the log an error message formatted using the fmt.Sprintf function and the given
|
||||
// format and arguments.
|
||||
func (l *StdLogger) Error(ctx context.Context, format string, args ...interface{}) {
|
||||
if l.errorEnabled {
|
||||
fmt.Fprintf(l.errStream, format+"\n", args...)
|
||||
}
|
||||
}
|
||||
|
||||
// Fatal sends to the log an error message formatted using the fmt.Sprintf function and the given
|
||||
// format and arguments. After that it will os.Exit(1)
|
||||
// This level is always enabled
|
||||
func (l *StdLogger) Fatal(ctx context.Context, format string, args ...interface{}) {
|
||||
fmt.Fprintf(l.errStream, format+"\n", args...)
|
||||
os.Exit(1)
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue