add service mesh controller

add service mesh metrics

remove unused circle yaml

fix travis misconfiguration

fix travis misconfiguration

fix travis misconfiguration
This commit is contained in:
jeff
2019-03-08 18:22:30 +08:00
committed by Jeff
parent 858facd4b2
commit 4ac20ffc2b
1709 changed files with 344390 additions and 60749 deletions

3
.gitmodules vendored Normal file
View File

@@ -0,0 +1,3 @@
[submodule "vendor/github.com/knative/pkg"]
path = vendor/github.com/knative/pkg
url = https://github.com/knative/pkg.git

View File

@@ -12,19 +12,19 @@ go:
go_import_path: kubesphere.io/kubesphere
before_install:
- curl https://raw.githubusercontent.com/golang/dep/master/install.sh | sh
- go get -u github.com/golang/dep/cmd/dep
before_script:
- dep ensure -v
- docker --version
- bash hack/install_kubebuilder.sh
script:
- make test
- bash hack/docker_build.sh
- make all && make test && bash hack/docker_build.sh
deploy:
skip_cleanup: true
provider: script
script: bash hack/docker_push.sh
on:
branch: master
branch: master

768
Gopkg.lock generated

File diff suppressed because it is too large Load Diff

View File

@@ -1,93 +1,68 @@
# Gopkg.toml example
#
# Refer to https://github.com/golang/dep/blob/master/docs/Gopkg.toml.md
# for detailed Gopkg.toml documentation.
#
# required = ["github.com/user/thing/cmd/thing"]
# ignored = ["github.com/user/project/pkgX", "bitbucket.org/user/project/pkgA/pkgY"]
#
# [[constraint]]
# name = "github.com/user/project"
# version = "1.0.0"
#
# [[constraint]]
# name = "github.com/user/project2"
# branch = "dev"
# source = "github.com/myfork/project2"
#
# [[override]]
# name = "github.com/x/y"
# version = "2.4.0"
#
# [prune]
# non-go = false
# go-tests = true
# unused-packages = true
required = [
"github.com/emicklei/go-restful",
"github.com/onsi/ginkgo", # for test framework
"github.com/onsi/gomega", # for test matchers
"k8s.io/gengo/examples/defaulter-gen/generators",
"k8s.io/gengo/examples/deepcopy-gen/generators",
"k8s.io/client-go/plugin/pkg/client/auth/gcp", # for development against gcp
"k8s.io/code-generator/cmd/client-gen",
"sigs.k8s.io/controller-tools/cmd/controller-gen", # for crd/rbac generation
"sigs.k8s.io/controller-runtime/pkg/client/config",
"sigs.k8s.io/controller-runtime/pkg/controller",
"sigs.k8s.io/controller-runtime/pkg/handler",
"sigs.k8s.io/controller-runtime/pkg/manager",
"sigs.k8s.io/controller-runtime/pkg/runtime/signals",
"sigs.k8s.io/controller-runtime/pkg/source",
"sigs.k8s.io/testing_frameworks/integration", # for integration testing
"k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1beta1",
]
[[constraint]]
name = "github.com/docker/docker"
version = "v17.05.0-ce"
[[constraint]]
name = "github.com/emicklei/go-restful"
version = "2.7.1"
[[constraint]]
name = "github.com/emicklei/go-restful-swagger12"
version = "1.0.1"
[[constraint]]
branch = "master"
name = "github.com/golang/glog"
[[constraint]]
name = "github.com/spf13/pflag"
version = "1.0.1"
[[override]]
name = "k8s.io/api"
version = "kubernetes-1.13.1"
[[override]]
name = "gopkg.in/igm/sockjs-go.v2"
version = "2.0.0"
[[constraint]]
name = "gopkg.in/yaml.v2"
version = "2.2.1"
[[constraint]]
name = "k8s.io/api"
version = "kubernetes-1.12.3"
[[constraint]]
name = "k8s.io/apimachinery"
version = "kubernetes-1.12.3"
version = "kubernetes-1.13.1"
[[constraint]]
name = "k8s.io/code-generator"
version = "kubernetes-1.13.1"
[[override]]
name = "k8s.io/client-go"
version = "kubernetes-1.12.3"
version = "kubernetes-1.13.1"
[[constraint]]
name = "k8s.io/kubernetes"
version = "1.12.3"
version = "1.13.1"
[[constraint]]
name = "github.com/mholt/caddy"
version = "v0.11.5"
name="sigs.k8s.io/controller-runtime"
version="v0.1.7"
[[constraint]]
name = "sigs.k8s.io/controller-runtime"
version = "v0.1.9"
name="sigs.k8s.io/controller-tools"
version="v0.1.7"
[[override]]
name = "sigs.k8s.io/controller-tools"
version = "v0.1.9"
[[override]]
name = "k8s.io/component-base"
branch = "master"
name="github.com/bifurcation/mint"
revision="824af65410658916142a7600349144e1289f2110"
[prune]
go-tests = true
unused-packages = true
non-go = true
[[prune.project]]
name = "k8s.io/code-generator"
unused-packages = false
non-go = false
# To use reference package:
# vendor/github.com/docker/docker/client/container_commit.go:17: undefined: reference.ParseNormalizedNamed
@@ -106,20 +81,24 @@
name = "github.com/docker/go-connections"
branch = "master"
# To use reference package:
# vendor/k8s.io/apimachinery/pkg/runtime/serializer/json/json.go:104:3: unknown field 'CaseSensitive' in struct literal of type jsoniter.Config
[[override]]
name = "github.com/json-iterator/go"
branch = "master"
# For dependency below: Refer to issue https://github.com/golang/dep/issues/1799
[[override]]
name = "gopkg.in/fsnotify.v1"
source = "https://github.com/fsnotify/fsnotify.git"
version = "v1.4.7"
[[override]]
name = "github.com/russross/blackfriday"
version = "v1.5.2"
version = "v1.5.2"
[[constraint]]
branch = "master"
name = "sigs.k8s.io/application"
[[constraint]]
name = "github.com/kiali/kiali"
version = "0.15.0"
[[constraint]]
name = "github.com/gorilla/mux"
version = "1.7.0"

View File

@@ -8,18 +8,6 @@ BIN ?= ks-apiserver
IMG ?= kubespheredev/ks-apiserver
OUTPUT_DIR=bin
define get_diff_files
$(eval DIFF_FILES=$(shell git diff --name-only --diff-filter=ad | grep -E "^(test|cmd|pkg)/.+\.go"))
endef
define get_build_flags
$(eval SHORT_VERSION=$(shell git describe --tags --always --dirty="-dev"))
$(eval SHA1_VERSION=$(shell git show --quiet --pretty=format:%H))
$(eval DATE=$(shell date +'%Y-%m-%dT%H:%M:%S'))
$(eval BUILD_FLAG= -X $(TRAG.Version).ShortVersion="$(SHORT_VERSION)" \
-X $(TRAG.Version).GitSha1Version="$(SHA1_VERSION)" \
-X $(TRAG.Version).BuildDate="$(DATE)")
endef
define ALL_HELP_INFO
# Build code.
#
@@ -62,6 +50,18 @@ fmt:
vet:
go vet ./pkg/... ./cmd/...
# Generate manifests e.g. CRD, RBAC etc.
manifests:
go run vendor/sigs.k8s.io/controller-tools/cmd/controller-gen/main.go all
deploy: manifests
kubectl apply -f config/crds
kustomize build config/default | kubectl apply -f -
# Generate DeepCopy to implement runtime.Object
deepcopy:
./vendor/k8s.io/code-generator/generate-groups.sh deepcopy kubesphere.io/kubesphere/pkg/client kubesphere.io/kubesphere/pkg/apis "servicemesh:v1alpha2"
# Generate code
generate:
ifndef GOPATH

View File

@@ -0,0 +1,18 @@
# Copyright 2018 The KubeSphere Authors. All rights reserved.
# Use of this source code is governed by a Apache license
# that can be found in the LICENSE file.
# Copyright 2018 The KubeSphere Authors. All rights reserved.
# Use of this source code is governed by a Apache license
# that can be found in the LICENSE file.
FROM golang:1.10.3 as controller-manager-builder
COPY / /go/src/kubesphere.io/kubesphere
WORKDIR /go/src/kubesphere.io/kubesphere
RUN GOOS=linux GOARCH=amd64 CGO_ENABLED=0 go build --ldflags "-extldflags -static" -o controller-manager ./cmd/controller-manager/
FROM alpine:3.7
RUN apk add --update ca-certificates && update-ca-certificates
COPY --from=controller-manager-builder /go/src/kubesphere.io/kubesphere/controller-manager /usr/local/bin/
CMD controller-manager

View File

@@ -20,11 +20,14 @@ package main
import (
"flag"
"os"
"sigs.k8s.io/application/pkg/apis/app/v1beta1"
_ "k8s.io/client-go/plugin/pkg/client/auth/gcp"
"kubesphere.io/kubesphere/pkg/informers"
"kubesphere.io/kubesphere/pkg/simple/client/k8s"
"kubesphere.io/kubesphere/pkg/simple/controller/namespace"
"os"
"sigs.k8s.io/controller-runtime/pkg/manager"
logf "sigs.k8s.io/controller-runtime/pkg/runtime/log"
"sigs.k8s.io/controller-runtime/pkg/runtime/signals"
@@ -66,6 +69,13 @@ func main() {
os.Exit(1)
}
log.Info("Print all known types")
for k, v := range mgr.GetScheme().AllKnownTypes() {
if k.Group == v1beta1.SchemeGroupVersion.Group {
log.Info(k.String() + " / " + v.String())
}
}
// Setup all Controllers
log.Info("Setting up controller")
if err := controller.AddToManager(mgr); err != nil {

View File

@@ -25,6 +25,7 @@ import (
_ "kubesphere.io/kubesphere/pkg/apis/monitoring/install"
_ "kubesphere.io/kubesphere/pkg/apis/operations/install"
_ "kubesphere.io/kubesphere/pkg/apis/resources/install"
_ "kubesphere.io/kubesphere/pkg/apis/servicemesh/metrics/install"
)
func main() {

View File

@@ -0,0 +1,30 @@
package options
import (
"github.com/spf13/pflag"
genericoptions "kubesphere.io/kubesphere/pkg/options"
)
type ServerRunOptions struct {
GenericServerRunOptions *genericoptions.ServerRunOptions
// istio pilot discovery service url
IstioPilotServiceURL string
}
func NewServerRunOptions() *ServerRunOptions {
s := ServerRunOptions{
GenericServerRunOptions: genericoptions.NewServerRunOptions(),
IstioPilotServiceURL: "http://istio-pilot.istio-system.svc:8080/version",
}
return &s
}
func (s *ServerRunOptions) AddFlags(fs *pflag.FlagSet) {
s.GenericServerRunOptions.AddFlags(fs)
fs.StringVar(&s.IstioPilotServiceURL, "istio-pilot-service-url", "http://istio-pilot.istio-system.svc:8080/version", "istio pilot discovery service url")
}

View File

@@ -21,18 +21,22 @@ import (
goflag "flag"
"fmt"
"github.com/golang/glog"
kconfig "github.com/kiali/kiali/config"
"github.com/spf13/cobra"
"github.com/spf13/pflag"
"kubesphere.io/kubesphere/cmd/ks-apiserver/app/options"
"kubesphere.io/kubesphere/pkg/apiserver/runtime"
"kubesphere.io/kubesphere/pkg/filter"
"kubesphere.io/kubesphere/pkg/informers"
"kubesphere.io/kubesphere/pkg/options"
"kubesphere.io/kubesphere/pkg/signals"
"kubesphere.io/kubesphere/pkg/simple/client/prometheus"
"log"
"net/http"
"net/url"
)
func NewAPIServerCommand() *cobra.Command {
s := options.SharedOptions
s := options.NewServerRunOptions()
cmd := &cobra.Command{
Use: "ks-apiserver",
@@ -44,14 +48,19 @@ cluster's shared state through which all other components interact.`,
},
}
cmd.Flags().AddFlagSet(s.CommandLine)
s.AddFlags(cmd.Flags())
cmd.Flags().AddGoFlagSet(goflag.CommandLine)
glog.CopyStandardLogTo("INFO")
return cmd
}
func Run(s *options.ServerRunOptions) error {
pflag.VisitAll(func(flag *pflag.Flag) {
log.Printf("FLAG: --%s=%q", flag.Name, flag.Value)
})
var err error
waitForResourceSync()
@@ -59,19 +68,55 @@ func Run(s *options.ServerRunOptions) error {
container := runtime.Container
container.Filter(filter.Logging)
log.Printf("Server listening on %d.", s.InsecurePort)
log.Printf("Server listening on %d.", s.GenericServerRunOptions.InsecurePort)
if s.InsecurePort != 0 {
err = http.ListenAndServe(fmt.Sprintf("%s:%d", s.BindAddress, s.InsecurePort), container)
for _, webservice := range container.RegisteredWebServices() {
for _, route := range webservice.Routes() {
log.Printf(route.Path)
}
}
if s.SecurePort != 0 && len(s.TlsCertFile) > 0 && len(s.TlsPrivateKey) > 0 {
err = http.ListenAndServeTLS(fmt.Sprintf("%s:%d", s.BindAddress, s.SecurePort), s.TlsCertFile, s.TlsPrivateKey, container)
initializeKialiConfig(s)
if s.GenericServerRunOptions.InsecurePort != 0 {
err = http.ListenAndServe(fmt.Sprintf("%s:%d", s.GenericServerRunOptions.BindAddress, s.GenericServerRunOptions.InsecurePort), container)
}
if s.GenericServerRunOptions.SecurePort != 0 && len(s.GenericServerRunOptions.TlsCertFile) > 0 && len(s.GenericServerRunOptions.TlsPrivateKey) > 0 {
err = http.ListenAndServeTLS(fmt.Sprintf("%s:%d", s.GenericServerRunOptions.BindAddress, s.GenericServerRunOptions.SecurePort), s.GenericServerRunOptions.TlsCertFile, s.GenericServerRunOptions.TlsPrivateKey, container)
}
return err
}
func initializeKialiConfig(s *options.ServerRunOptions) {
// Initialize kiali config
config := kconfig.NewConfig()
// Exclude system namespaces
config.API.Namespaces.Exclude = []string{"istio-system", "kubesphere*", "kube*"}
config.InCluster = false
// Set default prometheus service url
config.ExternalServices.PrometheusServiceURL = "http://prometheus.kubesphere-monitoring-system.svc:9090"
// ugly hack to get prometheus service url
if pflag.Parsed() && pflag.Lookup("prometheus-endpoint") != nil {
// Set prometheus
endpoint, err := url.Parse(prometheus.PrometheusAPIEndpoint)
if err != nil {
config.ExternalServices.PrometheusServiceURL = endpoint.Path
}
}
config.ExternalServices.PrometheusCustomMetricsURL = config.ExternalServices.PrometheusServiceURL
// Set istio pilot discovery service url
config.ExternalServices.Istio.UrlServiceVersion = s.IstioPilotServiceURL
kconfig.Set(config)
}
func waitForResourceSync() {
stopChan := signals.SetupSignalHandler()

View File

@@ -0,0 +1,22 @@
package options
import (
"github.com/spf13/pflag"
genericoptions "kubesphere.io/kubesphere/pkg/options"
)
type ServerRunOptions struct {
GenericServerRunOptions *genericoptions.ServerRunOptions
}
func NewServerRunOptions() *ServerRunOptions {
s := &ServerRunOptions{
GenericServerRunOptions: genericoptions.NewServerRunOptions(),
}
return s
}
func (s *ServerRunOptions) AddFlags(fs *pflag.FlagSet) {
s.GenericServerRunOptions.AddFlags(fs)
}

View File

@@ -22,18 +22,19 @@ import (
"fmt"
"github.com/golang/glog"
"github.com/spf13/cobra"
"github.com/spf13/pflag"
"kubesphere.io/kubesphere/cmd/ks-iam/app/options"
"kubesphere.io/kubesphere/pkg/apiserver/runtime"
"kubesphere.io/kubesphere/pkg/filter"
"kubesphere.io/kubesphere/pkg/informers"
"kubesphere.io/kubesphere/pkg/models/iam"
"kubesphere.io/kubesphere/pkg/options"
"kubesphere.io/kubesphere/pkg/signals"
"log"
"net/http"
)
func NewAPIServerCommand() *cobra.Command {
s := options.SharedOptions
s := options.NewServerRunOptions()
cmd := &cobra.Command{
Use: "ks-iam",
@@ -44,14 +45,19 @@ cluster's shared state through which all other components interact.`,
return Run(s)
},
}
cmd.Flags().AddFlagSet(s.CommandLine)
s.AddFlags(cmd.Flags())
cmd.Flags().AddGoFlagSet(goflag.CommandLine)
glog.CopyStandardLogTo("INFO")
return cmd
}
func Run(s *options.ServerRunOptions) error {
pflag.VisitAll(func(flag *pflag.Flag) {
log.Printf("FLAG: --%s=%q", flag.Name, flag.Value)
})
var err error
err = iam.DatabaseInit()
@@ -65,14 +71,12 @@ func Run(s *options.ServerRunOptions) error {
container := runtime.Container
container.Filter(filter.Logging)
log.Printf("Server listening on %d.", s.InsecurePort)
if s.InsecurePort != 0 {
err = http.ListenAndServe(fmt.Sprintf("%s:%d", s.BindAddress, s.InsecurePort), container)
if s.GenericServerRunOptions.InsecurePort != 0 {
err = http.ListenAndServe(fmt.Sprintf("%s:%d", s.GenericServerRunOptions.BindAddress, s.GenericServerRunOptions.InsecurePort), container)
}
if s.SecurePort != 0 && len(s.TlsCertFile) > 0 && len(s.TlsPrivateKey) > 0 {
err = http.ListenAndServeTLS(fmt.Sprintf("%s:%d", s.BindAddress, s.SecurePort), s.TlsCertFile, s.TlsPrivateKey, container)
if s.GenericServerRunOptions.SecurePort != 0 && len(s.GenericServerRunOptions.TlsCertFile) > 0 && len(s.GenericServerRunOptions.TlsPrivateKey) > 0 {
err = http.ListenAndServeTLS(fmt.Sprintf("%s:%d", s.GenericServerRunOptions.BindAddress, s.GenericServerRunOptions.SecurePort), s.GenericServerRunOptions.TlsCertFile, s.GenericServerRunOptions.TlsPrivateKey, container)
}
return err

View File

@@ -0,0 +1,239 @@
apiVersion: apiextensions.k8s.io/v1beta1
kind: CustomResourceDefinition
metadata:
creationTimestamp: null
labels:
controller-tools.k8s.io: "1.0"
name: applications.app.k8s.io
spec:
group: app.k8s.io
names:
kind: Application
plural: applications
scope: Namespaced
validation:
openAPIV3Schema:
properties:
apiVersion:
type: string
kind:
type: string
metadata:
type: object
spec:
properties:
assemblyPhase:
type: string
componentKinds:
items:
type: object
type: array
descriptor:
properties:
description:
type: string
icons:
items:
properties:
size:
type: string
src:
type: string
type:
type: string
required:
- src
type: object
type: array
keywords:
items:
type: string
type: array
links:
items:
properties:
description:
type: string
url:
type: string
type: object
type: array
maintainers:
items:
properties:
email:
type: string
name:
type: string
url:
type: string
type: object
type: array
notes:
type: string
owners:
items:
properties:
email:
type: string
name:
type: string
url:
type: string
type: object
type: array
type:
type: string
version:
type: string
type: object
info:
items:
properties:
name:
type: string
type:
type: string
value:
type: string
valueFrom:
properties:
configMapKeyRef:
properties:
apiVersion:
type: string
fieldPath:
type: string
key:
type: string
kind:
type: string
name:
type: string
namespace:
type: string
resourceVersion:
type: string
uid:
type: string
type: object
ingressRef:
properties:
apiVersion:
type: string
fieldPath:
type: string
host:
type: string
kind:
type: string
name:
type: string
namespace:
type: string
path:
type: string
resourceVersion:
type: string
uid:
type: string
type: object
secretKeyRef:
properties:
apiVersion:
type: string
fieldPath:
type: string
key:
type: string
kind:
type: string
name:
type: string
namespace:
type: string
resourceVersion:
type: string
uid:
type: string
type: object
serviceRef:
properties:
apiVersion:
type: string
fieldPath:
type: string
kind:
type: string
name:
type: string
namespace:
type: string
path:
type: string
port:
format: int32
type: integer
resourceVersion:
type: string
uid:
type: string
type: object
type:
type: string
type: object
type: object
type: array
selector:
type: object
type: object
status:
properties:
components:
items:
properties:
group:
type: string
kind:
type: string
link:
type: string
name:
type: string
status:
type: string
type: object
type: array
conditions:
items:
properties:
lastTransitionTime:
format: date-time
type: string
lastUpdateTime:
format: date-time
type: string
message:
type: string
reason:
type: string
status:
type: string
type:
type: string
required:
- type
- status
type: object
type: array
observedGeneration:
format: int64
type: integer
type: object
version: v1beta1
status:
acceptedNames:
kind: ""
plural: ""
conditions: []
storedVersions: []

1116
config/crds/istio-crds.yaml Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,763 @@
apiVersion: apiextensions.k8s.io/v1beta1
kind: CustomResourceDefinition
metadata:
creationTimestamp: null
labels:
controller-tools.k8s.io: "1.0"
name: destinationrules.istio.kubesphere.io
spec:
group: istio.kubesphere.io
names:
kind: DestinationRule
plural: destinationrules
scope: Namespaced
validation:
openAPIV3Schema:
properties:
apiVersion:
description: 'APIVersion defines the versioned schema of this representation
of an object. Servers should convert recognized schemas to the latest
internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/api-conventions.md#resources'
type: string
kind:
description: 'Kind is a string value representing the REST resource this
object represents. Servers may infer this from the endpoint the client
submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/api-conventions.md#types-kinds'
type: string
metadata:
type: object
spec:
properties:
host:
description: 'REQUIRED. The name of a service from the service registry.
Service names are looked up from the platform''s service registry
(e.g., Kubernetes services, Consul services, etc.) and from the hosts
declared by [ServiceEntries](#ServiceEntry). Rules defined for services
that do not exist in the service registry will be ignored. *Note
for Kubernetes users*: When short names are used (e.g. "reviews" instead
of "reviews.default.svc.cluster.local"), Istio will interpret the
short name based on the namespace of the rule, not the service. A
rule in the "default" namespace containing a host "reviews will be
interpreted as "reviews.default.svc.cluster.local", irrespective of
the actual namespace associated with the reviews service. _To avoid
potential misconfigurations, it is recommended to always use fully
qualified domain names over short names._ Note that the host field
applies to both HTTP and TCP services.'
type: string
subsets:
description: One or more named sets that represent individual versions
of a service. Traffic policies can be overridden at subset level.
items:
properties:
labels:
description: REQUIRED. Labels apply a filter over the endpoints
of a service in the service registry. See route rules for examples
of usage.
type: object
name:
description: REQUIRED. Name of the subset. The service name and
the subset name can be used for traffic splitting in a route
rule.
type: string
trafficPolicy:
description: Traffic policies that apply to this subset. Subsets
inherit the traffic policies specified at the DestinationRule
level. Settings specified at the subset level will override
the corresponding settings specified at the DestinationRule
level.
properties:
connectionPool:
description: Settings controlling the volume of connections
to an upstream service
properties:
http:
description: HTTP connection pool settings.
properties:
maxRequestsPerConnection:
description: Maximum number of requests per connection
to a backend. Setting this parameter to 1 disables
keep alive.
format: int32
type: integer
maxRetries:
description: Maximum number of retries that can be
outstanding to all hosts in a cluster at a given
time. Defaults to 3.
format: int32
type: integer
type: object
tcp:
description: Settings common to both HTTP and TCP upstream
connections.
properties:
connectTimeout:
description: TCP connection timeout.
type: string
maxConnections:
description: Maximum number of HTTP1 /TCP connections
to a destination host.
format: int32
type: integer
type: object
type: object
loadBalancer:
description: Settings controlling the load balancer algorithms.
properties:
consistentHash:
properties:
httpCookie:
description: Hash based on HTTP cookie.
properties:
name:
description: REQUIRED. Name of the cookie.
type: string
path:
description: Path to set for the cookie.
type: string
ttl:
description: REQUIRED. Lifetime of the cookie.
type: string
required:
- name
- ttl
type: object
httpHeaderName:
description: 'It is required to specify exactly one
of the fields as hash key: HttpHeaderName, HttpCookie,
or UseSourceIP. Hash based on a specific HTTP header.'
type: string
minimumRingSize:
description: The minimum number of virtual nodes to
use for the hash ring. Defaults to 1024. Larger
ring sizes result in more granular load distributions.
If the number of hosts in the load balancing pool
is larger than the ring size, each host will be
assigned a single virtual node.
format: int64
type: integer
useSourceIp:
description: Hash based on the source IP address.
type: boolean
type: object
simple:
description: 'It is required to specify exactly one of
the fields: Simple or ConsistentHash'
type: string
type: object
outlierDetection:
description: Settings controlling eviction of unhealthy hosts
from the load balancing pool
properties:
baseEjectionTime:
description: 'Minimum ejection duration. A host will remain
ejected for a period equal to the product of minimum
ejection duration and the number of times the host has
been ejected. This technique allows the system to automatically
increase the ejection period for unhealthy upstream
servers. format: 1h/1m/1s/1ms. MUST BE >=1ms. Default
is 30s.'
type: string
consecutiveErrors:
description: Number of errors before a host is ejected
from the connection pool. Defaults to 5. When the upstream
host is accessed over HTTP, a 5xx return code qualifies
as an error. When the upstream host is accessed over
an opaque TCP connection, connect timeouts and connection
error/failure events qualify as an error.
format: int32
type: integer
interval:
description: 'Time interval between ejection sweep analysis.
format: 1h/1m/1s/1ms. MUST BE >=1ms. Default is 10s.'
type: string
maxEjectionPercent:
description: Maximum % of hosts in the load balancing
pool for the upstream service that can be ejected. Defaults
to 10%.
format: int32
type: integer
type: object
portLevelSettings:
description: Traffic policies specific to individual ports.
Note that port level settings will override the destination-level
settings. Traffic settings specified at the destination-level
will not be inherited when overridden by port-level settings,
i.e. default values will be applied to fields omitted in
port-level traffic policies.
items:
properties:
connectionPool:
description: Settings controlling the volume of connections
to an upstream service
properties:
http:
description: HTTP connection pool settings.
properties:
maxRequestsPerConnection:
description: Maximum number of requests per
connection to a backend. Setting this parameter
to 1 disables keep alive.
format: int32
type: integer
maxRetries:
description: Maximum number of retries that
can be outstanding to all hosts in a cluster
at a given time. Defaults to 3.
format: int32
type: integer
type: object
tcp:
description: Settings common to both HTTP and TCP
upstream connections.
properties:
connectTimeout:
description: TCP connection timeout.
type: string
maxConnections:
description: Maximum number of HTTP1 /TCP connections
to a destination host.
format: int32
type: integer
type: object
type: object
loadBalancer:
description: Settings controlling the load balancer
algorithms.
properties:
consistentHash:
properties:
httpCookie:
description: Hash based on HTTP cookie.
properties:
name:
description: REQUIRED. Name of the cookie.
type: string
path:
description: Path to set for the cookie.
type: string
ttl:
description: REQUIRED. Lifetime of the cookie.
type: string
required:
- name
- ttl
type: object
httpHeaderName:
description: 'It is required to specify exactly
one of the fields as hash key: HttpHeaderName,
HttpCookie, or UseSourceIP. Hash based on
a specific HTTP header.'
type: string
minimumRingSize:
description: The minimum number of virtual nodes
to use for the hash ring. Defaults to 1024.
Larger ring sizes result in more granular
load distributions. If the number of hosts
in the load balancing pool is larger than
the ring size, each host will be assigned
a single virtual node.
format: int64
type: integer
useSourceIp:
description: Hash based on the source IP address.
type: boolean
type: object
simple:
description: 'It is required to specify exactly
one of the fields: Simple or ConsistentHash'
type: string
type: object
outlierDetection:
description: Settings controlling eviction of unhealthy
hosts from the load balancing pool
properties:
baseEjectionTime:
description: 'Minimum ejection duration. A host
will remain ejected for a period equal to the
product of minimum ejection duration and the number
of times the host has been ejected. This technique
allows the system to automatically increase the
ejection period for unhealthy upstream servers.
format: 1h/1m/1s/1ms. MUST BE >=1ms. Default is
30s.'
type: string
consecutiveErrors:
description: Number of errors before a host is ejected
from the connection pool. Defaults to 5. When
the upstream host is accessed over HTTP, a 5xx
return code qualifies as an error. When the upstream
host is accessed over an opaque TCP connection,
connect timeouts and connection error/failure
events qualify as an error.
format: int32
type: integer
interval:
description: 'Time interval between ejection sweep
analysis. format: 1h/1m/1s/1ms. MUST BE >=1ms.
Default is 10s.'
type: string
maxEjectionPercent:
description: Maximum % of hosts in the load balancing
pool for the upstream service that can be ejected.
Defaults to 10%.
format: int32
type: integer
type: object
port:
description: Specifies the port name or number of a
port on the destination service on which this policy
is being applied. Names must comply with DNS label
syntax (rfc1035) and therefore cannot collide with
numbers. If there are multiple ports on a service
with the same protocol the names should be of the
form <protocol-name>-<DNS label>.
properties:
name:
description: Valid port name
type: string
number:
description: Valid port number
format: int32
type: integer
type: object
tls:
description: TLS related settings for connections to
the upstream service.
properties:
caCertificates:
description: 'OPTIONAL: The path to the file containing
certificate authority certificates to use in verifying
a presented server certificate. If omitted, the
proxy will not verify the server''s certificate.
Should be empty if mode is `ISTIO_MUTUAL`.'
type: string
clientCertificate:
description: REQUIRED if mode is `MUTUAL`. The path
to the file holding the client-side TLS certificate
to use. Should be empty if mode is `ISTIO_MUTUAL`.
type: string
mode:
description: 'REQUIRED: Indicates whether connections
to this port should be secured using TLS. The
value of this field determines how TLS is enforced.'
type: string
privateKey:
description: REQUIRED if mode is `MUTUAL`. The path
to the file holding the client's private key.
Should be empty if mode is `ISTIO_MUTUAL`.
type: string
sni:
description: SNI string to present to the server
during TLS handshake. Should be empty if mode
is `ISTIO_MUTUAL`.
type: string
subjectAltNames:
description: A list of alternate names to verify
the subject identity in the certificate. If specified,
the proxy will verify that the server certificate's
subject alt name matches one of the specified
values. Should be empty if mode is `ISTIO_MUTUAL`.
items:
type: string
type: array
required:
- mode
type: object
required:
- port
type: object
type: array
tls:
description: TLS related settings for connections to the upstream
service.
properties:
caCertificates:
description: 'OPTIONAL: The path to the file containing
certificate authority certificates to use in verifying
a presented server certificate. If omitted, the proxy
will not verify the server''s certificate. Should be
empty if mode is `ISTIO_MUTUAL`.'
type: string
clientCertificate:
description: REQUIRED if mode is `MUTUAL`. The path to
the file holding the client-side TLS certificate to
use. Should be empty if mode is `ISTIO_MUTUAL`.
type: string
mode:
description: 'REQUIRED: Indicates whether connections
to this port should be secured using TLS. The value
of this field determines how TLS is enforced.'
type: string
privateKey:
description: REQUIRED if mode is `MUTUAL`. The path to
the file holding the client's private key. Should be
empty if mode is `ISTIO_MUTUAL`.
type: string
sni:
description: SNI string to present to the server during
TLS handshake. Should be empty if mode is `ISTIO_MUTUAL`.
type: string
subjectAltNames:
description: A list of alternate names to verify the subject
identity in the certificate. If specified, the proxy
will verify that the server certificate's subject alt
name matches one of the specified values. Should be
empty if mode is `ISTIO_MUTUAL`.
items:
type: string
type: array
required:
- mode
type: object
type: object
required:
- name
- labels
type: object
type: array
trafficPolicy:
description: Traffic policies to apply (load balancing policy, connection
pool sizes, outlier detection).
properties:
connectionPool:
description: Settings controlling the volume of connections to an
upstream service
properties:
http:
description: HTTP connection pool settings.
properties:
maxRequestsPerConnection:
description: Maximum number of requests per connection to
a backend. Setting this parameter to 1 disables keep alive.
format: int32
type: integer
maxRetries:
description: Maximum number of retries that can be outstanding
to all hosts in a cluster at a given time. Defaults to
3.
format: int32
type: integer
type: object
tcp:
description: Settings common to both HTTP and TCP upstream connections.
properties:
connectTimeout:
description: TCP connection timeout.
type: string
maxConnections:
description: Maximum number of HTTP1 /TCP connections to
a destination host.
format: int32
type: integer
type: object
type: object
loadBalancer:
description: Settings controlling the load balancer algorithms.
properties:
consistentHash:
properties:
httpCookie:
description: Hash based on HTTP cookie.
properties:
name:
description: REQUIRED. Name of the cookie.
type: string
path:
description: Path to set for the cookie.
type: string
ttl:
description: REQUIRED. Lifetime of the cookie.
type: string
required:
- name
- ttl
type: object
httpHeaderName:
description: 'It is required to specify exactly one of the
fields as hash key: HttpHeaderName, HttpCookie, or UseSourceIP.
Hash based on a specific HTTP header.'
type: string
minimumRingSize:
description: The minimum number of virtual nodes to use
for the hash ring. Defaults to 1024. Larger ring sizes
result in more granular load distributions. If the number
of hosts in the load balancing pool is larger than the
ring size, each host will be assigned a single virtual
node.
format: int64
type: integer
useSourceIp:
description: Hash based on the source IP address.
type: boolean
type: object
simple:
description: 'It is required to specify exactly one of the fields:
Simple or ConsistentHash'
type: string
type: object
outlierDetection:
description: Settings controlling eviction of unhealthy hosts from
the load balancing pool
properties:
baseEjectionTime:
description: 'Minimum ejection duration. A host will remain
ejected for a period equal to the product of minimum ejection
duration and the number of times the host has been ejected.
This technique allows the system to automatically increase
the ejection period for unhealthy upstream servers. format:
1h/1m/1s/1ms. MUST BE >=1ms. Default is 30s.'
type: string
consecutiveErrors:
description: Number of errors before a host is ejected from
the connection pool. Defaults to 5. When the upstream host
is accessed over HTTP, a 5xx return code qualifies as an error.
When the upstream host is accessed over an opaque TCP connection,
connect timeouts and connection error/failure events qualify
as an error.
format: int32
type: integer
interval:
description: 'Time interval between ejection sweep analysis.
format: 1h/1m/1s/1ms. MUST BE >=1ms. Default is 10s.'
type: string
maxEjectionPercent:
description: Maximum % of hosts in the load balancing pool for
the upstream service that can be ejected. Defaults to 10%.
format: int32
type: integer
type: object
portLevelSettings:
description: Traffic policies specific to individual ports. Note
that port level settings will override the destination-level settings.
Traffic settings specified at the destination-level will not be
inherited when overridden by port-level settings, i.e. default
values will be applied to fields omitted in port-level traffic
policies.
items:
properties:
connectionPool:
description: Settings controlling the volume of connections
to an upstream service
properties:
http:
description: HTTP connection pool settings.
properties:
maxRequestsPerConnection:
description: Maximum number of requests per connection
to a backend. Setting this parameter to 1 disables
keep alive.
format: int32
type: integer
maxRetries:
description: Maximum number of retries that can be
outstanding to all hosts in a cluster at a given
time. Defaults to 3.
format: int32
type: integer
type: object
tcp:
description: Settings common to both HTTP and TCP upstream
connections.
properties:
connectTimeout:
description: TCP connection timeout.
type: string
maxConnections:
description: Maximum number of HTTP1 /TCP connections
to a destination host.
format: int32
type: integer
type: object
type: object
loadBalancer:
description: Settings controlling the load balancer algorithms.
properties:
consistentHash:
properties:
httpCookie:
description: Hash based on HTTP cookie.
properties:
name:
description: REQUIRED. Name of the cookie.
type: string
path:
description: Path to set for the cookie.
type: string
ttl:
description: REQUIRED. Lifetime of the cookie.
type: string
required:
- name
- ttl
type: object
httpHeaderName:
description: 'It is required to specify exactly one
of the fields as hash key: HttpHeaderName, HttpCookie,
or UseSourceIP. Hash based on a specific HTTP header.'
type: string
minimumRingSize:
description: The minimum number of virtual nodes to
use for the hash ring. Defaults to 1024. Larger
ring sizes result in more granular load distributions.
If the number of hosts in the load balancing pool
is larger than the ring size, each host will be
assigned a single virtual node.
format: int64
type: integer
useSourceIp:
description: Hash based on the source IP address.
type: boolean
type: object
simple:
description: 'It is required to specify exactly one of
the fields: Simple or ConsistentHash'
type: string
type: object
outlierDetection:
description: Settings controlling eviction of unhealthy hosts
from the load balancing pool
properties:
baseEjectionTime:
description: 'Minimum ejection duration. A host will remain
ejected for a period equal to the product of minimum
ejection duration and the number of times the host has
been ejected. This technique allows the system to automatically
increase the ejection period for unhealthy upstream
servers. format: 1h/1m/1s/1ms. MUST BE >=1ms. Default
is 30s.'
type: string
consecutiveErrors:
description: Number of errors before a host is ejected
from the connection pool. Defaults to 5. When the upstream
host is accessed over HTTP, a 5xx return code qualifies
as an error. When the upstream host is accessed over
an opaque TCP connection, connect timeouts and connection
error/failure events qualify as an error.
format: int32
type: integer
interval:
description: 'Time interval between ejection sweep analysis.
format: 1h/1m/1s/1ms. MUST BE >=1ms. Default is 10s.'
type: string
maxEjectionPercent:
description: Maximum % of hosts in the load balancing
pool for the upstream service that can be ejected. Defaults
to 10%.
format: int32
type: integer
type: object
port:
description: Specifies the port name or number of a port on
the destination service on which this policy is being applied. Names
must comply with DNS label syntax (rfc1035) and therefore
cannot collide with numbers. If there are multiple ports
on a service with the same protocol the names should be
of the form <protocol-name>-<DNS label>.
properties:
name:
description: Valid port name
type: string
number:
description: Valid port number
format: int32
type: integer
type: object
tls:
description: TLS related settings for connections to the upstream
service.
properties:
caCertificates:
description: 'OPTIONAL: The path to the file containing
certificate authority certificates to use in verifying
a presented server certificate. If omitted, the proxy
will not verify the server''s certificate. Should be
empty if mode is `ISTIO_MUTUAL`.'
type: string
clientCertificate:
description: REQUIRED if mode is `MUTUAL`. The path to
the file holding the client-side TLS certificate to
use. Should be empty if mode is `ISTIO_MUTUAL`.
type: string
mode:
description: 'REQUIRED: Indicates whether connections
to this port should be secured using TLS. The value
of this field determines how TLS is enforced.'
type: string
privateKey:
description: REQUIRED if mode is `MUTUAL`. The path to
the file holding the client's private key. Should be
empty if mode is `ISTIO_MUTUAL`.
type: string
sni:
description: SNI string to present to the server during
TLS handshake. Should be empty if mode is `ISTIO_MUTUAL`.
type: string
subjectAltNames:
description: A list of alternate names to verify the subject
identity in the certificate. If specified, the proxy
will verify that the server certificate's subject alt
name matches one of the specified values. Should be
empty if mode is `ISTIO_MUTUAL`.
items:
type: string
type: array
required:
- mode
type: object
required:
- port
type: object
type: array
tls:
description: TLS related settings for connections to the upstream
service.
properties:
caCertificates:
description: 'OPTIONAL: The path to the file containing certificate
authority certificates to use in verifying a presented server
certificate. If omitted, the proxy will not verify the server''s
certificate. Should be empty if mode is `ISTIO_MUTUAL`.'
type: string
clientCertificate:
description: REQUIRED if mode is `MUTUAL`. The path to the file
holding the client-side TLS certificate to use. Should be
empty if mode is `ISTIO_MUTUAL`.
type: string
mode:
description: 'REQUIRED: Indicates whether connections to this
port should be secured using TLS. The value of this field
determines how TLS is enforced.'
type: string
privateKey:
description: REQUIRED if mode is `MUTUAL`. The path to the file
holding the client's private key. Should be empty if mode
is `ISTIO_MUTUAL`.
type: string
sni:
description: SNI string to present to the server during TLS
handshake. Should be empty if mode is `ISTIO_MUTUAL`.
type: string
subjectAltNames:
description: A list of alternate names to verify the subject
identity in the certificate. If specified, the proxy will
verify that the server certificate's subject alt name matches
one of the specified values. Should be empty if mode is `ISTIO_MUTUAL`.
items:
type: string
type: array
required:
- mode
type: object
type: object
required:
- host
type: object
required:
- spec
version: v1alpha3
status:
acceptedNames:
kind: ""
plural: ""
conditions: []
storedVersions: []

View File

@@ -0,0 +1,129 @@
apiVersion: apiextensions.k8s.io/v1beta1
kind: CustomResourceDefinition
metadata:
creationTimestamp: null
labels:
controller-tools.k8s.io: "1.0"
name: gateways.istio.kubesphere.io
spec:
group: istio.kubesphere.io
names:
kind: Gateway
plural: gateways
scope: Namespaced
validation:
openAPIV3Schema:
properties:
apiVersion:
description: 'APIVersion defines the versioned schema of this representation
of an object. Servers should convert recognized schemas to the latest
internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/api-conventions.md#resources'
type: string
kind:
description: 'Kind is a string value representing the REST resource this
object represents. Servers may infer this from the endpoint the client
submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/api-conventions.md#types-kinds'
type: string
metadata:
type: object
spec:
properties:
selector:
description: One or more labels that indicate a specific set of pods/VMs
on which this gateway configuration should be applied. If no selectors
are provided, the gateway will be implemented by the default istio-ingress
controller.
type: object
servers:
description: 'REQUIRED: A list of server specifications.'
items:
properties:
hosts:
description: A list of hosts exposed by this gateway. While typically
applicable to HTTP services, it can also be used for TCP services
using TLS with SNI. Standard DNS wildcard prefix syntax is permitted. A
VirtualService that is bound to a gateway must having a matching
host in its default destination. Specifically one of the VirtualService
destination hosts is a strict suffix of a gateway host or a
gateway host is a suffix of one of the VirtualService hosts.
items:
type: string
type: array
port:
description: 'REQUIRED: The Port on which the proxy should listen
for incoming connections'
properties:
name:
description: Label assigned to the port.
type: string
number:
description: 'REQUIRED: A valid non-negative integer port
number.'
format: int64
type: integer
protocol:
description: 'REQUIRED: The protocol exposed on the port.
MUST BE one of HTTP|HTTPS|GRPC|HTTP2|MONGO|TCP.'
type: string
required:
- number
- protocol
type: object
tls:
description: Set of TLS related options that govern the server's
behavior. Use these options to control if all http requests
should be redirected to https, and the TLS modes to use.
properties:
caCertificates:
description: REQUIRED if mode is "MUTUAL". The path to a file
containing certificate authority certificates to use in
verifying a presented client side certificate.
type: string
httpsRedirect:
description: If set to true, the load balancer will send a
302 redirect for all http connections, asking the clients
to use HTTPS.
type: boolean
mode:
description: 'Optional: Indicates whether connections to this
port should be secured using TLS. The value of this field
determines how TLS is enforced.'
type: string
privateKey:
description: REQUIRED if mode is "SIMPLE" or "MUTUAL". The
path to the file holding the server's private key.
type: string
serverCertificate:
description: REQUIRED if mode is "SIMPLE" or "MUTUAL". The
path to the file holding the server-side TLS certificate
to use.
type: string
subjectAltNames:
description: A list of alternate names to verify the subject
identity in the certificate presented by the client.
items:
type: string
type: array
required:
- httpsRedirect
- serverCertificate
- privateKey
- caCertificates
- subjectAltNames
type: object
required:
- port
type: object
type: array
required:
- servers
type: object
required:
- spec
version: v1alpha3
status:
acceptedNames:
kind: ""
plural: ""
conditions: []
storedVersions: []

View File

@@ -0,0 +1,695 @@
apiVersion: apiextensions.k8s.io/v1beta1
kind: CustomResourceDefinition
metadata:
creationTimestamp: null
labels:
controller-tools.k8s.io: "1.0"
name: virtualservices.istio.kubesphere.io
spec:
group: istio.kubesphere.io
names:
kind: VirtualService
plural: virtualservices
scope: Namespaced
validation:
openAPIV3Schema:
properties:
apiVersion:
description: 'APIVersion defines the versioned schema of this representation
of an object. Servers should convert recognized schemas to the latest
internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/api-conventions.md#resources'
type: string
kind:
description: 'Kind is a string value representing the REST resource this
object represents. Servers may infer this from the endpoint the client
submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/api-conventions.md#types-kinds'
type: string
metadata:
type: object
spec:
properties:
gateways:
description: The names of gateways and sidecars that should apply these
routes. A single VirtualService is used for sidecars inside the mesh
as well as for one or more gateways. The selection condition imposed
by this field can be overridden using the source field in the match
conditions of HTTP/TCP routes. The reserved word "mesh" is used to
imply all the sidecars in the mesh. When this field is omitted, the
default gateway ("mesh") will be used, which would apply the rule
to all sidecars in the mesh. If a list of gateway names is provided,
the rules will apply only to the gateways. To apply the rules to both
gateways and sidecars, specify "mesh" as one of the gateway names.
items:
type: string
type: array
hosts:
description: REQUIRED. The destination address for traffic captured
by this virtual service. Could be a DNS name with wildcard prefix
or a CIDR prefix. Depending on the platform, short-names can also
be used instead of a FQDN (i.e. has no dots in the name). In such
a scenario, the FQDN of the host would be derived based on the underlying
platform. For example on Kubernetes, when hosts contains a short
name, Istio will interpret the short name based on the namespace of
the rule. Thus, when a client namespace applies a rule in the "default"
namespace containing a name "reviews, Istio will setup routes to the
"reviews.default.svc.cluster.local" service. However, if a different
name such as "reviews.sales.svc.cluster.local" is used, it would be
treated as a FQDN during virtual host matching. In Consul, a plain
service name would be resolved to the FQDN "reviews.service.consul". Note
that the hosts field applies to both HTTP and TCP services. Service
inside the mesh, i.e., those found in the service registry, must always
be referred to using their alphanumeric names. IP addresses or CIDR
prefixes are allowed only for services defined via the Gateway.
items:
type: string
type: array
http:
description: An ordered list of route rules for HTTP traffic. The first
rule matching an incoming request is used.
items:
properties:
appendHeaders:
description: Additional HTTP headers to add before forwarding
a request to the destination service.
type: object
corsPolicy:
description: Cross-Origin Resource Sharing policy
properties:
allowCredentials:
description: Indicates whether the caller is allowed to send
the actual request (not the preflight) using credentials.
Translates to Access-Control-Allow-Credentials header.
type: boolean
allowHeaders:
description: List of HTTP headers that can be used when requesting
the resource. Serialized to Access-Control-Allow-Methods
header.
items:
type: string
type: array
allowMethods:
description: List of HTTP methods allowed to access the resource.
The content will be serialized into the Access-Control-Allow-Methods
header.
items:
type: string
type: array
allowOrigin:
description: The list of origins that are allowed to perform
CORS requests. The content will be serialized into the Access-Control-Allow-Origin
header. Wildcard * will allow all origins.
items:
type: string
type: array
exposeHeaders:
description: A white list of HTTP headers that the browsers
are allowed to access. Serialized into Access-Control-Expose-Headers
header.
items:
type: string
type: array
maxAge:
description: Specifies how long the the results of a preflight
request can be cached. Translates to the Access-Control-Max-Age
header.
type: string
type: object
fault:
description: Fault injection policy to apply on HTTP traffic.
properties:
abort:
description: Abort Http request attempts and return error
codes back to downstream service, giving the impression
that the upstream service is faulty.
properties:
httpStatus:
description: REQUIRED. HTTP status code to use to abort
the Http request.
format: int64
type: integer
percent:
description: Percentage of requests to be aborted with
the error code provided (0-100).
format: int64
type: integer
required:
- httpStatus
type: object
delay:
description: Delay requests before forwarding, emulating various
failures such as network issues, overloaded upstream service,
etc.
properties:
exponentialDelay:
description: (-- Add a delay (based on an exponential
function) before forwarding the request. mean delay
needed to derive the exponential delay values --)
type: string
fixedDelay:
description: 'REQUIRED. Add a fixed delay before forwarding
the request. Format: 1h/1m/1s/1ms. MUST be >=1ms.'
type: string
percent:
description: Percentage of requests on which the delay
will be injected (0-100).
format: int64
type: integer
required:
- fixedDelay
type: object
type: object
match:
description: Match conditions to be satisfied for the rule to
be activated. All conditions inside a single match block have
AND semantics, while the list of match blocks have OR semantics.
The rule is matched if any one of the match blocks succeed.
items:
properties:
authority:
description: 'HTTP Authority values are case-sensitive and
formatted as follows: - `exact: "value"` for exact string
match - `prefix: "value"` for prefix-based match - `regex:
"value"` for ECMAscript style regex-based match'
properties:
exact:
description: exact string match
type: string
prefix:
description: prefix-based match
type: string
regex:
description: ECMAscript style regex-based match
type: string
suffix:
description: suffix-based match.
type: string
type: object
gateways:
description: Names of gateways where the rule should be
applied to. Gateway names at the top of the VirtualService
(if any) are overridden. The gateway match is independent
of sourceLabels.
items:
type: string
type: array
headers:
description: 'The header keys must be lowercase and use
hyphen as the separator, e.g. _x-request-id_. Header
values are case-sensitive and formatted as follows: -
`exact: "value"` for exact string match - `prefix: "value"`
for prefix-based match - `regex: "value"` for ECMAscript
style regex-based match **Note:** The keys `uri`, `scheme`,
`method`, and `authority` will be ignored.'
type: object
method:
description: 'HTTP Method values are case-sensitive and
formatted as follows: - `exact: "value"` for exact string
match - `prefix: "value"` for prefix-based match - `regex:
"value"` for ECMAscript style regex-based match'
properties:
exact:
description: exact string match
type: string
prefix:
description: prefix-based match
type: string
regex:
description: ECMAscript style regex-based match
type: string
suffix:
description: suffix-based match.
type: string
type: object
port:
description: Specifies the ports on the host that is being
addressed. Many services only expose a single port or
label ports with the protocols they support, in these
cases it is not required to explicitly select the port.
format: int32
type: integer
scheme:
description: 'URI Scheme values are case-sensitive and formatted
as follows: - `exact: "value"` for exact string match -
`prefix: "value"` for prefix-based match - `regex: "value"`
for ECMAscript style regex-based match'
properties:
exact:
description: exact string match
type: string
prefix:
description: prefix-based match
type: string
regex:
description: ECMAscript style regex-based match
type: string
suffix:
description: suffix-based match.
type: string
type: object
sourceLabels:
description: One or more labels that constrain the applicability
of a rule to workloads with the given labels. If the VirtualService
has a list of gateways specified at the top, it should
include the reserved gateway `mesh` in order for this
field to be applicable.
type: object
uri:
description: 'URI to match values are case-sensitive and
formatted as follows: - `exact: "value"` for exact string
match - `prefix: "value"` for prefix-based match - `regex:
"value"` for ECMAscript style regex-based match'
properties:
exact:
description: exact string match
type: string
prefix:
description: prefix-based match
type: string
regex:
description: ECMAscript style regex-based match
type: string
suffix:
description: suffix-based match.
type: string
type: object
type: object
type: array
mirror:
description: Mirror HTTP traffic to a another destination in addition
to forwarding the requests to the intended destination. Mirrored
traffic is on a best effort basis where the sidecar/gateway
will not wait for the mirrored cluster to respond before returning
the response from the original destination. Statistics will
be generated for the mirrored destination.
properties:
host:
description: 'REQUIRED. The name of a service from the service
registry. Service names are looked up from the platform''s
service registry (e.g., Kubernetes services, Consul services,
etc.) and from the hosts declared by [ServiceEntry](#ServiceEntry).
Traffic forwarded to destinations that are not found in
either of the two, will be dropped. *Note for Kubernetes
users*: When short names are used (e.g. "reviews" instead
of "reviews.default.svc.cluster.local"), Istio will interpret
the short name based on the namespace of the rule, not the
service. A rule in the "default" namespace containing a
host "reviews will be interpreted as "reviews.default.svc.cluster.local",
irrespective of the actual namespace associated with the
reviews service. _To avoid potential misconfigurations,
it is recommended to always use fully qualified domain names
over short names._'
type: string
port:
description: Specifies the port on the host that is being
addressed. If a service exposes only a single port it is
not required to explicitly select the port.
properties:
name:
description: Valid port name
type: string
number:
description: Valid port number
format: int32
type: integer
type: object
subset:
description: The name of a subset within the service. Applicable
only to services within the mesh. The subset must be defined
in a corresponding DestinationRule.
type: string
required:
- host
type: object
redirect:
description: A http rule can either redirect or forward (default)
traffic. If traffic passthrough option is specified in the rule,
route/redirect will be ignored. The redirect primitive can be
used to send a HTTP 302 redirect to a different URI or Authority.
properties:
authority:
description: On a redirect, overwrite the Authority/Host portion
of the URL with this value.
type: string
uri:
description: On a redirect, overwrite the Path portion of
the URL with this value. Note that the entire path will
be replaced, irrespective of the request URI being matched
as an exact path or prefix.
type: string
type: object
removeResponseHeaders:
description: Http headers to remove before returning the response
to the caller
type: object
retries:
description: Retry policy for HTTP requests.
properties:
attempts:
description: REQUIRED. Number of retries for a given request.
The interval between retries will be determined automatically
(25ms+). Actual number of retries attempted depends on the
httpReqTimeout.
format: int64
type: integer
perTryTimeout:
description: 'Timeout per retry attempt for a given request.
format: 1h/1m/1s/1ms. MUST BE >=1ms.'
type: string
required:
- attempts
- perTryTimeout
type: object
rewrite:
description: Rewrite HTTP URIs and Authority headers. Rewrite
cannot be used with Redirect primitive. Rewrite will be performed
before forwarding.
properties:
authority:
description: rewrite the Authority/Host header with this value.
type: string
uri:
description: rewrite the path (or the prefix) portion of the
URI with this value. If the original URI was matched based
on prefix, the value provided in this field will replace
the corresponding matched prefix.
type: string
type: object
route:
description: A http rule can either redirect or forward (default)
traffic. The forwarding target can be one of several versions
of a service (see glossary in beginning of document). Weights
associated with the service version determine the proportion
of traffic it receives.
items:
properties:
destination:
description: REQUIRED. Destination uniquely identifies the
instances of a service to which the request/connection
should be forwarded to.
properties:
host:
description: 'REQUIRED. The name of a service from the
service registry. Service names are looked up from
the platform''s service registry (e.g., Kubernetes
services, Consul services, etc.) and from the hosts
declared by [ServiceEntry](#ServiceEntry). Traffic
forwarded to destinations that are not found in either
of the two, will be dropped. *Note for Kubernetes
users*: When short names are used (e.g. "reviews"
instead of "reviews.default.svc.cluster.local"), Istio
will interpret the short name based on the namespace
of the rule, not the service. A rule in the "default"
namespace containing a host "reviews will be interpreted
as "reviews.default.svc.cluster.local", irrespective
of the actual namespace associated with the reviews
service. _To avoid potential misconfigurations, it
is recommended to always use fully qualified domain
names over short names._'
type: string
port:
description: Specifies the port on the host that is
being addressed. If a service exposes only a single
port it is not required to explicitly select the port.
properties:
name:
description: Valid port name
type: string
number:
description: Valid port number
format: int32
type: integer
type: object
subset:
description: The name of a subset within the service.
Applicable only to services within the mesh. The subset
must be defined in a corresponding DestinationRule.
type: string
required:
- host
type: object
weight:
description: REQUIRED. The proportion of traffic to be forwarded
to the service version. (0-100). Sum of weights across
destinations SHOULD BE == 100. If there is only destination
in a rule, the weight value is assumed to be 100.
format: int64
type: integer
required:
- destination
- weight
type: object
type: array
timeout:
description: Timeout for HTTP requests.
type: string
websocketUpgrade:
description: Indicates that a HTTP/1.1 client connection to this
particular route should be allowed (and expected) to upgrade
to a WebSocket connection. The default is false. Istio's reference
sidecar implementation (Envoy) expects the first request to
this route to contain the WebSocket upgrade headers. Otherwise,
the request will be rejected. Note that Websocket allows secondary
protocol negotiation which may then be subject to further routing
rules based on the protocol selected.
type: boolean
type: object
type: array
tcp:
description: An ordered list of route rules for TCP traffic. The first
rule matching an incoming request is used.
items:
properties:
match:
description: Match conditions to be satisfied for the rule to
be activated. All conditions inside a single match block have
AND semantics, while the list of match blocks have OR semantics.
The rule is matched if any one of the match blocks succeed.
items:
properties:
destinationSubnets:
description: IPv4 or IPv6 ip address of destination with
optional subnet. E.g., a.b.c.d/xx form or just a.b.c.d.
items:
type: string
type: array
gateways:
description: Names of gateways where the rule should be
applied to. Gateway names at the top of the VirtualService
(if any) are overridden. The gateway match is independent
of sourceLabels.
items:
type: string
type: array
port:
description: Specifies the port on the host that is being
addressed. Many services only expose a single port or
label ports with the protocols they support, in these
cases it is not required to explicitly select the port.
format: int64
type: integer
sourceLabels:
description: One or more labels that constrain the applicability
of a rule to workloads with the given labels. If the VirtualService
has a list of gateways specified at the top, it should
include the reserved gateway `mesh` in order for this
field to be applicable.
type: object
type: object
type: array
route:
description: The destinations to which the connection should be
forwarded to. Weights must add to 100%.
items:
properties:
destination:
description: REQUIRED. Destination uniquely identifies the
instances of a service to which the request/connection
should be forwarded to.
properties:
host:
description: 'REQUIRED. The name of a service from the
service registry. Service names are looked up from
the platform''s service registry (e.g., Kubernetes
services, Consul services, etc.) and from the hosts
declared by [ServiceEntry](#ServiceEntry). Traffic
forwarded to destinations that are not found in either
of the two, will be dropped. *Note for Kubernetes
users*: When short names are used (e.g. "reviews"
instead of "reviews.default.svc.cluster.local"), Istio
will interpret the short name based on the namespace
of the rule, not the service. A rule in the "default"
namespace containing a host "reviews will be interpreted
as "reviews.default.svc.cluster.local", irrespective
of the actual namespace associated with the reviews
service. _To avoid potential misconfigurations, it
is recommended to always use fully qualified domain
names over short names._'
type: string
port:
description: Specifies the port on the host that is
being addressed. If a service exposes only a single
port it is not required to explicitly select the port.
properties:
name:
description: Valid port name
type: string
number:
description: Valid port number
format: int32
type: integer
type: object
subset:
description: The name of a subset within the service.
Applicable only to services within the mesh. The subset
must be defined in a corresponding DestinationRule.
type: string
required:
- host
type: object
weight:
description: REQUIRED. The proportion of traffic to be forwarded
to the service version. (0-100). Sum of weights across
destinations SHOULD BE == 100. If there is only destination
in a rule, the weight value is assumed to be 100.
format: int64
type: integer
required:
- destination
- weight
type: object
type: array
required:
- match
- route
type: object
type: array
tls:
items:
properties:
match:
description: REQUIRED. Match conditions to be satisfied for the
rule to be activated. All conditions inside a single match block
have AND semantics, while the list of match blocks have OR semantics.
The rule is matched if any one of the match blocks succeed.
items:
properties:
destinationSubnets:
description: IPv4 or IPv6 ip addresses of destination with
optional subnet. E.g., a.b.c.d/xx form or just a.b.c.d.
items:
type: string
type: array
gateways:
description: Names of gateways where the rule should be
applied to. Gateway names at the top of the VirtualService
(if any) are overridden. The gateway match is independent
of sourceLabels.
items:
type: string
type: array
port:
description: Specifies the port on the host that is being
addressed. Many services only expose a single port or
label ports with the protocols they support, in these
cases it is not required to explicitly select the port.
format: int64
type: integer
sniHosts:
description: REQUIRED. SNI (server name indicator) to match
on. Wildcard prefixes can be used in the SNI value, e.g.,
*.com will match foo.example.com as well as example.com.
An SNI value must be a subset (i.e., fall within the domain)
of the corresponding virtual service's hosts
items:
type: string
type: array
sourceLabels:
description: One or more labels that constrain the applicability
of a rule to workloads with the given labels. If the VirtualService
has a list of gateways specified at the top, it should
include the reserved gateway `mesh` in order for this
field to be applicable.
type: object
required:
- sniHosts
type: object
type: array
route:
description: The destination to which the connection should be
forwarded to.
items:
properties:
destination:
description: REQUIRED. Destination uniquely identifies the
instances of a service to which the request/connection
should be forwarded to.
properties:
host:
description: 'REQUIRED. The name of a service from the
service registry. Service names are looked up from
the platform''s service registry (e.g., Kubernetes
services, Consul services, etc.) and from the hosts
declared by [ServiceEntry](#ServiceEntry). Traffic
forwarded to destinations that are not found in either
of the two, will be dropped. *Note for Kubernetes
users*: When short names are used (e.g. "reviews"
instead of "reviews.default.svc.cluster.local"), Istio
will interpret the short name based on the namespace
of the rule, not the service. A rule in the "default"
namespace containing a host "reviews will be interpreted
as "reviews.default.svc.cluster.local", irrespective
of the actual namespace associated with the reviews
service. _To avoid potential misconfigurations, it
is recommended to always use fully qualified domain
names over short names._'
type: string
port:
description: Specifies the port on the host that is
being addressed. If a service exposes only a single
port it is not required to explicitly select the port.
properties:
name:
description: Valid port name
type: string
number:
description: Valid port number
format: int32
type: integer
type: object
subset:
description: The name of a subset within the service.
Applicable only to services within the mesh. The subset
must be defined in a corresponding DestinationRule.
type: string
required:
- host
type: object
weight:
description: REQUIRED. The proportion of traffic to be forwarded
to the service version. (0-100). Sum of weights across
destinations SHOULD BE == 100. If there is only destination
in a rule, the weight value is assumed to be 100.
format: int64
type: integer
required:
- destination
- weight
type: object
type: array
required:
- match
- route
type: object
type: array
required:
- hosts
type: object
required:
- spec
version: v1alpha3
status:
acceptedNames:
kind: ""
plural: ""
conditions: []
storedVersions: []

View File

@@ -0,0 +1,762 @@
apiVersion: apiextensions.k8s.io/v1beta1
kind: CustomResourceDefinition
metadata:
creationTimestamp: null
labels:
controller-tools.k8s.io: "1.0"
name: strategies.servicemesh.kubesphere.io
spec:
group: servicemesh.kubesphere.io
names:
kind: Strategy
plural: strategies
scope: Namespaced
validation:
openAPIV3Schema:
properties:
apiVersion:
description: 'APIVersion defines the versioned schema of this representation
of an object. Servers should convert recognized schemas to the latest
internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/api-conventions.md#resources'
type: string
kind:
description: 'Kind is a string value representing the REST resource this
object represents. Servers may infer this from the endpoint the client
submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/api-conventions.md#types-kinds'
type: string
metadata:
type: object
spec:
properties:
paused:
description: Indicates that the strategy is paused and will not be processed
by the strategy controller
type: boolean
selector:
description: Label selector for virtual services.
type: object
template:
description: Template describes the virtual service that will be created.
properties:
metadata:
description: Metadata of the virtual services created from this
template
type: object
spec:
description: Spec indicates the behavior of a virtual service.
properties:
gateways:
description: The names of gateways and sidecars that should
apply these routes. A single VirtualService is used for sidecars
inside the mesh as well as for one or more gateways. The selection
condition imposed by this field can be overridden using the
source field in the match conditions of HTTP/TCP routes. The
reserved word "mesh" is used to imply all the sidecars in
the mesh. When this field is omitted, the default gateway
("mesh") will be used, which would apply the rule to all sidecars
in the mesh. If a list of gateway names is provided, the rules
will apply only to the gateways. To apply the rules to both
gateways and sidecars, specify "mesh" as one of the gateway
names.
items:
type: string
type: array
hosts:
description: REQUIRED. The destination address for traffic captured
by this virtual service. Could be a DNS name with wildcard
prefix or a CIDR prefix. Depending on the platform, short-names
can also be used instead of a FQDN (i.e. has no dots in the
name). In such a scenario, the FQDN of the host would be derived
based on the underlying platform. For example on Kubernetes,
when hosts contains a short name, Istio will interpret the
short name based on the namespace of the rule. Thus, when
a client namespace applies a rule in the "default" namespace
containing a name "reviews, Istio will setup routes to the
"reviews.default.svc.cluster.local" service. However, if a
different name such as "reviews.sales.svc.cluster.local" is
used, it would be treated as a FQDN during virtual host matching.
In Consul, a plain service name would be resolved to the FQDN
"reviews.service.consul". Note that the hosts field applies
to both HTTP and TCP services. Service inside the mesh, i.e.,
those found in the service registry, must always be referred
to using their alphanumeric names. IP addresses or CIDR prefixes
are allowed only for services defined via the Gateway.
items:
type: string
type: array
http:
description: An ordered list of route rules for HTTP traffic.
The first rule matching an incoming request is used.
items:
properties:
appendHeaders:
description: Additional HTTP headers to add before forwarding
a request to the destination service.
type: object
corsPolicy:
description: Cross-Origin Resource Sharing policy
properties:
allowCredentials:
description: Indicates whether the caller is allowed
to send the actual request (not the preflight) using
credentials. Translates to Access-Control-Allow-Credentials
header.
type: boolean
allowHeaders:
description: List of HTTP headers that can be used
when requesting the resource. Serialized to Access-Control-Allow-Methods
header.
items:
type: string
type: array
allowMethods:
description: List of HTTP methods allowed to access
the resource. The content will be serialized into
the Access-Control-Allow-Methods header.
items:
type: string
type: array
allowOrigin:
description: The list of origins that are allowed
to perform CORS requests. The content will be serialized
into the Access-Control-Allow-Origin header. Wildcard
* will allow all origins.
items:
type: string
type: array
exposeHeaders:
description: A white list of HTTP headers that the
browsers are allowed to access. Serialized into
Access-Control-Expose-Headers header.
items:
type: string
type: array
maxAge:
description: Specifies how long the the results of
a preflight request can be cached. Translates to
the Access-Control-Max-Age header.
type: string
type: object
fault:
description: Fault injection policy to apply on HTTP traffic.
properties:
abort:
description: Abort Http request attempts and return
error codes back to downstream service, giving the
impression that the upstream service is faulty.
properties:
httpStatus:
description: REQUIRED. HTTP status code to use
to abort the Http request.
format: int64
type: integer
percent:
description: Percentage of requests to be aborted
with the error code provided (0-100).
format: int64
type: integer
required:
- httpStatus
type: object
delay:
description: Delay requests before forwarding, emulating
various failures such as network issues, overloaded
upstream service, etc.
properties:
exponentialDelay:
description: (-- Add a delay (based on an exponential
function) before forwarding the request. mean
delay needed to derive the exponential delay
values --)
type: string
fixedDelay:
description: 'REQUIRED. Add a fixed delay before
forwarding the request. Format: 1h/1m/1s/1ms.
MUST be >=1ms.'
type: string
percent:
description: Percentage of requests on which the
delay will be injected (0-100).
format: int64
type: integer
required:
- fixedDelay
type: object
type: object
match:
description: Match conditions to be satisfied for the
rule to be activated. All conditions inside a single
match block have AND semantics, while the list of match
blocks have OR semantics. The rule is matched if any
one of the match blocks succeed.
items:
properties:
authority:
description: 'HTTP Authority values are case-sensitive
and formatted as follows: - `exact: "value"`
for exact string match - `prefix: "value"` for
prefix-based match - `regex: "value"` for ECMAscript
style regex-based match'
properties:
exact:
description: exact string match
type: string
prefix:
description: prefix-based match
type: string
regex:
description: ECMAscript style regex-based match
type: string
suffix:
description: suffix-based match.
type: string
type: object
gateways:
description: Names of gateways where the rule should
be applied to. Gateway names at the top of the
VirtualService (if any) are overridden. The gateway
match is independent of sourceLabels.
items:
type: string
type: array
headers:
description: 'The header keys must be lowercase
and use hyphen as the separator, e.g. _x-request-id_. Header
values are case-sensitive and formatted as follows: -
`exact: "value"` for exact string match - `prefix:
"value"` for prefix-based match - `regex: "value"`
for ECMAscript style regex-based match **Note:**
The keys `uri`, `scheme`, `method`, and `authority`
will be ignored.'
type: object
method:
description: 'HTTP Method values are case-sensitive
and formatted as follows: - `exact: "value"`
for exact string match - `prefix: "value"` for
prefix-based match - `regex: "value"` for ECMAscript
style regex-based match'
properties:
exact:
description: exact string match
type: string
prefix:
description: prefix-based match
type: string
regex:
description: ECMAscript style regex-based match
type: string
suffix:
description: suffix-based match.
type: string
type: object
port:
description: Specifies the ports on the host that
is being addressed. Many services only expose
a single port or label ports with the protocols
they support, in these cases it is not required
to explicitly select the port.
format: int32
type: integer
scheme:
description: 'URI Scheme values are case-sensitive
and formatted as follows: - `exact: "value"`
for exact string match - `prefix: "value"` for
prefix-based match - `regex: "value"` for ECMAscript
style regex-based match'
properties:
exact:
description: exact string match
type: string
prefix:
description: prefix-based match
type: string
regex:
description: ECMAscript style regex-based match
type: string
suffix:
description: suffix-based match.
type: string
type: object
sourceLabels:
description: One or more labels that constrain the
applicability of a rule to workloads with the
given labels. If the VirtualService has a list
of gateways specified at the top, it should include
the reserved gateway `mesh` in order for this
field to be applicable.
type: object
uri:
description: 'URI to match values are case-sensitive
and formatted as follows: - `exact: "value"`
for exact string match - `prefix: "value"` for
prefix-based match - `regex: "value"` for ECMAscript
style regex-based match'
properties:
exact:
description: exact string match
type: string
prefix:
description: prefix-based match
type: string
regex:
description: ECMAscript style regex-based match
type: string
suffix:
description: suffix-based match.
type: string
type: object
type: object
type: array
mirror:
description: Mirror HTTP traffic to a another destination
in addition to forwarding the requests to the intended
destination. Mirrored traffic is on a best effort basis
where the sidecar/gateway will not wait for the mirrored
cluster to respond before returning the response from
the original destination. Statistics will be generated
for the mirrored destination.
properties:
host:
description: 'REQUIRED. The name of a service from
the service registry. Service names are looked up
from the platform''s service registry (e.g., Kubernetes
services, Consul services, etc.) and from the hosts
declared by [ServiceEntry](#ServiceEntry). Traffic
forwarded to destinations that are not found in
either of the two, will be dropped. *Note for Kubernetes
users*: When short names are used (e.g. "reviews"
instead of "reviews.default.svc.cluster.local"),
Istio will interpret the short name based on the
namespace of the rule, not the service. A rule in
the "default" namespace containing a host "reviews
will be interpreted as "reviews.default.svc.cluster.local",
irrespective of the actual namespace associated
with the reviews service. _To avoid potential misconfigurations,
it is recommended to always use fully qualified
domain names over short names._'
type: string
port:
description: Specifies the port on the host that is
being addressed. If a service exposes only a single
port it is not required to explicitly select the
port.
properties:
name:
description: Valid port name
type: string
number:
description: Valid port number
format: int32
type: integer
type: object
subset:
description: The name of a subset within the service.
Applicable only to services within the mesh. The
subset must be defined in a corresponding DestinationRule.
type: string
required:
- host
type: object
redirect:
description: A http rule can either redirect or forward
(default) traffic. If traffic passthrough option is
specified in the rule, route/redirect will be ignored.
The redirect primitive can be used to send a HTTP 302
redirect to a different URI or Authority.
properties:
authority:
description: On a redirect, overwrite the Authority/Host
portion of the URL with this value.
type: string
uri:
description: On a redirect, overwrite the Path portion
of the URL with this value. Note that the entire
path will be replaced, irrespective of the request
URI being matched as an exact path or prefix.
type: string
type: object
removeResponseHeaders:
description: Http headers to remove before returning the
response to the caller
type: object
retries:
description: Retry policy for HTTP requests.
properties:
attempts:
description: REQUIRED. Number of retries for a given
request. The interval between retries will be determined
automatically (25ms+). Actual number of retries
attempted depends on the httpReqTimeout.
format: int64
type: integer
perTryTimeout:
description: 'Timeout per retry attempt for a given
request. format: 1h/1m/1s/1ms. MUST BE >=1ms.'
type: string
required:
- attempts
- perTryTimeout
type: object
rewrite:
description: Rewrite HTTP URIs and Authority headers.
Rewrite cannot be used with Redirect primitive. Rewrite
will be performed before forwarding.
properties:
authority:
description: rewrite the Authority/Host header with
this value.
type: string
uri:
description: rewrite the path (or the prefix) portion
of the URI with this value. If the original URI
was matched based on prefix, the value provided
in this field will replace the corresponding matched
prefix.
type: string
type: object
route:
description: A http rule can either redirect or forward
(default) traffic. The forwarding target can be one
of several versions of a service (see glossary in beginning
of document). Weights associated with the service version
determine the proportion of traffic it receives.
items:
properties:
destination:
description: REQUIRED. Destination uniquely identifies
the instances of a service to which the request/connection
should be forwarded to.
properties:
host:
description: 'REQUIRED. The name of a service
from the service registry. Service names are
looked up from the platform''s service registry
(e.g., Kubernetes services, Consul services,
etc.) and from the hosts declared by [ServiceEntry](#ServiceEntry).
Traffic forwarded to destinations that are
not found in either of the two, will be dropped. *Note
for Kubernetes users*: When short names are
used (e.g. "reviews" instead of "reviews.default.svc.cluster.local"),
Istio will interpret the short name based
on the namespace of the rule, not the service.
A rule in the "default" namespace containing
a host "reviews will be interpreted as "reviews.default.svc.cluster.local",
irrespective of the actual namespace associated
with the reviews service. _To avoid potential
misconfigurations, it is recommended to always
use fully qualified domain names over short
names._'
type: string
port:
description: Specifies the port on the host
that is being addressed. If a service exposes
only a single port it is not required to explicitly
select the port.
properties:
name:
description: Valid port name
type: string
number:
description: Valid port number
format: int32
type: integer
type: object
subset:
description: The name of a subset within the
service. Applicable only to services within
the mesh. The subset must be defined in a
corresponding DestinationRule.
type: string
required:
- host
type: object
weight:
description: REQUIRED. The proportion of traffic
to be forwarded to the service version. (0-100).
Sum of weights across destinations SHOULD BE ==
100. If there is only destination in a rule, the
weight value is assumed to be 100.
format: int64
type: integer
required:
- destination
- weight
type: object
type: array
timeout:
description: Timeout for HTTP requests.
type: string
websocketUpgrade:
description: Indicates that a HTTP/1.1 client connection
to this particular route should be allowed (and expected)
to upgrade to a WebSocket connection. The default is
false. Istio's reference sidecar implementation (Envoy)
expects the first request to this route to contain the
WebSocket upgrade headers. Otherwise, the request will
be rejected. Note that Websocket allows secondary protocol
negotiation which may then be subject to further routing
rules based on the protocol selected.
type: boolean
type: object
type: array
tcp:
description: An ordered list of route rules for TCP traffic.
The first rule matching an incoming request is used.
items:
properties:
match:
description: Match conditions to be satisfied for the
rule to be activated. All conditions inside a single
match block have AND semantics, while the list of match
blocks have OR semantics. The rule is matched if any
one of the match blocks succeed.
items:
properties:
destinationSubnets:
description: IPv4 or IPv6 ip address of destination
with optional subnet. E.g., a.b.c.d/xx form or
just a.b.c.d.
items:
type: string
type: array
gateways:
description: Names of gateways where the rule should
be applied to. Gateway names at the top of the
VirtualService (if any) are overridden. The gateway
match is independent of sourceLabels.
items:
type: string
type: array
port:
description: Specifies the port on the host that
is being addressed. Many services only expose
a single port or label ports with the protocols
they support, in these cases it is not required
to explicitly select the port.
format: int64
type: integer
sourceLabels:
description: One or more labels that constrain the
applicability of a rule to workloads with the
given labels. If the VirtualService has a list
of gateways specified at the top, it should include
the reserved gateway `mesh` in order for this
field to be applicable.
type: object
type: object
type: array
route:
description: The destinations to which the connection
should be forwarded to. Weights must add to 100%.
items:
properties:
destination:
description: REQUIRED. Destination uniquely identifies
the instances of a service to which the request/connection
should be forwarded to.
properties:
host:
description: 'REQUIRED. The name of a service
from the service registry. Service names are
looked up from the platform''s service registry
(e.g., Kubernetes services, Consul services,
etc.) and from the hosts declared by [ServiceEntry](#ServiceEntry).
Traffic forwarded to destinations that are
not found in either of the two, will be dropped. *Note
for Kubernetes users*: When short names are
used (e.g. "reviews" instead of "reviews.default.svc.cluster.local"),
Istio will interpret the short name based
on the namespace of the rule, not the service.
A rule in the "default" namespace containing
a host "reviews will be interpreted as "reviews.default.svc.cluster.local",
irrespective of the actual namespace associated
with the reviews service. _To avoid potential
misconfigurations, it is recommended to always
use fully qualified domain names over short
names._'
type: string
port:
description: Specifies the port on the host
that is being addressed. If a service exposes
only a single port it is not required to explicitly
select the port.
properties:
name:
description: Valid port name
type: string
number:
description: Valid port number
format: int32
type: integer
type: object
subset:
description: The name of a subset within the
service. Applicable only to services within
the mesh. The subset must be defined in a
corresponding DestinationRule.
type: string
required:
- host
type: object
weight:
description: REQUIRED. The proportion of traffic
to be forwarded to the service version. (0-100).
Sum of weights across destinations SHOULD BE ==
100. If there is only destination in a rule, the
weight value is assumed to be 100.
format: int64
type: integer
required:
- destination
- weight
type: object
type: array
required:
- match
- route
type: object
type: array
tls:
items:
properties:
match:
description: REQUIRED. Match conditions to be satisfied
for the rule to be activated. All conditions inside
a single match block have AND semantics, while the list
of match blocks have OR semantics. The rule is matched
if any one of the match blocks succeed.
items:
properties:
destinationSubnets:
description: IPv4 or IPv6 ip addresses of destination
with optional subnet. E.g., a.b.c.d/xx form or
just a.b.c.d.
items:
type: string
type: array
gateways:
description: Names of gateways where the rule should
be applied to. Gateway names at the top of the
VirtualService (if any) are overridden. The gateway
match is independent of sourceLabels.
items:
type: string
type: array
port:
description: Specifies the port on the host that
is being addressed. Many services only expose
a single port or label ports with the protocols
they support, in these cases it is not required
to explicitly select the port.
format: int64
type: integer
sniHosts:
description: REQUIRED. SNI (server name indicator)
to match on. Wildcard prefixes can be used in
the SNI value, e.g., *.com will match foo.example.com
as well as example.com. An SNI value must be a
subset (i.e., fall within the domain) of the corresponding
virtual service's hosts
items:
type: string
type: array
sourceLabels:
description: One or more labels that constrain the
applicability of a rule to workloads with the
given labels. If the VirtualService has a list
of gateways specified at the top, it should include
the reserved gateway `mesh` in order for this
field to be applicable.
type: object
required:
- sniHosts
type: object
type: array
route:
description: The destination to which the connection should
be forwarded to.
items:
properties:
destination:
description: REQUIRED. Destination uniquely identifies
the instances of a service to which the request/connection
should be forwarded to.
properties:
host:
description: 'REQUIRED. The name of a service
from the service registry. Service names are
looked up from the platform''s service registry
(e.g., Kubernetes services, Consul services,
etc.) and from the hosts declared by [ServiceEntry](#ServiceEntry).
Traffic forwarded to destinations that are
not found in either of the two, will be dropped. *Note
for Kubernetes users*: When short names are
used (e.g. "reviews" instead of "reviews.default.svc.cluster.local"),
Istio will interpret the short name based
on the namespace of the rule, not the service.
A rule in the "default" namespace containing
a host "reviews will be interpreted as "reviews.default.svc.cluster.local",
irrespective of the actual namespace associated
with the reviews service. _To avoid potential
misconfigurations, it is recommended to always
use fully qualified domain names over short
names._'
type: string
port:
description: Specifies the port on the host
that is being addressed. If a service exposes
only a single port it is not required to explicitly
select the port.
properties:
name:
description: Valid port name
type: string
number:
description: Valid port number
format: int32
type: integer
type: object
subset:
description: The name of a subset within the
service. Applicable only to services within
the mesh. The subset must be defined in a
corresponding DestinationRule.
type: string
required:
- host
type: object
weight:
description: REQUIRED. The proportion of traffic
to be forwarded to the service version. (0-100).
Sum of weights across destinations SHOULD BE ==
100. If there is only destination in a rule, the
weight value is assumed to be 100.
format: int64
type: integer
required:
- destination
- weight
type: object
type: array
required:
- match
- route
type: object
type: array
required:
- hosts
type: object
type: object
type:
description: Strategy type
type: string
type: object
status:
type: object
version: v1alpha2
status:
acceptedNames:
kind: ""
plural: ""
conditions: []
storedVersions: []

View File

@@ -24,9 +24,9 @@ resources:
# Comment the following 3 lines if you want to disable
# the auth proxy (https://github.com/brancz/kube-rbac-proxy)
# which protects your /metrics endpoint.
- ../rbac/auth_proxy_service.yaml
- ../rbac/auth_proxy_role.yaml
- ../rbac/auth_proxy_role_binding.yaml
#- ../rbac/auth_proxy_service.yaml
#- ../rbac/auth_proxy_role.yaml
#- ../rbac/auth_proxy_role_binding.yaml
patches:
- manager_image_patch.yaml

View File

@@ -10,7 +10,7 @@ spec:
spec:
containers:
- name: kube-rbac-proxy
image: gcr.io/kubebuilder/kube-rbac-proxy:v0.4.0
image: quay.io/coreos/kube-rbac-proxy:v0.4.0
args:
- "--secure-listen-address=0.0.0.0:8443"
- "--upstream=http://127.0.0.1:8080/"

View File

@@ -8,5 +8,5 @@ spec:
spec:
containers:
# Change the value of image field below to your controller image URL
- image: IMAGE_URL
- image: kubespheredev/controller-manager:latest
name: manager

View File

@@ -43,8 +43,8 @@ spec:
spec:
containers:
- command:
- /manager
image: controller:latest
- ./controller-manager
image: kubespheredev/controller-manager:latest
imagePullPolicy: Always
name: manager
env:

View File

@@ -0,0 +1,87 @@
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
creationTimestamp: null
name: manager-role
rules:
- apiGroups:
- networking.istio.io
resources:
- virtualservices
verbs:
- get
- list
- watch
- create
- update
- patch
- delete
- apiGroups:
- networking.istio.io
resources:
- virtualservices/status
verbs:
- get
- list
- watch
- create
- update
- patch
- delete
- apiGroups:
- servicemesh.kubesphere.io
resources:
- strategies
verbs:
- get
- list
- watch
- create
- update
- patch
- delete
- apiGroups:
- servicemesh.kubesphere.io
resources:
- strategies/status
verbs:
- get
- update
- patch
- apiGroups:
- admissionregistration.k8s.io
resources:
- mutatingwebhookconfigurations
- validatingwebhookconfigurations
verbs:
- get
- list
- watch
- create
- update
- patch
- delete
- apiGroups:
- ""
resources:
- secrets
verbs:
- get
- list
- watch
- create
- update
- patch
- delete
- apiGroups:
- ""
resources:
- services
verbs:
- get
- list
- watch
- create
- update
- patch
- delete

View File

@@ -0,0 +1,13 @@
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
creationTimestamp: null
name: manager-rolebinding
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: ClusterRole
name: manager-role
subjects:
- kind: ServiceAccount
name: default
namespace: system

View File

@@ -0,0 +1,26 @@
apiVersion: servicemesh.kubesphere.io/v1alpha2
kind: Strategy
metadata:
labels:
controller-tools.k8s.io: "1.0"
name: strategy-sample
spec:
# Add fields here
type: Canary
selector:
matchLabels:
"servicemesh.kubesphere.io/type": "canary"
template:
spec:
hosts:
- details
http:
- route:
- destination:
host: "details"
subset: v1
weight: 60
- destination:
host: "details"
subset: v2
weight: 40

View File

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

View File

@@ -29,8 +29,8 @@ fi
ROOTDIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
OUTPUT_DIR=${ROOTDIR}/bin
BUILDPATH=${ROOTDIR}/${1:?"path to build"}
OUTPUT_DIR=bin
BUILDPATH=./${1:?"path to build"}
OUT=${OUTPUT_DIR}/${1:?"output path"}
set -e
@@ -42,4 +42,4 @@ GOBINARY=${GOBINARY:-go}
# forgoing -i (incremental build) because it will be deprecated by tool chain.
time GOOS=${BUILD_GOOS} GOARCH=${BUILD_GOARCH} ${GOBINARY} build \
-o ${OUT} \
${BUILDPATH}
${BUILDPATH}

88
hack/install_kubebuilder.sh Executable file
View File

@@ -0,0 +1,88 @@
#!/bin/sh
#
# This file will be fetched as: curl -L https://git.io/getLatestKubebuilder | sh -
# so it should be pure bourne shell, not bash (and not reference other scripts)
#
# The script fetches the latest kubebuilder release candidate and untars it.
# It lets users to do curl -L https://git.io//getLatestKubebuilder | KUBEBUILDER_VERSION=1.0.5 sh -
# for instance to change the version fetched.
# Check if the program is installed, otherwise exit
function command_exists () {
if ! [ -x "$(command -v $1)" ]; then
echo "Error: $1 program is not installed." >&2
exit 1
fi
}
# Determine OS
OS="$(uname)"
case $OS in
Darwin)
OSEXT="darwin"
;;
Linux)
OSEXT="linux"
;;
*)
echo "Only OSX and Linux OS are supported !"
exit 1
;;
esac
HW=$(uname -m)
case $HW in
x86_64)
ARCH=amd64 ;;
*)
echo "Only x86_64 machines are supported !"
exit 1
;;
esac
# Check if curl, tar commands/programs exist
command_exists curl
command_exists tar
if [ "x${KUBEBUILDER_VERSION}" = "x" ] ; then
KUBEBUILDER_VERSION=$(curl -L -s https://api.github.com/repos/kubernetes-sigs/kubebuilder/releases/latest | \
grep tag_name | sed "s/ *\"tag_name\": *\"\\(.*\\)\",*/\\1/")
if [ -z "$KUBEBUILDER_VERSION" ]; then
echo "\nUnable to fetch the latest version tag. This may be due to network access problem"
exit 0
fi
fi
KUBEBUILDER_VERSION=${KUBEBUILDER_VERSION#"v"}
KUBEBUILDER_VERSION_NAME="kubebuilder_${KUBEBUILDER_VERSION}"
KUBEBUILDER_DIR=/usr/local/kubebuilder
# Check if folder containing kubebuilder executable exists and is not empty
if [ -d "$KUBEBUILDER_DIR" ]; then
if [ "$(ls -A $KUBEBUILDER_DIR)" ]; then
echo "\n/usr/local/kubebuilder folder is not empty. Please delete or backup it before to install ${KUBEBUILDER_VERSION_NAME}"
exit 1
fi
fi
TMP_DIR=$(mktemp -d)
pushd $TMP_DIR
# Downloading Kubebuilder compressed file using curl program
URL="https://github.com/kubernetes-sigs/kubebuilder/releases/download/v${KUBEBUILDER_VERSION}/${KUBEBUILDER_VERSION_NAME}_${OSEXT}_${ARCH}.tar.gz"
echo "Downloading ${KUBEBUILDER_VERSION_NAME}\nfrom $URL\n"
curl -L "$URL"| tar xz -C $TMP_DIR
echo "Downloaded executable files"
ls "${KUBEBUILDER_VERSION_NAME}_${OSEXT}_${ARCH}/bin"
echo "Moving files to $KUBEBUILDER_DIR folder\n"
mv ${KUBEBUILDER_VERSION_NAME}_${OSEXT}_${ARCH} kubebuilder && sudo mv -f kubebuilder /usr/local/
echo "Add kubebuilder to your path; e.g copy paste in your shell and/or edit your ~/.profile file"
echo "export PATH=\$PATH:/usr/local/kubebuilder/bin"
popd
rm -rf $TMP_DIR
export PATH=$PATH:/usr/local/kubebuilder/bin

View File

@@ -0,0 +1,35 @@
/*
Copyright 2019 The KubeSphere authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package apis
import (
"github.com/knative/pkg/apis/istio/v1alpha3"
"kubesphere.io/kubesphere/pkg/apis/servicemesh/v1alpha2"
"sigs.k8s.io/application/pkg/apis/app/v1beta1"
)
func init() {
// Register the types with the Scheme so the components can map objects to GroupVersionKinds and back
AddToSchemes = append(AddToSchemes, v1alpha2.SchemeBuilder.AddToScheme)
// Register networking.istio.io/v1alpha3
AddToSchemes = append(AddToSchemes, v1alpha3.SchemeBuilder.AddToScheme)
// Register application scheme
AddToSchemes = append(AddToSchemes, v1beta1.SchemeBuilder.AddToScheme)
}

View File

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

View File

@@ -0,0 +1,16 @@
package install
import (
"github.com/emicklei/go-restful"
urlruntime "k8s.io/apimachinery/pkg/util/runtime"
"kubesphere.io/kubesphere/pkg/apis/servicemesh/metrics/v1alpha2"
"kubesphere.io/kubesphere/pkg/apiserver/runtime"
)
func init() {
Install(runtime.Container)
}
func Install(c *restful.Container) {
urlruntime.Must(v1alpha2.AddToContainer(c))
}

View File

@@ -0,0 +1,132 @@
package v1alpha2
import (
"github.com/emicklei/go-restful"
"github.com/emicklei/go-restful-openapi"
"k8s.io/apimachinery/pkg/runtime/schema"
"kubesphere.io/kubesphere/pkg/apiserver/runtime"
"kubesphere.io/kubesphere/pkg/apiserver/servicemesh/metrics"
"kubesphere.io/kubesphere/pkg/errors"
)
const GroupName = "servicemesh.kubesphere.io"
var GroupVersion = schema.GroupVersion{Group: GroupName, Version: "v1alpha2"}
var (
WebServiceBuilder = runtime.NewContainerBuilder(addWebService)
AddToContainer = WebServiceBuilder.AddToContainer
)
func addWebService(c *restful.Container) error {
tags := []string{"ServiceMesh"}
webservice := runtime.NewWebService(GroupVersion)
// Get service metrics
// GET /namespaces/{namespace}/services/{service}/metrics
webservice.Route(webservice.GET("/namespaces/{namespace}/services/{service}/metrics").
To(metrics.GetServiceMetrics).
Metadata(restfulspec.KeyOpenAPITags, tags).
Doc("Get app metrics from a specific namespace").
Param(webservice.PathParameter("namespace", "name of the namespace")).
Param(webservice.PathParameter("service", "name of the service")).
Param(webservice.QueryParameter("filters[]", "type of metrics type, e.g. request_count, request_duration, request_error_count")).
Param(webservice.QueryParameter("queryTime", "from which UNIX time to extract metrics")).
Param(webservice.QueryParameter("duration", "metrics duration, in seconds")).
Param(webservice.QueryParameter("step", "metrics step")).
Param(webservice.QueryParameter("rateInterval", "metrics rate intervals, e.g. 20s")).
Param(webservice.QueryParameter("quantiles[]", "metrics quantiles, 0.5, 0.9, 0.99")).
Param(webservice.QueryParameter("byLabels[]", "by which labels to group node, e.g. source_workload, destination_service_name")).
Param(webservice.QueryParameter("requestProtocol", "request protocol, http/tcp")).
Param(webservice.QueryParameter("reporter", "destination")).
Writes(errors.Error{})).Produces(restful.MIME_JSON)
// Get app metrics
// Get /namespaces/{namespace}/apps/{app}/metrics
webservice.Route(webservice.GET("/namespaces/{namespace}/apps/{app}/metrics").
To(metrics.GetAppMetrics).
Metadata(restfulspec.KeyOpenAPITags, tags).
Doc("Get app metrics from a specific namespace").
Param(webservice.PathParameter("namespace", "name of the namespace")).
Param(webservice.PathParameter("app", "name of the workload label app value")).
Param(webservice.QueryParameter("filters[]", "type of metrics type, e.g. request_count, request_duration, request_error_count")).
Param(webservice.QueryParameter("queryTime", "from which UNIX time to extract metrics")).
Param(webservice.QueryParameter("duration", "metrics duration, in seconds")).
Param(webservice.QueryParameter("step", "metrics step")).
Param(webservice.QueryParameter("rateInterval", "metrics rate intervals, e.g. 20s")).
Param(webservice.QueryParameter("quantiles[]", "metrics quantiles, 0.5, 0.9, 0.99")).
Param(webservice.QueryParameter("byLabels[]", "by which labels to group node, e.g. source_workload, destination_service_name")).
Param(webservice.QueryParameter("requestProtocol", "request protocol, http/tcp")).
Param(webservice.QueryParameter("reporter", "destination")).
Writes(errors.Error{})).Produces(restful.MIME_JSON)
// Get workload metrics
// Get /namespaces/{namespace}/workloads/{workload}/metrics
webservice.Route(webservice.GET("/namespaces/{namespace}/workloads/{workload}/metrics").
To(metrics.GetWorkloadMetrics).
Metadata(restfulspec.KeyOpenAPITags, tags).
Doc("Get workload metrics from a specific namespace").
Param(webservice.PathParameter("namespace", "name of the namespace")).
Param(webservice.PathParameter("workload", "name of the workload")).
Param(webservice.QueryParameter("filters[]", "type of metrics type, e.g. request_count, request_duration, request_error_count")).
Param(webservice.QueryParameter("queryTime", "from which UNIX time to extract metrics")).
Param(webservice.QueryParameter("duration", "metrics duration, in seconds")).
Param(webservice.QueryParameter("step", "metrics step")).
Param(webservice.QueryParameter("rateInterval", "metrics rate intervals, e.g. 20s")).
Param(webservice.QueryParameter("quantiles[]", "metrics quantiles, 0.5, 0.9, 0.99")).
Param(webservice.QueryParameter("byLabels[]", "by which labels to group node, e.g. source_workload, destination_service_name")).
Param(webservice.QueryParameter("requestProtocol", "request protocol, http/tcp")).
Param(webservice.QueryParameter("reporter", "destination")).
Writes(errors.Error{})).Produces(restful.MIME_JSON)
// Get namespace metrics
// Get /namespaces/{namespace}/metrics
webservice.Route(webservice.GET("/namespaces/{namespace}/metrics").
To(metrics.GetNamespaceMetrics).
Metadata(restfulspec.KeyOpenAPITags, tags).
Doc("Get workload metrics from a specific namespace").
Param(webservice.PathParameter("namespace", "name of the namespace")).
Param(webservice.QueryParameter("filters[]", "type of metrics type, e.g. request_count, request_duration, request_error_count")).
Param(webservice.QueryParameter("queryTime", "from which UNIX time to extract metrics")).
Param(webservice.QueryParameter("duration", "metrics duration, in seconds")).
Param(webservice.QueryParameter("step", "metrics step")).
Param(webservice.QueryParameter("rateInterval", "metrics rate intervals, e.g. 20s")).
Param(webservice.QueryParameter("quantiles[]", "metrics quantiles, 0.5, 0.9, 0.99")).
Param(webservice.QueryParameter("byLabels[]", "by which labels to group node, e.g. source_workload, destination_service_name")).
Param(webservice.QueryParameter("requestProtocol", "request protocol, http/tcp")).
Param(webservice.QueryParameter("reporter", "destination")).
Writes(errors.Error{})).Produces(restful.MIME_JSON)
// Get namespace graph
// Get /namespaces/{namespace}/graph
webservice.Route(webservice.GET("/namespaces/{namespace}/graph").
To(metrics.GetNamespaceGraph).
Metadata(restfulspec.KeyOpenAPITags, tags).
Doc("Get service graph for a specific namespace").
Param(webservice.PathParameter("namespace", "name of a namespace")).
Param(webservice.QueryParameter("graphType", "type of the generated service graph, eg. ")).
Param(webservice.QueryParameter("groupBy", "group nodes by kind")).
Param(webservice.QueryParameter("queryTime", "from which time point, default now")).
Param(webservice.QueryParameter("injectServiceNodes", "whether to inject service ndoes")).
Writes(errors.Error{})).Produces(restful.MIME_JSON)
// Get namespaces graph, for multiple namespaces
// Get /namespaces/graph
webservice.Route(webservice.GET("/namespaces/{namespace}/graph").
To(metrics.GetNamespacesGraph).
Metadata(restfulspec.KeyOpenAPITags, tags).
Doc("Get service graph for a specific namespace").
Param(webservice.PathParameter("namespace", "name of a namespace")).
Param(webservice.QueryParameter("graphType", "type of the generated service graph, eg. ")).
Param(webservice.QueryParameter("groupBy", "group nodes by kind")).
Param(webservice.QueryParameter("queryTime", "from which time point, default now")).
Param(webservice.QueryParameter("injectServiceNodes", "whether to inject service ndoes")).
Param(webservice.QueryParameter("namespaces", "names of namespaces")).
Writes(errors.Error{})).Produces(restful.MIME_JSON)
c.Add(webservice)
return nil
}

View File

@@ -0,0 +1,23 @@
/*
Copyright 2019 The KubeSphere authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
// Package v1alpha2 contains API Schema definitions for the servicemesh v1alpha2 API group
// +k8s:openapi-gen=true
// +k8s:deepcopy-gen=package,register
// +k8s:conversion-gen=kubesphere.io/kubesphere/pkg/apis/servicemesh
// +k8s:defaulter-gen=TypeMeta
// +groupName=servicemesh.kubesphere.io
package v1alpha2

View File

@@ -0,0 +1,46 @@
/*
Copyright 2019 The KubeSphere authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
// NOTE: Boilerplate only. Ignore this file.
// Package v1alpha2 contains API Schema definitions for the servicemesh v1alpha2 API group
// +k8s:openapi-gen=true
// +k8s:deepcopy-gen=package,register
// +k8s:conversion-gen=kubesphere.io/kubesphere/pkg/apis/servicemesh
// +k8s:defaulter-gen=TypeMeta
// +groupName=servicemesh.kubesphere.io
package v1alpha2
import (
"k8s.io/apimachinery/pkg/runtime/schema"
"sigs.k8s.io/controller-runtime/pkg/runtime/scheme"
)
var (
// SchemeGroupVersion is group version used to register these objects
SchemeGroupVersion = schema.GroupVersion{Group: "servicemesh.kubesphere.io", Version: "v1alpha2"}
// SchemeBuilder is used to add go types to the GroupVersionKind scheme
SchemeBuilder = &scheme.Builder{GroupVersion: SchemeGroupVersion}
// AddToScheme is required by pkg/client/...
AddToScheme = SchemeBuilder.AddToScheme
)
// Resource is required by pkg/client/listers/...
func Resource(resource string) schema.GroupResource {
return SchemeGroupVersion.WithResource(resource).GroupResource()
}

View File

@@ -0,0 +1,151 @@
/*
Copyright 2019 The KubeSphere authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package v1alpha2
import (
"github.com/knative/pkg/apis/istio/v1alpha3"
"k8s.io/apiextensions-apiserver/pkg/apis/apiextensions"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
)
// EDIT THIS FILE! THIS IS SCAFFOLDING FOR YOU TO OWN!
// NOTE: json tags are required. Any new fields you add must have json tags for the fields to be serialized.
type StrategyType string
const (
// Canary strategy type
CanaryType StrategyType = "Canary"
// BlueGreen strategy type
BlueGreenType StrategyType = "BlueGreen"
// Mirror strategy type
Mirror StrategyType = "Mirror"
)
// StrategySpec defines the desired state of Strategy
type StrategySpec struct {
// Strategy type
Type StrategyType `json:"type,omitempty"`
// Label selector for virtual services.
// +optional
Selector *metav1.LabelSelector `json:"selector,omitempty"`
// Template describes the virtual service that will be created.
Template VirtualServiceTemplateSpec `json:"template,omitempty"`
// Indicates that the strategy is paused and will not be processed
// by the strategy controller
Paused bool `json:"paused,omitempty"`
}
// VirtualServiceTemplateSpec
type VirtualServiceTemplateSpec struct {
// Metadata of the virtual services created from this template
// +optional
metav1.ObjectMeta `json:"metadata,omitempty"`
// Spec indicates the behavior of a virtual service.
// +optional
Spec v1alpha3.VirtualServiceSpec `json:"spec,omitempty"`
}
// StrategyStatus defines the observed state of Strategy
type StrategyStatus struct {
// INSERT ADDITIONAL STATUS FIELD - define observed state of cluster
// Important: Run "make" to regenerate code after modifying this file
// The latest available observations of an object's current state.
// +optional
Conditions []StrategyCondition
// Represents time when the strategy was acknowledged by the controller.
// It is represented in RFC3339 form and is in UTC.
// +optional
StartTime *metav1.Time
// Represents time when the strategy was completed.
// It is represented in RFC3339 form and is in UTC.
// +optional
CompletionTime *metav1.Time
}
type StrategyConditionType string
// These are valid conditions of a strategy.
const (
// StrategyComplete means the strategy has been delivered to istio.
StrategyComplete StrategyConditionType = "Complete"
// StrategyFailed means the strategy has failed its delivery to istio.
StrategyFailed StrategyConditionType = "Failed"
)
// StrategyCondition describes current state of a strategy.
type StrategyCondition struct {
// Type of strategy condition, Complete or Failed.
Type StrategyConditionType
// Status of the condition, one of True, False, Unknown
Status apiextensions.ConditionStatus
// Last time the condition was checked.
// +optional
LastProbeTime metav1.Time
// Last time the condition transit from one status to another
// +optional
LastTransitionTime metav1.Time
// reason for the condition's last transition
Reason string
// Human readable message indicating details about last transition.
// +optinal
Message string
}
// +genclient
// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object
// Strategy is the Schema for the strategies API
// +k8s:openapi-gen=true
type Strategy struct {
metav1.TypeMeta `json:",inline"`
metav1.ObjectMeta `json:"metadata,omitempty"`
Spec StrategySpec `json:"spec,omitempty"`
Status StrategyStatus `json:"status,omitempty"`
}
// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object
// StrategyList contains a list of Strategy
type StrategyList struct {
metav1.TypeMeta `json:",inline"`
metav1.ListMeta `json:"metadata,omitempty"`
Items []Strategy `json:"items"`
}
func init() {
SchemeBuilder.Register(&Strategy{}, &StrategyList{})
}

View File

@@ -0,0 +1,88 @@
/*
Copyright 2019 The KubeSphere authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package v1alpha2
import (
"github.com/knative/pkg/apis/istio/v1alpha3"
"io/ioutil"
"k8s.io/apimachinery/pkg/util/json"
"k8s.io/client-go/kubernetes/scheme"
"testing"
"github.com/onsi/gomega"
"golang.org/x/net/context"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/types"
)
func TestStorageStrategy(t *testing.T) {
key := types.NamespacedName{
Name: "foo",
Namespace: "default",
}
created := &Strategy{
ObjectMeta: metav1.ObjectMeta{
Name: "foo",
Namespace: "default",
},
Spec: StrategySpec{
Template: VirtualServiceTemplateSpec{
Spec: v1alpha3.VirtualServiceSpec{
Hosts: []string{
"details",
},
},
},
},
}
g := gomega.NewGomegaWithT(t)
// Test Create
fetched := &Strategy{}
g.Expect(c.Create(context.TODO(), created)).NotTo(gomega.HaveOccurred())
g.Expect(c.Get(context.TODO(), key, fetched)).NotTo(gomega.HaveOccurred())
g.Expect(fetched).To(gomega.Equal(created))
// Test Updating the Labels
updated := fetched.DeepCopy()
updated.Labels = map[string]string{"hello": "world"}
g.Expect(c.Update(context.TODO(), updated)).NotTo(gomega.HaveOccurred())
g.Expect(c.Get(context.TODO(), key, fetched)).NotTo(gomega.HaveOccurred())
g.Expect(fetched).To(gomega.Equal(updated))
// Test Delete
g.Expect(c.Delete(context.TODO(), fetched)).NotTo(gomega.HaveOccurred())
g.Expect(c.Get(context.TODO(), key, fetched)).To(gomega.HaveOccurred())
}
func TestStrategyRead(t *testing.T) {
//g := gomega.NewGomegaWithT(t)
var str []byte
file, err := ioutil.ReadFile("/Users/zry/go/src/kubesphere.io/kubesphere/config/samples/servicemesh_v1alpha2_strategy.yaml")
if err == nil {
obj, _, _ := scheme.Codecs.UniversalDeserializer().Decode(file, nil, &Strategy{})
switch obj.(type) {
case *Strategy:
str, err = json.Marshal(obj)
t.Logf("Read strategy %s", str)
}
}
}

View File

@@ -0,0 +1,55 @@
/*
Copyright 2019 The KubeSphere authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package v1alpha2
import (
"log"
"os"
"path/filepath"
"testing"
"k8s.io/client-go/kubernetes/scheme"
"k8s.io/client-go/rest"
"sigs.k8s.io/controller-runtime/pkg/client"
"sigs.k8s.io/controller-runtime/pkg/envtest"
)
var cfg *rest.Config
var c client.Client
func TestMain(m *testing.M) {
t := &envtest.Environment{
CRDDirectoryPaths: []string{filepath.Join("..", "..", "..", "..", "config", "crds")},
}
err := SchemeBuilder.AddToScheme(scheme.Scheme)
if err != nil {
log.Fatal(err)
}
if cfg, err = t.Start(); err != nil {
log.Fatal(err)
}
if c, err = client.New(cfg, client.Options{Scheme: scheme.Scheme}); err != nil {
log.Fatal(err)
}
code := m.Run()
t.Stop()
os.Exit(code)
}

View File

@@ -0,0 +1,176 @@
// +build !ignore_autogenerated
/*
Copyright The Kubernetes Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
// Code generated by deepcopy-gen. DO NOT EDIT.
package v1alpha2
import (
v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
runtime "k8s.io/apimachinery/pkg/runtime"
)
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *Strategy) DeepCopyInto(out *Strategy) {
*out = *in
out.TypeMeta = in.TypeMeta
in.ObjectMeta.DeepCopyInto(&out.ObjectMeta)
in.Spec.DeepCopyInto(&out.Spec)
in.Status.DeepCopyInto(&out.Status)
return
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Strategy.
func (in *Strategy) DeepCopy() *Strategy {
if in == nil {
return nil
}
out := new(Strategy)
in.DeepCopyInto(out)
return out
}
// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object.
func (in *Strategy) DeepCopyObject() runtime.Object {
if c := in.DeepCopy(); c != nil {
return c
}
return nil
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *StrategyCondition) DeepCopyInto(out *StrategyCondition) {
*out = *in
in.LastProbeTime.DeepCopyInto(&out.LastProbeTime)
in.LastTransitionTime.DeepCopyInto(&out.LastTransitionTime)
return
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new StrategyCondition.
func (in *StrategyCondition) DeepCopy() *StrategyCondition {
if in == nil {
return nil
}
out := new(StrategyCondition)
in.DeepCopyInto(out)
return out
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *StrategyList) DeepCopyInto(out *StrategyList) {
*out = *in
out.TypeMeta = in.TypeMeta
out.ListMeta = in.ListMeta
if in.Items != nil {
in, out := &in.Items, &out.Items
*out = make([]Strategy, len(*in))
for i := range *in {
(*in)[i].DeepCopyInto(&(*out)[i])
}
}
return
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new StrategyList.
func (in *StrategyList) DeepCopy() *StrategyList {
if in == nil {
return nil
}
out := new(StrategyList)
in.DeepCopyInto(out)
return out
}
// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object.
func (in *StrategyList) DeepCopyObject() runtime.Object {
if c := in.DeepCopy(); c != nil {
return c
}
return nil
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *StrategySpec) DeepCopyInto(out *StrategySpec) {
*out = *in
if in.Selector != nil {
in, out := &in.Selector, &out.Selector
*out = new(v1.LabelSelector)
(*in).DeepCopyInto(*out)
}
in.Template.DeepCopyInto(&out.Template)
return
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new StrategySpec.
func (in *StrategySpec) DeepCopy() *StrategySpec {
if in == nil {
return nil
}
out := new(StrategySpec)
in.DeepCopyInto(out)
return out
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *StrategyStatus) DeepCopyInto(out *StrategyStatus) {
*out = *in
if in.Conditions != nil {
in, out := &in.Conditions, &out.Conditions
*out = make([]StrategyCondition, len(*in))
for i := range *in {
(*in)[i].DeepCopyInto(&(*out)[i])
}
}
if in.StartTime != nil {
in, out := &in.StartTime, &out.StartTime
*out = (*in).DeepCopy()
}
if in.CompletionTime != nil {
in, out := &in.CompletionTime, &out.CompletionTime
*out = (*in).DeepCopy()
}
return
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new StrategyStatus.
func (in *StrategyStatus) DeepCopy() *StrategyStatus {
if in == nil {
return nil
}
out := new(StrategyStatus)
in.DeepCopyInto(out)
return out
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *VirtualServiceTemplateSpec) DeepCopyInto(out *VirtualServiceTemplateSpec) {
*out = *in
in.ObjectMeta.DeepCopyInto(&out.ObjectMeta)
in.Spec.DeepCopyInto(&out.Spec)
return
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new VirtualServiceTemplateSpec.
func (in *VirtualServiceTemplateSpec) DeepCopy() *VirtualServiceTemplateSpec {
if in == nil {
return nil
}
out := new(VirtualServiceTemplateSpec)
in.DeepCopyInto(out)
return out
}

View File

@@ -0,0 +1,43 @@
package metrics
import (
"fmt"
"github.com/emicklei/go-restful"
"github.com/kiali/kiali/handlers"
)
// Get app metrics
func GetAppMetrics(request *restful.Request, response *restful.Response) {
handlers.AppMetrics(response.ResponseWriter, request.Request)
}
// Get workload metrics
func GetWorkloadMetrics(request *restful.Request, response *restful.Response) {
handlers.WorkloadMetrics(response.ResponseWriter, request.Request)
}
// Get service metrics
func GetServiceMetrics(request *restful.Request, response *restful.Response) {
handlers.ServiceMetrics(response.ResponseWriter, request.Request)
}
// Get namespace metrics
func GetNamespaceMetrics(request *restful.Request, response *restful.Response) {
handlers.NamespaceMetrics(response.ResponseWriter, request.Request)
}
// Get service graph for namespace
func GetNamespaceGraph(request *restful.Request, response *restful.Response) {
namespace := request.PathParameter("namespace")
if len(namespace) > 0 {
request.Request.URL.RawQuery = fmt.Sprintf("%s&namespaces=%s", request.Request.URL.RawQuery, namespace)
}
handlers.GraphNamespaces(response.ResponseWriter, request.Request)
}
// Get service graph for namespaces
func GetNamespacesGraph(request *restful.Request, response *restful.Response) {
handlers.GraphNamespaces(response.ResponseWriter, request.Request)
}

View File

@@ -0,0 +1,30 @@
/*
Copyright 2019 The KubeSphere authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package controller
import (
"kubesphere.io/kubesphere/pkg/controller/strategy"
)
func init() {
// AddToManagerFuncs is a list of functions to create controllers and add them to a manager.
AddToManagerFuncs = append(AddToManagerFuncs, strategy.Add)
// Add application to manager functions
//AddToManagerFuncs = append(AddToManagerFuncs, application.Add)
}

View File

@@ -1,5 +1,5 @@
/*
Copyright 2019 The KubeSphere authors.
Copyright 2019 The KubeSphere Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.

View File

@@ -0,0 +1,148 @@
/*
Copyright 2019 The KubeSphere authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package strategy
import (
"context"
"github.com/knative/pkg/apis/istio/v1alpha3"
"reflect"
"k8s.io/apimachinery/pkg/api/errors"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/runtime"
"k8s.io/apimachinery/pkg/types"
servicemeshv1alpha2 "kubesphere.io/kubesphere/pkg/apis/servicemesh/v1alpha2"
"sigs.k8s.io/controller-runtime/pkg/client"
"sigs.k8s.io/controller-runtime/pkg/controller"
"sigs.k8s.io/controller-runtime/pkg/controller/controllerutil"
"sigs.k8s.io/controller-runtime/pkg/handler"
"sigs.k8s.io/controller-runtime/pkg/manager"
"sigs.k8s.io/controller-runtime/pkg/reconcile"
logf "sigs.k8s.io/controller-runtime/pkg/runtime/log"
"sigs.k8s.io/controller-runtime/pkg/source"
)
var log = logf.Log.WithName("controller")
// Add creates a new Strategy Controller and adds it to the Manager with default RBAC. The Manager will set fields on the Controller
// and Start it when the Manager is Started.
func Add(mgr manager.Manager) error {
return add(mgr, newReconciler(mgr))
}
// newReconciler returns a new reconcile.Reconciler
func newReconciler(mgr manager.Manager) reconcile.Reconciler {
return &ReconcileStrategy{Client: mgr.GetClient(), scheme: mgr.GetScheme()}
}
// add adds a new Controller to mgr with r as the reconcile.Reconciler
func add(mgr manager.Manager, r reconcile.Reconciler) error {
// Create a new controller
c, err := controller.New("strategy-controller", mgr, controller.Options{Reconciler: r})
if err != nil {
return err
}
// Watch for changes to Strategy
err = c.Watch(&source.Kind{Type: &servicemeshv1alpha2.Strategy{}}, &handler.EnqueueRequestForObject{})
if err != nil {
return err
}
err = c.Watch(&source.Kind{Type: &v1alpha3.VirtualService{}}, &handler.EnqueueRequestForObject{})
if err != nil {
return err
}
// TODO(user): Modify this to be the types you create
// Watch a VirtualService created by Strategy
err = c.Watch(&source.Kind{Type: &v1alpha3.VirtualService{}}, &handler.EnqueueRequestForOwner{
IsController: true,
OwnerType: &servicemeshv1alpha2.Strategy{},
})
if err != nil {
return err
}
return nil
}
var _ reconcile.Reconciler = &ReconcileStrategy{}
// ReconcileStrategy reconciles a Strategy object
type ReconcileStrategy struct {
client.Client
scheme *runtime.Scheme
}
// Reconcile reads that state of the cluster for a Strategy object and makes changes based on the state read
// and what is in the Strategy.Spec
// a Deployment as an example
// Automatically generate RBAC rules to allow the Controller to read and write Deployments
// +kubebuilder:rbac:groups=networking.istio.io,resources=virtualservices,verbs=get;list;watch;create;update;patch;delete
// +kubebuilder:rbac:groups=networking.istio.io,resources=virtualservices/status,verbs=get;list;watch;create;update;patch;delete
// +kubebuilder:rbac:groups=servicemesh.kubesphere.io,resources=strategies,verbs=get;list;watch;create;update;patch;delete
// +kubebuilder:rbac:groups=servicemesh.kubesphere.io,resources=strategies/status,verbs=get;update;patch
func (r *ReconcileStrategy) Reconcile(request reconcile.Request) (reconcile.Result, error) {
// Fetch the Strategy instance
strategy := &servicemeshv1alpha2.Strategy{}
err := r.Get(context.TODO(), request.NamespacedName, strategy)
if err != nil {
if errors.IsNotFound(err) {
// Object not found, return. Created objects are automatically garbage collected.
// For additional cleanup logic use finalizers.
return reconcile.Result{}, nil
}
// Error reading the object - requeue the request.
return reconcile.Result{}, err
}
// Define VirtualService to be created
vs := &v1alpha3.VirtualService{
ObjectMeta: metav1.ObjectMeta{
Name: strategy.Name + "-virtualservice",
Namespace: strategy.Namespace,
Labels: strategy.Spec.Selector.MatchLabels,
},
Spec: strategy.Spec.Template.Spec,
}
if err := controllerutil.SetControllerReference(strategy, vs, r.scheme); err != nil {
return reconcile.Result{}, err
}
// Check if the VirtualService already exists
found := &v1alpha3.VirtualService{}
err = r.Get(context.TODO(), types.NamespacedName{Name: vs.Name, Namespace: vs.Namespace}, found)
if err != nil && errors.IsNotFound(err) {
log.Info("Creating VirtualService", "namespace", vs.Namespace, "name", vs.Name)
err = r.Create(context.TODO(), vs)
return reconcile.Result{}, err
} else if err != nil {
return reconcile.Result{}, err
}
// Update the found object and write the result back if there are any changes
if !reflect.DeepEqual(vs.Spec, found.Spec) {
found.Spec = vs.Spec
log.Info("Updating VirtualService", "namespace", vs.Namespace, "name", vs.Name)
err = r.Update(context.TODO(), found)
if err != nil {
return reconcile.Result{}, err
}
}
return reconcile.Result{}, nil
}

View File

@@ -0,0 +1,75 @@
/*
Copyright 2019 The KubeSphere authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package strategy
import (
stdlog "log"
"os"
"path/filepath"
"sync"
"testing"
"github.com/onsi/gomega"
"k8s.io/client-go/kubernetes/scheme"
"k8s.io/client-go/rest"
"kubesphere.io/kubesphere/pkg/apis"
"sigs.k8s.io/controller-runtime/pkg/envtest"
"sigs.k8s.io/controller-runtime/pkg/manager"
"sigs.k8s.io/controller-runtime/pkg/reconcile"
)
var cfg *rest.Config
func TestMain(m *testing.M) {
t := &envtest.Environment{
CRDDirectoryPaths: []string{filepath.Join("..", "..", "..", "config", "crds")},
}
apis.AddToScheme(scheme.Scheme)
var err error
if cfg, err = t.Start(); err != nil {
stdlog.Fatal(err)
}
code := m.Run()
t.Stop()
os.Exit(code)
}
// SetupTestReconcile returns a reconcile.Reconcile implementation that delegates to inner and
// writes the request to requests after Reconcile is finished.
func SetupTestReconcile(inner reconcile.Reconciler) (reconcile.Reconciler, chan reconcile.Request) {
requests := make(chan reconcile.Request)
fn := reconcile.Func(func(req reconcile.Request) (reconcile.Result, error) {
result, err := inner.Reconcile(req)
requests <- req
return result, err
})
return fn, requests
}
// StartTestManager adds recFn
func StartTestManager(mgr manager.Manager, g *gomega.GomegaWithT) (chan struct{}, *sync.WaitGroup) {
stop := make(chan struct{})
wg := &sync.WaitGroup{}
wg.Add(1)
go func() {
defer wg.Done()
g.Expect(mgr.Start(stop)).NotTo(gomega.HaveOccurred())
}()
return stop, wg
}

View File

@@ -0,0 +1,143 @@
/*
Copyright 2019 The KubeSphere authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package strategy
import (
"github.com/knative/pkg/apis/istio/common/v1alpha1"
"github.com/knative/pkg/apis/istio/v1alpha3"
"k8s.io/apimachinery/pkg/util/json"
"testing"
"time"
"github.com/onsi/gomega"
"golang.org/x/net/context"
apierrors "k8s.io/apimachinery/pkg/api/errors"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/types"
servicemeshv1alpha2 "kubesphere.io/kubesphere/pkg/apis/servicemesh/v1alpha2"
"sigs.k8s.io/controller-runtime/pkg/client"
"sigs.k8s.io/controller-runtime/pkg/manager"
"sigs.k8s.io/controller-runtime/pkg/reconcile"
)
var c client.Client
var expectedRequest = reconcile.Request{NamespacedName: types.NamespacedName{Name: "foo", Namespace: "default"}}
var depKey = types.NamespacedName{Name: "foo-virtualservice", Namespace: "default"}
const timeout = time.Second * 5
func TestReconcile(t *testing.T) {
g := gomega.NewGomegaWithT(t)
instance := &servicemeshv1alpha2.Strategy{
ObjectMeta: metav1.ObjectMeta{
Name: "foo",
Namespace: "default",
},
Spec: servicemeshv1alpha2.StrategySpec{
Type: servicemeshv1alpha2.CanaryType,
Selector: &metav1.LabelSelector{
MatchLabels: map[string]string{
"type": "Canary",
},
},
Template: servicemeshv1alpha2.VirtualServiceTemplateSpec{
Spec: v1alpha3.VirtualServiceSpec{
Hosts: []string{"details"},
Gateways: []string{"default"},
Http: []v1alpha3.HTTPRoute{
{
Match: []v1alpha3.HTTPMatchRequest{
{
Method: &v1alpha1.StringMatch{
Exact: "POST",
},
},
},
Route: []v1alpha3.DestinationWeight{
{
Destination: v1alpha3.Destination{
Host: "details",
Subset: "v1",
},
Weight: 60,
},
},
},
{
Route: []v1alpha3.DestinationWeight{
{
Destination: v1alpha3.Destination{
Host: "details",
Subset: "v2",
},
Weight: 40,
},
},
},
},
},
},
},
}
// Setup the Manager and Controller. Wrap the Controller Reconcile function so it writes each request to a
// channel when it is finished.
mgr, err := manager.New(cfg, manager.Options{})
g.Expect(err).NotTo(gomega.HaveOccurred())
c = mgr.GetClient()
recFn, requests := SetupTestReconcile(newReconciler(mgr))
g.Expect(add(mgr, recFn)).NotTo(gomega.HaveOccurred())
stopMgr, mgrStopped := StartTestManager(mgr, g)
defer func() {
close(stopMgr)
mgrStopped.Wait()
}()
// Create the Strategy object and expect the Reconcile and Deployment to be created
err = c.Create(context.TODO(), instance)
// The instance object may not be a valid object because it might be missing some required fields.
// Please modify the instance object by adding required fields and then remove the following if statement.
if apierrors.IsInvalid(err) {
t.Logf("failed to create object, got an invalid object error: %v", err)
return
}
g.Expect(err).NotTo(gomega.HaveOccurred())
defer c.Delete(context.TODO(), instance)
g.Eventually(requests, timeout).Should(gomega.Receive(gomega.Equal(expectedRequest)))
vs := &v1alpha3.VirtualService{}
g.Eventually(func() error { return c.Get(context.TODO(), depKey, vs) }, timeout).
Should(gomega.Succeed())
if str, err := json.Marshal(vs); err == nil {
t.Logf("Created virtual service %s\n", str)
}
// Delete the Deployment and expect Reconcile to be called for Deployment deletion
g.Expect(c.Delete(context.TODO(), vs)).NotTo(gomega.HaveOccurred())
g.Eventually(requests, timeout).Should(gomega.Receive(gomega.Equal(expectedRequest)))
//g.Eventually(func() error { return c.Get(context.TODO(), depKey, vs) }, timeout).Should(gomega.Succeed())
// Manually delete Deployment since GC isn't enabled in the test control plane
g.Eventually(func() error { return c.Delete(context.TODO(), vs) }, timeout).
Should(gomega.MatchError("virtualservices.networking.istio.io \"foo-virtualservice\" not found"))
}

View File

@@ -0,0 +1,7 @@
package metrics
import "github.com/emicklei/go-restful"
func GetAppMetrics(request *restful.Request, response *restful.Response) {
}

View File

@@ -17,11 +17,7 @@
*/
package options
import (
"github.com/spf13/pflag"
)
var SharedOptions = NewServerRunOptions()
import "github.com/spf13/pflag"
type ServerRunOptions struct {
// server bind address
@@ -38,8 +34,6 @@ type ServerRunOptions struct {
// tls private key file
TlsPrivateKey string
CommandLine *pflag.FlagSet
}
func NewServerRunOptions() *ServerRunOptions {
@@ -50,14 +44,16 @@ func NewServerRunOptions() *ServerRunOptions {
SecurePort: 0,
TlsCertFile: "",
TlsPrivateKey: "",
CommandLine: &pflag.FlagSet{},
}
s.CommandLine.StringVar(&s.BindAddress, "bind-address", "0.0.0.0", "server bind address")
s.CommandLine.IntVar(&s.InsecurePort, "insecure-port", 9090, "insecure port number")
s.CommandLine.IntVar(&s.SecurePort, "secure-port", 0, "secure port number")
s.CommandLine.StringVar(&s.TlsCertFile, "tls-cert-file", "", "tls cert file")
s.CommandLine.StringVar(&s.TlsPrivateKey, "tls-private-key", "", "tls private key")
return &s
}
func (s *ServerRunOptions) AddFlags(fs *pflag.FlagSet) {
fs.StringVar(&s.BindAddress, "bind-address", "0.0.0.0", "server bind address")
fs.IntVar(&s.InsecurePort, "insecure-port", 9090, "insecure port number")
fs.IntVar(&s.SecurePort, "secure-port", 0, "secure port number")
fs.StringVar(&s.TlsCertFile, "tls-cert-file", "", "tls cert file")
fs.StringVar(&s.TlsPrivateKey, "tls-private-key", "", "tls private key")
}

View File

@@ -38,11 +38,11 @@ const (
)
var (
prometheusAPIEndpoint string
PrometheusAPIEndpoint string
)
func init() {
flag.StringVar(&prometheusAPIEndpoint, "prometheus-endpoint", "http://prometheus-k8s.kubesphere-monitoring-system.svc:9090/api/v1/", "prometheus api endpoint")
flag.StringVar(&PrometheusAPIEndpoint, "prometheus-endpoint", "http://prometheus-k8s.kubesphere-monitoring-system.svc:9090/api/v1/", "prometheus api endpoint")
}
type MonitoringRequestParams struct {
@@ -71,7 +71,7 @@ type MonitoringRequestParams struct {
}
func SendMonitoringRequest(queryType string, params string) string {
epurl := prometheusAPIEndpoint + queryType + params
epurl := PrometheusAPIEndpoint + queryType + params
response, err := http.DefaultClient.Get(epurl)
if err != nil {

7
pkg/utils/utils.go Normal file
View File

@@ -0,0 +1,7 @@
package utils
func CheckError(err error) {
if err != nil {
panic(err)
}
}

View File

@@ -1 +0,0 @@
*.exe

View File

@@ -1,22 +0,0 @@
# go-winio
This repository contains utilities for efficiently performing Win32 IO operations in
Go. Currently, this is focused on accessing named pipes and other file handles, and
for using named pipes as a net transport.
This code relies on IO completion ports to avoid blocking IO on system threads, allowing Go
to reuse the thread to schedule another goroutine. This limits support to Windows Vista and
newer operating systems. This is similar to the implementation of network sockets in Go's net
package.
Please see the LICENSE file for licensing information.
This project has adopted the [Microsoft Open Source Code of
Conduct](https://opensource.microsoft.com/codeofconduct/). For more information
see the [Code of Conduct
FAQ](https://opensource.microsoft.com/codeofconduct/faq/) or contact
[opencode@microsoft.com](mailto:opencode@microsoft.com) with any additional
questions or comments.
Thanks to natefinch for the inspiration for this library. See https://github.com/natefinch/npipe
for another named pipe implementation.

View File

@@ -1,5 +0,0 @@
*.sublime-*
.DS_Store
*.swp
*.swo
tags

View File

@@ -1,12 +0,0 @@
language: go
go:
- 1.4.x
- 1.5.x
- 1.6.x
- 1.7.x
- 1.8.x
- 1.9.x
- "1.10.x"
- "1.11.x"
- tip

View File

@@ -1,188 +0,0 @@
# Purell
Purell is a tiny Go library to normalize URLs. It returns a pure URL. Pure-ell. Sanitizer and all. Yeah, I know...
Based on the [wikipedia paper][wiki] and the [RFC 3986 document][rfc].
[![build status](https://travis-ci.org/PuerkitoBio/purell.svg?branch=master)](http://travis-ci.org/PuerkitoBio/purell)
## Install
`go get github.com/PuerkitoBio/purell`
## Changelog
* **v1.1.1** : Fix failing test due to Go1.12 changes (thanks to @ianlancetaylor).
* **2016-11-14 (v1.1.0)** : IDN: Conform to RFC 5895: Fold character width (thanks to @beeker1121).
* **2016-07-27 (v1.0.0)** : Normalize IDN to ASCII (thanks to @zenovich).
* **2015-02-08** : Add fix for relative paths issue ([PR #5][pr5]) and add fix for unnecessary encoding of reserved characters ([see issue #7][iss7]).
* **v0.2.0** : Add benchmarks, Attempt IDN support.
* **v0.1.0** : Initial release.
## Examples
From `example_test.go` (note that in your code, you would import "github.com/PuerkitoBio/purell", and would prefix references to its methods and constants with "purell."):
```go
package purell
import (
"fmt"
"net/url"
)
func ExampleNormalizeURLString() {
if normalized, err := NormalizeURLString("hTTp://someWEBsite.com:80/Amazing%3f/url/",
FlagLowercaseScheme|FlagLowercaseHost|FlagUppercaseEscapes); err != nil {
panic(err)
} else {
fmt.Print(normalized)
}
// Output: http://somewebsite.com:80/Amazing%3F/url/
}
func ExampleMustNormalizeURLString() {
normalized := MustNormalizeURLString("hTTpS://someWEBsite.com:443/Amazing%fa/url/",
FlagsUnsafeGreedy)
fmt.Print(normalized)
// Output: http://somewebsite.com/Amazing%FA/url
}
func ExampleNormalizeURL() {
if u, err := url.Parse("Http://SomeUrl.com:8080/a/b/.././c///g?c=3&a=1&b=9&c=0#target"); err != nil {
panic(err)
} else {
normalized := NormalizeURL(u, FlagsUsuallySafeGreedy|FlagRemoveDuplicateSlashes|FlagRemoveFragment)
fmt.Print(normalized)
}
// Output: http://someurl.com:8080/a/c/g?c=3&a=1&b=9&c=0
}
```
## API
As seen in the examples above, purell offers three methods, `NormalizeURLString(string, NormalizationFlags) (string, error)`, `MustNormalizeURLString(string, NormalizationFlags) (string)` and `NormalizeURL(*url.URL, NormalizationFlags) (string)`. They all normalize the provided URL based on the specified flags. Here are the available flags:
```go
const (
// Safe normalizations
FlagLowercaseScheme NormalizationFlags = 1 << iota // HTTP://host -> http://host, applied by default in Go1.1
FlagLowercaseHost // http://HOST -> http://host
FlagUppercaseEscapes // http://host/t%ef -> http://host/t%EF
FlagDecodeUnnecessaryEscapes // http://host/t%41 -> http://host/tA
FlagEncodeNecessaryEscapes // http://host/!"#$ -> http://host/%21%22#$
FlagRemoveDefaultPort // http://host:80 -> http://host
FlagRemoveEmptyQuerySeparator // http://host/path? -> http://host/path
// Usually safe normalizations
FlagRemoveTrailingSlash // http://host/path/ -> http://host/path
FlagAddTrailingSlash // http://host/path -> http://host/path/ (should choose only one of these add/remove trailing slash flags)
FlagRemoveDotSegments // http://host/path/./a/b/../c -> http://host/path/a/c
// Unsafe normalizations
FlagRemoveDirectoryIndex // http://host/path/index.html -> http://host/path/
FlagRemoveFragment // http://host/path#fragment -> http://host/path
FlagForceHTTP // https://host -> http://host
FlagRemoveDuplicateSlashes // http://host/path//a///b -> http://host/path/a/b
FlagRemoveWWW // http://www.host/ -> http://host/
FlagAddWWW // http://host/ -> http://www.host/ (should choose only one of these add/remove WWW flags)
FlagSortQuery // http://host/path?c=3&b=2&a=1&b=1 -> http://host/path?a=1&b=1&b=2&c=3
// Normalizations not in the wikipedia article, required to cover tests cases
// submitted by jehiah
FlagDecodeDWORDHost // http://1113982867 -> http://66.102.7.147
FlagDecodeOctalHost // http://0102.0146.07.0223 -> http://66.102.7.147
FlagDecodeHexHost // http://0x42660793 -> http://66.102.7.147
FlagRemoveUnnecessaryHostDots // http://.host../path -> http://host/path
FlagRemoveEmptyPortSeparator // http://host:/path -> http://host/path
// Convenience set of safe normalizations
FlagsSafe NormalizationFlags = FlagLowercaseHost | FlagLowercaseScheme | FlagUppercaseEscapes | FlagDecodeUnnecessaryEscapes | FlagEncodeNecessaryEscapes | FlagRemoveDefaultPort | FlagRemoveEmptyQuerySeparator
// For convenience sets, "greedy" uses the "remove trailing slash" and "remove www. prefix" flags,
// while "non-greedy" uses the "add (or keep) the trailing slash" and "add www. prefix".
// Convenience set of usually safe normalizations (includes FlagsSafe)
FlagsUsuallySafeGreedy NormalizationFlags = FlagsSafe | FlagRemoveTrailingSlash | FlagRemoveDotSegments
FlagsUsuallySafeNonGreedy NormalizationFlags = FlagsSafe | FlagAddTrailingSlash | FlagRemoveDotSegments
// Convenience set of unsafe normalizations (includes FlagsUsuallySafe)
FlagsUnsafeGreedy NormalizationFlags = FlagsUsuallySafeGreedy | FlagRemoveDirectoryIndex | FlagRemoveFragment | FlagForceHTTP | FlagRemoveDuplicateSlashes | FlagRemoveWWW | FlagSortQuery
FlagsUnsafeNonGreedy NormalizationFlags = FlagsUsuallySafeNonGreedy | FlagRemoveDirectoryIndex | FlagRemoveFragment | FlagForceHTTP | FlagRemoveDuplicateSlashes | FlagAddWWW | FlagSortQuery
// Convenience set of all available flags
FlagsAllGreedy = FlagsUnsafeGreedy | FlagDecodeDWORDHost | FlagDecodeOctalHost | FlagDecodeHexHost | FlagRemoveUnnecessaryHostDots | FlagRemoveEmptyPortSeparator
FlagsAllNonGreedy = FlagsUnsafeNonGreedy | FlagDecodeDWORDHost | FlagDecodeOctalHost | FlagDecodeHexHost | FlagRemoveUnnecessaryHostDots | FlagRemoveEmptyPortSeparator
)
```
For convenience, the set of flags `FlagsSafe`, `FlagsUsuallySafe[Greedy|NonGreedy]`, `FlagsUnsafe[Greedy|NonGreedy]` and `FlagsAll[Greedy|NonGreedy]` are provided for the similarly grouped normalizations on [wikipedia's URL normalization page][wiki]. You can add (using the bitwise OR `|` operator) or remove (using the bitwise AND NOT `&^` operator) individual flags from the sets if required, to build your own custom set.
The [full godoc reference is available on gopkgdoc][godoc].
Some things to note:
* `FlagDecodeUnnecessaryEscapes`, `FlagEncodeNecessaryEscapes`, `FlagUppercaseEscapes` and `FlagRemoveEmptyQuerySeparator` are always implicitly set, because internally, the URL string is parsed as an URL object, which automatically decodes unnecessary escapes, uppercases and encodes necessary ones, and removes empty query separators (an unnecessary `?` at the end of the url). So this operation cannot **not** be done. For this reason, `FlagRemoveEmptyQuerySeparator` (as well as the other three) has been included in the `FlagsSafe` convenience set, instead of `FlagsUnsafe`, where Wikipedia puts it.
* The `FlagDecodeUnnecessaryEscapes` decodes the following escapes (*from -> to*):
- %24 -> $
- %26 -> &
- %2B-%3B -> +,-./0123456789:;
- %3D -> =
- %40-%5A -> @ABCDEFGHIJKLMNOPQRSTUVWXYZ
- %5F -> _
- %61-%7A -> abcdefghijklmnopqrstuvwxyz
- %7E -> ~
* When the `NormalizeURL` function is used (passing an URL object), this source URL object is modified (that is, after the call, the URL object will be modified to reflect the normalization).
* The *replace IP with domain name* normalization (`http://208.77.188.166/ → http://www.example.com/`) is obviously not possible for a library without making some network requests. This is not implemented in purell.
* The *remove unused query string parameters* and *remove default query parameters* are also not implemented, since this is a very case-specific normalization, and it is quite trivial to do with an URL object.
### Safe vs Usually Safe vs Unsafe
Purell allows you to control the level of risk you take while normalizing an URL. You can aggressively normalize, play it totally safe, or anything in between.
Consider the following URL:
`HTTPS://www.RooT.com/toto/t%45%1f///a/./b/../c/?z=3&w=2&a=4&w=1#invalid`
Normalizing with the `FlagsSafe` gives:
`https://www.root.com/toto/tE%1F///a/./b/../c/?z=3&w=2&a=4&w=1#invalid`
With the `FlagsUsuallySafeGreedy`:
`https://www.root.com/toto/tE%1F///a/c?z=3&w=2&a=4&w=1#invalid`
And with `FlagsUnsafeGreedy`:
`http://root.com/toto/tE%1F/a/c?a=4&w=1&w=2&z=3`
## TODOs
* Add a class/default instance to allow specifying custom directory index names? At the moment, removing directory index removes `(^|/)((?:default|index)\.\w{1,4})$`.
## Thanks / Contributions
@rogpeppe
@jehiah
@opennota
@pchristopher1275
@zenovich
@beeker1121
## License
The [BSD 3-Clause license][bsd].
[bsd]: http://opensource.org/licenses/BSD-3-Clause
[wiki]: http://en.wikipedia.org/wiki/URL_normalization
[rfc]: http://tools.ietf.org/html/rfc3986#section-6
[godoc]: http://go.pkgdoc.org/github.com/PuerkitoBio/purell
[pr5]: https://github.com/PuerkitoBio/purell/pull/5
[iss7]: https://github.com/PuerkitoBio/purell/issues/7

View File

@@ -1,15 +0,0 @@
language: go
go:
- 1.4.x
- 1.5.x
- 1.6.x
- 1.7.x
- 1.8.x
- tip
install:
- go build .
script:
- go test -v

View File

@@ -1,16 +0,0 @@
urlesc [![Build Status](https://travis-ci.org/PuerkitoBio/urlesc.svg?branch=master)](https://travis-ci.org/PuerkitoBio/urlesc) [![GoDoc](http://godoc.org/github.com/PuerkitoBio/urlesc?status.svg)](http://godoc.org/github.com/PuerkitoBio/urlesc)
======
Package urlesc implements query escaping as per RFC 3986.
It contains some parts of the net/url package, modified so as to allow
some reserved characters incorrectly escaped by net/url (see [issue 5684](https://github.com/golang/go/issues/5684)).
## Install
go get github.com/PuerkitoBio/urlesc
## License
Go license (BSD-3-Clause)

View File

@@ -1,2 +0,0 @@
logrus
vendor

View File

@@ -1,52 +0,0 @@
language: go
go_import_path: github.com/sirupsen/logrus
env:
- GOMAXPROCS=4 GORACE=halt_on_error=1
matrix:
include:
- go: 1.10.x
install:
- go get github.com/stretchr/testify/assert
- go get golang.org/x/crypto/ssh/terminal
- go get golang.org/x/sys/unix
- go get golang.org/x/sys/windows
script:
- go test -race -v ./...
- go: 1.11.x
env: GO111MODULE=on
install:
- go mod download
script:
- go test -race -v ./...
- go: 1.11.x
env: GO111MODULE=off
install:
- go get github.com/stretchr/testify/assert
- go get golang.org/x/crypto/ssh/terminal
- go get golang.org/x/sys/unix
- go get golang.org/x/sys/windows
script:
- go test -race -v ./...
- go: 1.10.x
install:
- go get github.com/stretchr/testify/assert
- go get golang.org/x/crypto/ssh/terminal
- go get golang.org/x/sys/unix
- go get golang.org/x/sys/windows
script:
- go test -race -v -tags appengine ./...
- go: 1.11.x
env: GO111MODULE=on
install:
- go mod download
script:
- go test -race -v -tags appengine ./...
- go: 1.11.x
env: GO111MODULE=off
install:
- go get github.com/stretchr/testify/assert
- go get golang.org/x/crypto/ssh/terminal
- go get golang.org/x/sys/unix
- go get golang.org/x/sys/windows
script:
- go test -race -v -tags appengine ./...

View File

@@ -1,190 +0,0 @@
# 1.4.0
This new release introduces:
* Add `DeferExitHandler`, similar to `RegisterExitHandler` but prepending the handler to the list of handlers (semantically like `defer`) (#848).
* Add `CallerPrettyfier` to `JSONFormatter` and `TextFormatter (#909, #911)
* Add `Entry.WithContext()` and `Entry.Context`, to set a context on entries to be used e.g. in hooks (#919).
Fixes:
* Fix wrong method calls `Logger.Print` and `Logger.Warningln` (#893).
* Update `Entry.Logf` to not do string formatting unless the log level is enabled (#903)
* Fix infinite recursion on unknown `Level.String()` (#907)
* Fix race condition in `getCaller` (#916).
# 1.3.0
This new release introduces:
* Log, Logf, Logln functions for Logger and Entry that take a Level
Fixes:
* Building prometheus node_exporter on AIX (#840)
* Race condition in TextFormatter (#468)
* Travis CI import path (#868)
* Remove coloured output on Windows (#862)
* Pointer to func as field in JSONFormatter (#870)
* Properly marshal Levels (#873)
# 1.2.0
This new release introduces:
* A new method `SetReportCaller` in the `Logger` to enable the file, line and calling function from which the trace has been issued
* A new trace level named `Trace` whose level is below `Debug`
* A configurable exit function to be called upon a Fatal trace
* The `Level` object now implements `encoding.TextUnmarshaler` interface
# 1.1.1
This is a bug fix release.
* fix the build break on Solaris
* don't drop a whole trace in JSONFormatter when a field param is a function pointer which can not be serialized
# 1.1.0
This new release introduces:
* several fixes:
* a fix for a race condition on entry formatting
* proper cleanup of previously used entries before putting them back in the pool
* the extra new line at the end of message in text formatter has been removed
* a new global public API to check if a level is activated: IsLevelEnabled
* the following methods have been added to the Logger object
* IsLevelEnabled
* SetFormatter
* SetOutput
* ReplaceHooks
* introduction of go module
* an indent configuration for the json formatter
* output colour support for windows
* the field sort function is now configurable for text formatter
* the CLICOLOR and CLICOLOR\_FORCE environment variable support in text formater
# 1.0.6
This new release introduces:
* a new api WithTime which allows to easily force the time of the log entry
which is mostly useful for logger wrapper
* a fix reverting the immutability of the entry given as parameter to the hooks
a new configuration field of the json formatter in order to put all the fields
in a nested dictionnary
* a new SetOutput method in the Logger
* a new configuration of the textformatter to configure the name of the default keys
* a new configuration of the text formatter to disable the level truncation
# 1.0.5
* Fix hooks race (#707)
* Fix panic deadlock (#695)
# 1.0.4
* Fix race when adding hooks (#612)
* Fix terminal check in AppEngine (#635)
# 1.0.3
* Replace example files with testable examples
# 1.0.2
* bug: quote non-string values in text formatter (#583)
* Make (*Logger) SetLevel a public method
# 1.0.1
* bug: fix escaping in text formatter (#575)
# 1.0.0
* Officially changed name to lower-case
* bug: colors on Windows 10 (#541)
* bug: fix race in accessing level (#512)
# 0.11.5
* feature: add writer and writerlevel to entry (#372)
# 0.11.4
* bug: fix undefined variable on solaris (#493)
# 0.11.3
* formatter: configure quoting of empty values (#484)
* formatter: configure quoting character (default is `"`) (#484)
* bug: fix not importing io correctly in non-linux environments (#481)
# 0.11.2
* bug: fix windows terminal detection (#476)
# 0.11.1
* bug: fix tty detection with custom out (#471)
# 0.11.0
* performance: Use bufferpool to allocate (#370)
* terminal: terminal detection for app-engine (#343)
* feature: exit handler (#375)
# 0.10.0
* feature: Add a test hook (#180)
* feature: `ParseLevel` is now case-insensitive (#326)
* feature: `FieldLogger` interface that generalizes `Logger` and `Entry` (#308)
* performance: avoid re-allocations on `WithFields` (#335)
# 0.9.0
* logrus/text_formatter: don't emit empty msg
* logrus/hooks/airbrake: move out of main repository
* logrus/hooks/sentry: move out of main repository
* logrus/hooks/papertrail: move out of main repository
* logrus/hooks/bugsnag: move out of main repository
* logrus/core: run tests with `-race`
* logrus/core: detect TTY based on `stderr`
* logrus/core: support `WithError` on logger
* logrus/core: Solaris support
# 0.8.7
* logrus/core: fix possible race (#216)
* logrus/doc: small typo fixes and doc improvements
# 0.8.6
* hooks/raven: allow passing an initialized client
# 0.8.5
* logrus/core: revert #208
# 0.8.4
* formatter/text: fix data race (#218)
# 0.8.3
* logrus/core: fix entry log level (#208)
* logrus/core: improve performance of text formatter by 40%
* logrus/core: expose `LevelHooks` type
* logrus/core: add support for DragonflyBSD and NetBSD
* formatter/text: print structs more verbosely
# 0.8.2
* logrus: fix more Fatal family functions
# 0.8.1
* logrus: fix not exiting on `Fatalf` and `Fatalln`
# 0.8.0
* logrus: defaults to stderr instead of stdout
* hooks/sentry: add special field for `*http.Request`
* formatter/text: ignore Windows for colors
# 0.7.3
* formatter/\*: allow configuration of timestamp layout
# 0.7.2
* formatter/text: Add configuration option for time format (#158)

View File

@@ -1,495 +0,0 @@
# Logrus <img src="http://i.imgur.com/hTeVwmJ.png" width="40" height="40" alt=":walrus:" class="emoji" title=":walrus:"/>&nbsp;[![Build Status](https://travis-ci.org/sirupsen/logrus.svg?branch=master)](https://travis-ci.org/sirupsen/logrus)&nbsp;[![GoDoc](https://godoc.org/github.com/sirupsen/logrus?status.svg)](https://godoc.org/github.com/sirupsen/logrus)
Logrus is a structured logger for Go (golang), completely API compatible with
the standard library logger.
**Seeing weird case-sensitive problems?** It's in the past been possible to
import Logrus as both upper- and lower-case. Due to the Go package environment,
this caused issues in the community and we needed a standard. Some environments
experienced problems with the upper-case variant, so the lower-case was decided.
Everything using `logrus` will need to use the lower-case:
`github.com/sirupsen/logrus`. Any package that isn't, should be changed.
To fix Glide, see [these
comments](https://github.com/sirupsen/logrus/issues/553#issuecomment-306591437).
For an in-depth explanation of the casing issue, see [this
comment](https://github.com/sirupsen/logrus/issues/570#issuecomment-313933276).
**Are you interested in assisting in maintaining Logrus?** Currently I have a
lot of obligations, and I am unable to provide Logrus with the maintainership it
needs. If you'd like to help, please reach out to me at `simon at author's
username dot com`.
Nicely color-coded in development (when a TTY is attached, otherwise just
plain text):
![Colored](http://i.imgur.com/PY7qMwd.png)
With `log.SetFormatter(&log.JSONFormatter{})`, for easy parsing by logstash
or Splunk:
```json
{"animal":"walrus","level":"info","msg":"A group of walrus emerges from the
ocean","size":10,"time":"2014-03-10 19:57:38.562264131 -0400 EDT"}
{"level":"warning","msg":"The group's number increased tremendously!",
"number":122,"omg":true,"time":"2014-03-10 19:57:38.562471297 -0400 EDT"}
{"animal":"walrus","level":"info","msg":"A giant walrus appears!",
"size":10,"time":"2014-03-10 19:57:38.562500591 -0400 EDT"}
{"animal":"walrus","level":"info","msg":"Tremendously sized cow enters the ocean.",
"size":9,"time":"2014-03-10 19:57:38.562527896 -0400 EDT"}
{"level":"fatal","msg":"The ice breaks!","number":100,"omg":true,
"time":"2014-03-10 19:57:38.562543128 -0400 EDT"}
```
With the default `log.SetFormatter(&log.TextFormatter{})` when a TTY is not
attached, the output is compatible with the
[logfmt](http://godoc.org/github.com/kr/logfmt) format:
```text
time="2015-03-26T01:27:38-04:00" level=debug msg="Started observing beach" animal=walrus number=8
time="2015-03-26T01:27:38-04:00" level=info msg="A group of walrus emerges from the ocean" animal=walrus size=10
time="2015-03-26T01:27:38-04:00" level=warning msg="The group's number increased tremendously!" number=122 omg=true
time="2015-03-26T01:27:38-04:00" level=debug msg="Temperature changes" temperature=-4
time="2015-03-26T01:27:38-04:00" level=panic msg="It's over 9000!" animal=orca size=9009
time="2015-03-26T01:27:38-04:00" level=fatal msg="The ice breaks!" err=&{0x2082280c0 map[animal:orca size:9009] 2015-03-26 01:27:38.441574009 -0400 EDT panic It's over 9000!} number=100 omg=true
```
To ensure this behaviour even if a TTY is attached, set your formatter as follows:
```go
log.SetFormatter(&log.TextFormatter{
DisableColors: true,
FullTimestamp: true,
})
```
#### Logging Method Name
If you wish to add the calling method as a field, instruct the logger via:
```go
log.SetReportCaller(true)
```
This adds the caller as 'method' like so:
```json
{"animal":"penguin","level":"fatal","method":"github.com/sirupsen/arcticcreatures.migrate","msg":"a penguin swims by",
"time":"2014-03-10 19:57:38.562543129 -0400 EDT"}
```
```text
time="2015-03-26T01:27:38-04:00" level=fatal method=github.com/sirupsen/arcticcreatures.migrate msg="a penguin swims by" animal=penguin
```
Note that this does add measurable overhead - the cost will depend on the version of Go, but is
between 20 and 40% in recent tests with 1.6 and 1.7. You can validate this in your
environment via benchmarks:
```
go test -bench=.*CallerTracing
```
#### Case-sensitivity
The organization's name was changed to lower-case--and this will not be changed
back. If you are getting import conflicts due to case sensitivity, please use
the lower-case import: `github.com/sirupsen/logrus`.
#### Example
The simplest way to use Logrus is simply the package-level exported logger:
```go
package main
import (
log "github.com/sirupsen/logrus"
)
func main() {
log.WithFields(log.Fields{
"animal": "walrus",
}).Info("A walrus appears")
}
```
Note that it's completely api-compatible with the stdlib logger, so you can
replace your `log` imports everywhere with `log "github.com/sirupsen/logrus"`
and you'll now have the flexibility of Logrus. You can customize it all you
want:
```go
package main
import (
"os"
log "github.com/sirupsen/logrus"
)
func init() {
// Log as JSON instead of the default ASCII formatter.
log.SetFormatter(&log.JSONFormatter{})
// Output to stdout instead of the default stderr
// Can be any io.Writer, see below for File example
log.SetOutput(os.Stdout)
// Only log the warning severity or above.
log.SetLevel(log.WarnLevel)
}
func main() {
log.WithFields(log.Fields{
"animal": "walrus",
"size": 10,
}).Info("A group of walrus emerges from the ocean")
log.WithFields(log.Fields{
"omg": true,
"number": 122,
}).Warn("The group's number increased tremendously!")
log.WithFields(log.Fields{
"omg": true,
"number": 100,
}).Fatal("The ice breaks!")
// A common pattern is to re-use fields between logging statements by re-using
// the logrus.Entry returned from WithFields()
contextLogger := log.WithFields(log.Fields{
"common": "this is a common field",
"other": "I also should be logged always",
})
contextLogger.Info("I'll be logged with common and other field")
contextLogger.Info("Me too")
}
```
For more advanced usage such as logging to multiple locations from the same
application, you can also create an instance of the `logrus` Logger:
```go
package main
import (
"os"
"github.com/sirupsen/logrus"
)
// Create a new instance of the logger. You can have any number of instances.
var log = logrus.New()
func main() {
// The API for setting attributes is a little different than the package level
// exported logger. See Godoc.
log.Out = os.Stdout
// You could set this to any `io.Writer` such as a file
// file, err := os.OpenFile("logrus.log", os.O_CREATE|os.O_WRONLY, 0666)
// if err == nil {
// log.Out = file
// } else {
// log.Info("Failed to log to file, using default stderr")
// }
log.WithFields(logrus.Fields{
"animal": "walrus",
"size": 10,
}).Info("A group of walrus emerges from the ocean")
}
```
#### Fields
Logrus encourages careful, structured logging through logging fields instead of
long, unparseable error messages. For example, instead of: `log.Fatalf("Failed
to send event %s to topic %s with key %d")`, you should log the much more
discoverable:
```go
log.WithFields(log.Fields{
"event": event,
"topic": topic,
"key": key,
}).Fatal("Failed to send event")
```
We've found this API forces you to think about logging in a way that produces
much more useful logging messages. We've been in countless situations where just
a single added field to a log statement that was already there would've saved us
hours. The `WithFields` call is optional.
In general, with Logrus using any of the `printf`-family functions should be
seen as a hint you should add a field, however, you can still use the
`printf`-family functions with Logrus.
#### Default Fields
Often it's helpful to have fields _always_ attached to log statements in an
application or parts of one. For example, you may want to always log the
`request_id` and `user_ip` in the context of a request. Instead of writing
`log.WithFields(log.Fields{"request_id": request_id, "user_ip": user_ip})` on
every line, you can create a `logrus.Entry` to pass around instead:
```go
requestLogger := log.WithFields(log.Fields{"request_id": request_id, "user_ip": user_ip})
requestLogger.Info("something happened on that request") # will log request_id and user_ip
requestLogger.Warn("something not great happened")
```
#### Hooks
You can add hooks for logging levels. For example to send errors to an exception
tracking service on `Error`, `Fatal` and `Panic`, info to StatsD or log to
multiple places simultaneously, e.g. syslog.
Logrus comes with [built-in hooks](hooks/). Add those, or your custom hook, in
`init`:
```go
import (
log "github.com/sirupsen/logrus"
"gopkg.in/gemnasium/logrus-airbrake-hook.v2" // the package is named "airbrake"
logrus_syslog "github.com/sirupsen/logrus/hooks/syslog"
"log/syslog"
)
func init() {
// Use the Airbrake hook to report errors that have Error severity or above to
// an exception tracker. You can create custom hooks, see the Hooks section.
log.AddHook(airbrake.NewHook(123, "xyz", "production"))
hook, err := logrus_syslog.NewSyslogHook("udp", "localhost:514", syslog.LOG_INFO, "")
if err != nil {
log.Error("Unable to connect to local syslog daemon")
} else {
log.AddHook(hook)
}
}
```
Note: Syslog hook also support connecting to local syslog (Ex. "/dev/log" or "/var/run/syslog" or "/var/run/log"). For the detail, please check the [syslog hook README](hooks/syslog/README.md).
A list of currently known of service hook can be found in this wiki [page](https://github.com/sirupsen/logrus/wiki/Hooks)
#### Level logging
Logrus has seven logging levels: Trace, Debug, Info, Warning, Error, Fatal and Panic.
```go
log.Trace("Something very low level.")
log.Debug("Useful debugging information.")
log.Info("Something noteworthy happened!")
log.Warn("You should probably take a look at this.")
log.Error("Something failed but I'm not quitting.")
// Calls os.Exit(1) after logging
log.Fatal("Bye.")
// Calls panic() after logging
log.Panic("I'm bailing.")
```
You can set the logging level on a `Logger`, then it will only log entries with
that severity or anything above it:
```go
// Will log anything that is info or above (warn, error, fatal, panic). Default.
log.SetLevel(log.InfoLevel)
```
It may be useful to set `log.Level = logrus.DebugLevel` in a debug or verbose
environment if your application has that.
#### Entries
Besides the fields added with `WithField` or `WithFields` some fields are
automatically added to all logging events:
1. `time`. The timestamp when the entry was created.
2. `msg`. The logging message passed to `{Info,Warn,Error,Fatal,Panic}` after
the `AddFields` call. E.g. `Failed to send event.`
3. `level`. The logging level. E.g. `info`.
#### Environments
Logrus has no notion of environment.
If you wish for hooks and formatters to only be used in specific environments,
you should handle that yourself. For example, if your application has a global
variable `Environment`, which is a string representation of the environment you
could do:
```go
import (
log "github.com/sirupsen/logrus"
)
init() {
// do something here to set environment depending on an environment variable
// or command-line flag
if Environment == "production" {
log.SetFormatter(&log.JSONFormatter{})
} else {
// The TextFormatter is default, you don't actually have to do this.
log.SetFormatter(&log.TextFormatter{})
}
}
```
This configuration is how `logrus` was intended to be used, but JSON in
production is mostly only useful if you do log aggregation with tools like
Splunk or Logstash.
#### Formatters
The built-in logging formatters are:
* `logrus.TextFormatter`. Logs the event in colors if stdout is a tty, otherwise
without colors.
* *Note:* to force colored output when there is no TTY, set the `ForceColors`
field to `true`. To force no colored output even if there is a TTY set the
`DisableColors` field to `true`. For Windows, see
[github.com/mattn/go-colorable](https://github.com/mattn/go-colorable).
* When colors are enabled, levels are truncated to 4 characters by default. To disable
truncation set the `DisableLevelTruncation` field to `true`.
* All options are listed in the [generated docs](https://godoc.org/github.com/sirupsen/logrus#TextFormatter).
* `logrus.JSONFormatter`. Logs fields as JSON.
* All options are listed in the [generated docs](https://godoc.org/github.com/sirupsen/logrus#JSONFormatter).
Third party logging formatters:
* [`FluentdFormatter`](https://github.com/joonix/log). Formats entries that can be parsed by Kubernetes and Google Container Engine.
* [`GELF`](https://github.com/fabienm/go-logrus-formatters). Formats entries so they comply to Graylog's [GELF 1.1 specification](http://docs.graylog.org/en/2.4/pages/gelf.html).
* [`logstash`](https://github.com/bshuster-repo/logrus-logstash-hook). Logs fields as [Logstash](http://logstash.net) Events.
* [`prefixed`](https://github.com/x-cray/logrus-prefixed-formatter). Displays log entry source along with alternative layout.
* [`zalgo`](https://github.com/aybabtme/logzalgo). Invoking the P͉̫o̳̼̊w̖͈̰͎e̬͔̭͂r͚̼̹̲ ̫͓͉̳͈ō̠͕͖̚f̝͍̠ ͕̲̞͖͑Z̖̫̤̫ͪa͉̬͈̗l͖͎g̳̥o̰̥̅!̣͔̲̻͊̄ ̙̘̦̹̦.
* [`nested-logrus-formatter`](https://github.com/antonfisher/nested-logrus-formatter). Converts logrus fields to a nested structure.
You can define your formatter by implementing the `Formatter` interface,
requiring a `Format` method. `Format` takes an `*Entry`. `entry.Data` is a
`Fields` type (`map[string]interface{}`) with all your fields as well as the
default ones (see Entries section above):
```go
type MyJSONFormatter struct {
}
log.SetFormatter(new(MyJSONFormatter))
func (f *MyJSONFormatter) Format(entry *Entry) ([]byte, error) {
// Note this doesn't include Time, Level and Message which are available on
// the Entry. Consult `godoc` on information about those fields or read the
// source of the official loggers.
serialized, err := json.Marshal(entry.Data)
if err != nil {
return nil, fmt.Errorf("Failed to marshal fields to JSON, %v", err)
}
return append(serialized, '\n'), nil
}
```
#### Logger as an `io.Writer`
Logrus can be transformed into an `io.Writer`. That writer is the end of an `io.Pipe` and it is your responsibility to close it.
```go
w := logger.Writer()
defer w.Close()
srv := http.Server{
// create a stdlib log.Logger that writes to
// logrus.Logger.
ErrorLog: log.New(w, "", 0),
}
```
Each line written to that writer will be printed the usual way, using formatters
and hooks. The level for those entries is `info`.
This means that we can override the standard library logger easily:
```go
logger := logrus.New()
logger.Formatter = &logrus.JSONFormatter{}
// Use logrus for standard log output
// Note that `log` here references stdlib's log
// Not logrus imported under the name `log`.
log.SetOutput(logger.Writer())
```
#### Rotation
Log rotation is not provided with Logrus. Log rotation should be done by an
external program (like `logrotate(8)`) that can compress and delete old log
entries. It should not be a feature of the application-level logger.
#### Tools
| Tool | Description |
| ---- | ----------- |
|[Logrus Mate](https://github.com/gogap/logrus_mate)|Logrus mate is a tool for Logrus to manage loggers, you can initial logger's level, hook and formatter by config file, the logger will generated with different config at different environment.|
|[Logrus Viper Helper](https://github.com/heirko/go-contrib/tree/master/logrusHelper)|An Helper around Logrus to wrap with spf13/Viper to load configuration with fangs! And to simplify Logrus configuration use some behavior of [Logrus Mate](https://github.com/gogap/logrus_mate). [sample](https://github.com/heirko/iris-contrib/blob/master/middleware/logrus-logger/example) |
#### Testing
Logrus has a built in facility for asserting the presence of log messages. This is implemented through the `test` hook and provides:
* decorators for existing logger (`test.NewLocal` and `test.NewGlobal`) which basically just add the `test` hook
* a test logger (`test.NewNullLogger`) that just records log messages (and does not output any):
```go
import(
"github.com/sirupsen/logrus"
"github.com/sirupsen/logrus/hooks/test"
"github.com/stretchr/testify/assert"
"testing"
)
func TestSomething(t*testing.T){
logger, hook := test.NewNullLogger()
logger.Error("Helloerror")
assert.Equal(t, 1, len(hook.Entries))
assert.Equal(t, logrus.ErrorLevel, hook.LastEntry().Level)
assert.Equal(t, "Helloerror", hook.LastEntry().Message)
hook.Reset()
assert.Nil(t, hook.LastEntry())
}
```
#### Fatal handlers
Logrus can register one or more functions that will be called when any `fatal`
level message is logged. The registered handlers will be executed before
logrus performs a `os.Exit(1)`. This behavior may be helpful if callers need
to gracefully shutdown. Unlike a `panic("Something went wrong...")` call which can be intercepted with a deferred `recover` a call to `os.Exit(1)` can not be intercepted.
```
...
handler := func() {
// gracefully shutdown something...
}
logrus.RegisterExitHandler(handler)
...
```
#### Thread safety
By default, Logger is protected by a mutex for concurrent writes. The mutex is held when calling hooks and writing logs.
If you are sure such locking is not needed, you can call logger.SetNoLock() to disable the locking.
Situation when locking is not needed includes:
* You have no hooks registered, or hooks calling is already thread-safe.
* Writing to logger.Out is already thread-safe, for example:
1) logger.Out is protected by locks.
2) logger.Out is a os.File handler opened with `O_APPEND` flag, and every write is smaller than 4k. (This allow multi-thread/multi-process writing)
(Refer to http://www.notthewizard.com/2014/06/17/are-files-appends-really-atomic/)

View File

@@ -1,14 +0,0 @@
version: "{build}"
platform: x64
clone_folder: c:\gopath\src\github.com\sirupsen\logrus
environment:
GOPATH: c:\gopath
branches:
only:
- master
install:
- set PATH=%GOPATH%\bin;c:\go\bin;%PATH%
- go version
build_script:
- go get -t
- go test

View File

@@ -1,11 +0,0 @@
module github.com/sirupsen/logrus
require (
github.com/davecgh/go-spew v1.1.1 // indirect
github.com/konsorten/go-windows-terminal-sequences v1.0.1
github.com/pmezard/go-difflib v1.0.0 // indirect
github.com/stretchr/objx v0.1.1 // indirect
github.com/stretchr/testify v1.2.2
golang.org/x/crypto v0.0.0-20180904163835-0709b304e793
golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33
)

View File

@@ -1,15 +0,0 @@
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/konsorten/go-windows-terminal-sequences v0.0.0-20180402223658-b729f2633dfe h1:CHRGQ8V7OlCYtwaKPJi3iA7J+YdNKdo8j7nG5IgDhjs=
github.com/konsorten/go-windows-terminal-sequences v0.0.0-20180402223658-b729f2633dfe/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/stretchr/objx v0.1.1 h1:2vfRuCMp5sSVIDSqO8oNnWJq7mPa6KVP3iPIwFBuy8A=
github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/testify v1.2.2 h1:bSDNvY7ZPG5RlJ8otE/7V6gMiyenm9RtJ7IUVIAoJ1w=
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
golang.org/x/crypto v0.0.0-20180904163835-0709b304e793 h1:u+LnwYTOOW7Ukr/fppxEb1Nwz0AtPflrblfvUudpo+I=
golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33 h1:I6FyU15t786LL7oL/hn43zqTuEGr4PN7F4XJ1p4E3Y8=
golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=

View File

@@ -1,25 +0,0 @@
# Compiled Object files, Static and Dynamic libs (Shared Objects)
*.o
*.a
*.so
# Folders
_obj
_test
.vscode
# Architecture specific extensions/prefixes
*.[568vq]
[568vq].out
*.cgo1.go
*.cgo2.c
_cgo_defun.c
_cgo_gotypes.go
_cgo_export.*
_testmain.go
*.exe
*.test
*.prof

View File

@@ -1,25 +0,0 @@
language: go
go:
- "1.8.x"
- "1.9.x"
- "1.10.x"
env:
- TRAVIS_GOARCH=amd64
- TRAVIS_GOARCH=386
before_install:
- export GOARCH=$TRAVIS_GOARCH
branches:
only:
- master
before_script:
- go get -u github.com/klauspost/asmfmt/cmd/asmfmt
script:
- diff -au <(gofmt -d .) <(printf "")
- diff -au <(asmfmt -d .) <(printf "")
- go test -v ./...

View File

@@ -1,82 +0,0 @@
[![Godoc Reference](https://godoc.org/github.com/aead/chacha20?status.svg)](https://godoc.org/github.com/aead/chacha20)
[![Build Status](https://travis-ci.org/aead/chacha20.svg?branch=master)](https://travis-ci.org/aead/chacha20)
[![Go Report Card](https://goreportcard.com/badge/aead/chacha20)](https://goreportcard.com/report/aead/chacha20)
## The ChaCha20 stream cipher
ChaCha is a stream cipher family created by Daniel J. Bernstein.
The most common ChaCha variant is ChaCha20 (20 rounds). ChaCha20 is
standardized in [RFC 7539](https://tools.ietf.org/html/rfc7539 "RFC 7539").
This package provides implementations of three ChaCha versions:
- ChaCha20 with a 64 bit nonce (can en/decrypt up to 2^64 * 64 bytes for one key-nonce combination)
- ChaCha20 with a 96 bit nonce (can en/decrypt up to 2^32 * 64 bytes ~ 256 GB for one key-nonce combination)
- XChaCha20 with a 192 bit nonce (can en/decrypt up to 2^64 * 64 bytes for one key-nonce combination)
Furthermore the chacha sub package implements ChaCha20/12 and ChaCha20/8.
These versions use 12 or 8 rounds instead of 20.
But it's recommended to use ChaCha20 (with 20 rounds) - it will be fast enough for almost all purposes.
### Installation
Install in your GOPATH: `go get -u github.com/aead/chacha20`
### Requirements
All go versions >= 1.8.7 are supported.
The code may also work on Go 1.7 but this is not tested.
### Performance
#### AMD64
Hardware: Intel i7-6500U 2.50GHz x 2
System: Linux Ubuntu 16.04 - kernel: 4.4.0-62-generic
Go version: 1.8.0
```
AVX2
name speed cpb
ChaCha20_64-4 573MB/s ± 0% 4.16
ChaCha20_1K-4 2.19GB/s ± 0% 1.06
XChaCha20_64-4 261MB/s ± 0% 9.13
XChaCha20_1K-4 1.69GB/s ± 4% 1.37
XORKeyStream64-4 474MB/s ± 2% 5.02
XORKeyStream1K-4 2.09GB/s ± 1% 1.11
XChaCha20_XORKeyStream64-4 262MB/s ± 0% 9.09
XChaCha20_XORKeyStream1K-4 1.71GB/s ± 1% 1.36
SSSE3
name speed cpb
ChaCha20_64-4 583MB/s ± 0% 4.08
ChaCha20_1K-4 1.15GB/s ± 1% 2.02
XChaCha20_64-4 267MB/s ± 0% 8.92
XChaCha20_1K-4 984MB/s ± 5% 2.42
XORKeyStream64-4 492MB/s ± 1% 4.84
XORKeyStream1K-4 1.10GB/s ± 5% 2.11
XChaCha20_XORKeyStream64-4 266MB/s ± 0% 8.96
XChaCha20_XORKeyStream1K-4 1.00GB/s ± 2% 2.32
```
#### 386
Hardware: Intel i7-6500U 2.50GHz x 2
System: Linux Ubuntu 16.04 - kernel: 4.4.0-62-generic
Go version: 1.8.0
```
SSSE3
name                        speed cpb
ChaCha20_64-4               570MB/s ± 0% 4.18
ChaCha20_1K-4               650MB/s ± 0% 3.66
XChaCha20_64-4              223MB/s ± 0% 10.69
XChaCha20_1K-4              584MB/s ± 1% 4.08
XORKeyStream64-4            392MB/s ± 1% 6.08
XORKeyStream1K-4            629MB/s ± 1% 3.79
XChaCha20_XORKeyStream64-4  222MB/s ± 0% 10.73
XChaCha20_XORKeyStream1K-4  585MB/s ± 0% 4.07
SSE2
name speed cpb
ChaCha20_64-4 509MB/s ± 0% 4.68
ChaCha20_1K-4 553MB/s ± 2% 4.31
XChaCha20_64-4 201MB/s ± 0% 11.86
XChaCha20_1K-4 498MB/s ± 4% 4.78
XORKeyStream64-4 359MB/s ± 1% 6.64
XORKeyStream1K-4 545MB/s ± 0% 4.37
XChaCha20_XORKeyStream64-4 201MB/s ± 1% 11.86
XChaCha20_XORKeyStream1K-4 507MB/s ± 0% 4.70
```

View File

@@ -8,20 +8,22 @@ import (
"strings"
)
var errBadJSONDoc = fmt.Errorf("Invalid JSON Document")
var errBadJSONDoc = fmt.Errorf("invalid JSON Document")
type JsonPatchOperation struct {
type JsonPatchOperation = Operation
type Operation struct {
Operation string `json:"op"`
Path string `json:"path"`
Value interface{} `json:"value,omitempty"`
}
func (j *JsonPatchOperation) Json() string {
func (j *Operation) Json() string {
b, _ := json.Marshal(j)
return string(b)
}
func (j *JsonPatchOperation) MarshalJSON() ([]byte, error) {
func (j *Operation) MarshalJSON() ([]byte, error) {
var b bytes.Buffer
b.WriteString("{")
b.WriteString(fmt.Sprintf(`"op":"%s"`, j.Operation))
@@ -39,14 +41,14 @@ func (j *JsonPatchOperation) MarshalJSON() ([]byte, error) {
return b.Bytes(), nil
}
type ByPath []JsonPatchOperation
type ByPath []Operation
func (a ByPath) Len() int { return len(a) }
func (a ByPath) Swap(i, j int) { a[i], a[j] = a[j], a[i] }
func (a ByPath) Less(i, j int) bool { return a[i].Path < a[j].Path }
func NewPatch(operation, path string, value interface{}) JsonPatchOperation {
return JsonPatchOperation{Operation: operation, Path: path, Value: value}
func NewPatch(operation, path string, value interface{}) Operation {
return Operation{Operation: operation, Path: path, Value: value}
}
// CreatePatch creates a patch as specified in http://jsonpatch.com/
@@ -55,7 +57,7 @@ func NewPatch(operation, path string, value interface{}) JsonPatchOperation {
// The function will return an array of JsonPatchOperations
//
// An error will be returned if any of the two documents are invalid.
func CreatePatch(a, b []byte) ([]JsonPatchOperation, error) {
func CreatePatch(a, b []byte) ([]Operation, error) {
aI := map[string]interface{}{}
bI := map[string]interface{}{}
err := json.Unmarshal(a, &aI)
@@ -66,7 +68,7 @@ func CreatePatch(a, b []byte) ([]JsonPatchOperation, error) {
if err != nil {
return nil, errBadJSONDoc
}
return diff(aI, bI, "", []JsonPatchOperation{})
return diff(aI, bI, "", []Operation{})
}
// Returns true if the values matches (must be json types)
@@ -78,22 +80,25 @@ func matchesValue(av, bv interface{}) bool {
}
switch at := av.(type) {
case string:
bt := bv.(string)
if bt == at {
bt, ok := bv.(string)
if ok && bt == at {
return true
}
case float64:
bt := bv.(float64)
if bt == at {
bt, ok := bv.(float64)
if ok && bt == at {
return true
}
case bool:
bt := bv.(bool)
if bt == at {
bt, ok := bv.(bool)
if ok && bt == at {
return true
}
case map[string]interface{}:
bt := bv.(map[string]interface{})
bt, ok := bv.(map[string]interface{})
if !ok {
return false
}
for key := range at {
if !matchesValue(at[key], bt[key]) {
return false
@@ -106,7 +111,10 @@ func matchesValue(av, bv interface{}) bool {
}
return true
case []interface{}:
bt := bv.([]interface{})
bt, ok := bv.([]interface{})
if !ok {
return false
}
if len(bt) != len(at) {
return false
}
@@ -148,7 +156,7 @@ func makePath(path string, newPart interface{}) string {
}
// diff returns the (recursive) difference between a and b as an array of JsonPatchOperations.
func diff(a, b map[string]interface{}, path string, patch []JsonPatchOperation) ([]JsonPatchOperation, error) {
func diff(a, b map[string]interface{}, path string, patch []Operation) ([]Operation, error) {
for key, bv := range b {
p := makePath(path, key)
av, ok := a[key]
@@ -157,11 +165,6 @@ func diff(a, b map[string]interface{}, path string, patch []JsonPatchOperation)
patch = append(patch, NewPatch("add", p, bv))
continue
}
// If types have changed, replace completely
if reflect.TypeOf(av) != reflect.TypeOf(bv) {
patch = append(patch, NewPatch("replace", p, bv))
continue
}
// Types are the same, compare values
var err error
patch, err = handleValues(av, bv, p, patch)
@@ -181,7 +184,21 @@ func diff(a, b map[string]interface{}, path string, patch []JsonPatchOperation)
return patch, nil
}
func handleValues(av, bv interface{}, p string, patch []JsonPatchOperation) ([]JsonPatchOperation, error) {
func handleValues(av, bv interface{}, p string, patch []Operation) ([]Operation, error) {
{
at := reflect.TypeOf(av)
bt := reflect.TypeOf(bv)
if at == nil && bt == nil {
// do nothing
return patch, nil
} else if at == nil && bt != nil {
return append(patch, NewPatch("add", p, bv)), nil
} else if at != bt {
// If types have changed, replace completely (preserves null in destination)
return append(patch, NewPatch("replace", p, bv)), nil
}
}
var err error
switch at := av.(type) {
case map[string]interface{}:
@@ -195,63 +212,125 @@ func handleValues(av, bv interface{}, p string, patch []JsonPatchOperation) ([]J
patch = append(patch, NewPatch("replace", p, bv))
}
case []interface{}:
bt, ok := bv.([]interface{})
if !ok {
// array replaced by non-array
patch = append(patch, NewPatch("replace", p, bv))
} else if len(at) != len(bt) {
// arrays are not the same length
patch = append(patch, compareArray(at, bt, p)...)
bt := bv.([]interface{})
if isSimpleArray(at) && isSimpleArray(bt) {
patch = append(patch, compareEditDistance(at, bt, p)...)
} else {
for i := range bt {
n := min(len(at), len(bt))
for i := len(at) - 1; i >= n; i-- {
patch = append(patch, NewPatch("remove", makePath(p, i), nil))
}
for i := n; i < len(bt); i++ {
patch = append(patch, NewPatch("add", makePath(p, i), bt[i]))
}
for i := 0; i < n; i++ {
var err error
patch, err = handleValues(at[i], bt[i], makePath(p, i), patch)
if err != nil {
return nil, err
}
}
}
case nil:
switch bv.(type) {
case nil:
// Both nil, fine.
default:
patch = append(patch, NewPatch("add", p, bv))
}
default:
panic(fmt.Sprintf("Unknown type:%T ", av))
}
return patch, nil
}
func compareArray(av, bv []interface{}, p string) []JsonPatchOperation {
retval := []JsonPatchOperation{}
// var err error
for i, v := range av {
found := false
for _, v2 := range bv {
if reflect.DeepEqual(v, v2) {
found = true
break
}
}
if !found {
retval = append(retval, NewPatch("remove", makePath(p, i), nil))
}
func isBasicType(a interface{}) bool {
switch a.(type) {
case string, float64, bool:
default:
return false
}
for i, v := range bv {
found := false
for _, v2 := range av {
if reflect.DeepEqual(v, v2) {
found = true
break
}
}
if !found {
retval = append(retval, NewPatch("add", makePath(p, i), v))
}
}
return retval
return true
}
func isSimpleArray(a []interface{}) bool {
for i := range a {
switch a[i].(type) {
case string, float64, bool:
default:
val := reflect.ValueOf(a[i])
if val.Kind() == reflect.Map {
for _, k := range val.MapKeys() {
av := val.MapIndex(k)
if av.Kind() == reflect.Ptr || av.Kind() == reflect.Interface {
if av.IsNil() {
continue
}
av = av.Elem()
}
if av.Kind() != reflect.String && av.Kind() != reflect.Float64 && av.Kind() != reflect.Bool {
return false
}
}
return true
}
return false
}
}
return true
}
// https://en.wikipedia.org/wiki/Wagner%E2%80%93Fischer_algorithm
// Adapted from https://github.com/texttheater/golang-levenshtein
func compareEditDistance(s, t []interface{}, p string) []Operation {
m := len(s)
n := len(t)
d := make([][]int, m+1)
for i := 0; i <= m; i++ {
d[i] = make([]int, n+1)
d[i][0] = i
}
for j := 0; j <= n; j++ {
d[0][j] = j
}
for j := 1; j <= n; j++ {
for i := 1; i <= m; i++ {
if reflect.DeepEqual(s[i-1], t[j-1]) {
d[i][j] = d[i-1][j-1] // no op required
} else {
del := d[i-1][j] + 1
add := d[i][j-1] + 1
rep := d[i-1][j-1] + 1
d[i][j] = min(rep, min(add, del))
}
}
}
return backtrace(s, t, p, m, n, d)
}
func min(x int, y int) int {
if y < x {
return y
}
return x
}
func backtrace(s, t []interface{}, p string, i int, j int, matrix [][]int) []Operation {
if i > 0 && matrix[i-1][j]+1 == matrix[i][j] {
op := NewPatch("remove", makePath(p, i-1), nil)
return append([]Operation{op}, backtrace(s, t, p, i-1, j, matrix)...)
}
if j > 0 && matrix[i][j-1]+1 == matrix[i][j] {
op := NewPatch("add", makePath(p, i), t[j-1])
return append([]Operation{op}, backtrace(s, t, p, i, j-1, matrix)...)
}
if i > 0 && j > 0 && matrix[i-1][j-1]+1 == matrix[i][j] {
if isBasicType(s[0]) {
op := NewPatch("replace", makePath(p, i-1), t[j-1])
return append([]Operation{op}, backtrace(s, t, p, i-1, j-1, matrix)...)
}
p2, _ := handleValues(s[j-1], t[j-1], makePath(p, i-1), []Operation{})
return append(p2, backtrace(s, t, p, i-1, j-1, matrix)...)
}
if i > 0 && j > 0 && matrix[i-1][j-1] == matrix[i][j] {
return backtrace(s, t, p, i-1, j-1, matrix)
}
return []Operation{}
}

File diff suppressed because it is too large Load Diff

View File

@@ -1,94 +0,0 @@
![A lock with a mint leaf](https://ipv.sx/mint/mint.svg)
mint - A Minimal TLS 1.3 stack
==============================
[![Build Status](https://circleci.com/gh/bifurcation/mint.svg)](https://circleci.com/gh/bifurcation/mint)
This project is primarily a learning effort for me to understand the [TLS
1.3](http://tlswg.github.io/tls13-spec/) protocol. The goal is to arrive at a
pretty complete implementation of TLS 1.3, with minimal, elegant code that
demonstrates how things work. Testing is a priority to ensure correctness, but
otherwise, the quality of the software engineering might not be at a level where
it makes sense to integrate this with other libraries. Backward compatibility
is not an objective.
We borrow liberally from the [Go TLS
library](https://golang.org/pkg/crypto/tls/), especially where TLS 1.3 aligns
with earlier TLS versions. However, unnecessary parts will be ruthlessly cut
off.
## DTLS Support
Mint has partial support for DTLS, but that support is not yet complete
and may still contain serious defects.
## Quickstart
Installation is the same as for any other Go package:
```
go get github.com/bifurcation/mint
```
The API is pretty much the same as for the TLS module, with `Dial` and `Listen`
methods wrapping the underlying socket APIs.
```
conn, err := mint.Dial("tcp", "localhost:4430", &mint.Config{...})
...
listener, err := mint.Listen("tcp", "localhost:4430", &mint.Config{...})
```
Documentation is available on
[godoc.org](https://godoc.org/github.com/bifurcation/mint)
## Interoperability testing
The `mint-client` and `mint-server` executables are included to make it easy to
do basic interoperability tests with other TLS 1.3 implementations. The steps
for testing against NSS are as follows.
```
# Install mint
go get github.com/bifurcation/mint
# Environment for NSS (you'll probably want a new directory)
NSS_ROOT=<whereever you want to put NSS>
mkdir $NSS_ROOT
cd $NSS_ROOT
export USE_64=1
export ENABLE_TLS_1_3=1
export HOST=localhost
export DOMSUF=localhost
# Build NSS
hg clone https://hg.mozilla.org/projects/nss
hg clone https://hg.mozilla.org/projects/nspr
cd nss
make nss_build_all
export PLATFORM=`cat $NSS_ROOT/dist/latest`
export DYLD_LIBRARY_PATH=$NSS_ROOT/dist/$PLATFORM/lib
export LD_LIBRARY_PATH=$NSS_ROOT/dist/$PLATFORM/lib
# Run NSS tests (this creates data for the server to use)
cd tests/ssl_gtests
./ssl_gtests.sh
# Test with client=mint server=NSS
cd $NSS_ROOT
./dist/$PLATFORM/bin/selfserv -d tests_results/security/$HOST.1/ssl_gtests/ -n rsa -p 4430
# if you get `NSS_Init failed.`, check the path above, particularly around $HOST
# ...
go run $GOPATH/src/github.com/bifurcation/mint/bin/mint-client/main.go
# Test with client=NSS server=mint
go run $GOPATH/src/github.com/bifurcation/mint/bin/mint-server/main.go
# ...
cd $NSS_ROOT
dist/$PLATFORM/bin/tstclnt -d tests_results/security/$HOST/ssl_gtests/ -V tls1.3:tls1.3 -h 127.0.0.1 -p 4430 -o
```

View File

@@ -89,7 +89,7 @@ func (state clientStateStart) Next(hr handshakeMessageReader) (HandshakeState, [
logf(logTypeHandshake, "opts: %+v", state.Opts)
// supported_versions, supported_groups, signature_algorithms, server_name
sv := SupportedVersionsExtension{HandshakeType: HandshakeTypeClientHello, Versions: []uint16{supportedVersion}}
sv := SupportedVersionsExtension{HandshakeType: HandshakeTypeClientHello, Versions: []uint16{tls13Version}}
sni := ServerNameExtension(state.Opts.ServerName)
sg := SupportedGroupsExtension{Groups: state.Config.Groups}
sa := SignatureAlgorithmsExtension{Algorithms: state.Config.SignatureSchemes}
@@ -136,6 +136,15 @@ func (state clientStateStart) Next(hr handshakeMessageReader) (HandshakeState, [
}
}
if len(state.Config.PSKModes) != 0 {
kem := &PSKKeyExchangeModesExtension{KEModes: state.Config.PSKModes}
err = ch.Extensions.Add(kem)
if err != nil {
logf(logTypeHandshake, "Error adding PSKKeyExchangeModes extension: %v", err)
return nil, nil, AlertInternalError
}
}
// Run the external extension handler.
if state.Config.ExtensionHandler != nil {
err := state.Config.ExtensionHandler.Send(HandshakeTypeClientHello, &ch.Extensions)
@@ -152,7 +161,7 @@ func (state clientStateStart) Next(hr handshakeMessageReader) (HandshakeState, [
var offeredPSK PreSharedKey
var earlyHash crypto.Hash
var earlySecret []byte
var clientEarlyTrafficKeys keySet
var clientEarlyTrafficKeys KeySet
var clientHello *HandshakeMessage
if key, ok := state.Config.PSKs.Get(state.Opts.ServerName); ok {
offeredPSK = key
@@ -190,12 +199,6 @@ func (state clientStateStart) Next(hr handshakeMessageReader) (HandshakeState, [
logf(logTypeHandshake, "PSK selected, but no PSKModes")
return nil, nil, AlertInternalError
}
kem := &PSKKeyExchangeModesExtension{KEModes: state.Config.PSKModes}
err = ch.Extensions.Add(kem)
if err != nil {
logf(logTypeHandshake, "Error adding PSKKeyExchangeModes extension: %v", err)
return nil, nil, AlertInternalError
}
// Add the shim PSK extension to the ClientHello
logf(logTypeHandshake, "Adding PSK extension with id = %x", key.Identity)
@@ -354,7 +357,7 @@ func (state clientStateWaitSH) Next(hr handshakeMessageReader) (HandshakeState,
logf(logTypeHandshake, "[ClientStateWaitSH] no supported_versions extension")
return nil, nil, AlertMissingExtension
}
if supportedVersions.Versions[0] != supportedVersion {
if supportedVersions.Versions[0] != tls13Version {
logf(logTypeHandshake, "[ClientStateWaitSH] unsupported version [%x]", supportedVersions.Versions[0])
return nil, nil, AlertProtocolVersion
}
@@ -416,6 +419,7 @@ func (state clientStateWaitSH) Next(hr handshakeMessageReader) (HandshakeState,
// mode. In DTLS, we also need to bump the sequence number.
// This is a pre-existing defect in Mint. Issue #175.
logf(logTypeHandshake, "[ClientStateWaitSH] -> [ClientStateStart]")
state.hsCtx.SetVersion(tls12Version) // Everything after this should be 1.2.
return clientStateStart{
Config: state.Config,
Opts: state.Opts,

View File

@@ -6,7 +6,7 @@ import (
)
const (
supportedVersion uint16 = 0x7f16 // draft-22
tls13Version uint16 = 0x0304
tls12Version uint16 = 0x0303
tls10Version uint16 = 0x0301
dtls12WireVersion uint16 = 0xfefd
@@ -118,7 +118,7 @@ const (
ExtensionTypeSupportedGroups ExtensionType = 10
ExtensionTypeSignatureAlgorithms ExtensionType = 13
ExtensionTypeALPN ExtensionType = 16
ExtensionTypeKeyShare ExtensionType = 40
ExtensionTypeKeyShare ExtensionType = 51
ExtensionTypePreSharedKey ExtensionType = 41
ExtensionTypeEarlyData ExtensionType = 42
ExtensionTypeSupportedVersions ExtensionType = 43

View File

@@ -129,6 +129,8 @@ type Config struct {
NonBlocking bool
UseDTLS bool
RecordLayer RecordLayerFactory
// The same config object can be shared among different connections, so it
// needs its own mutex
mutex sync.RWMutex
@@ -270,28 +272,33 @@ type Conn struct {
handshakeComplete bool
readBuffer []byte
in, out *RecordLayer
in, out RecordLayer
hsCtx *HandshakeContext
}
func NewConn(conn net.Conn, config *Config, isClient bool) *Conn {
c := &Conn{conn: conn, config: config, isClient: isClient, hsCtx: &HandshakeContext{}}
if !config.UseDTLS {
c.in = NewRecordLayerTLS(c.conn, directionRead)
c.out = NewRecordLayerTLS(c.conn, directionWrite)
if config.RecordLayer == nil {
c.in = NewRecordLayerTLS(c.conn, DirectionRead)
c.out = NewRecordLayerTLS(c.conn, DirectionWrite)
} else {
c.in = config.RecordLayer.NewLayer(c.conn, DirectionRead)
c.out = config.RecordLayer.NewLayer(c.conn, DirectionWrite)
}
c.hsCtx.hIn = NewHandshakeLayerTLS(c.hsCtx, c.in)
c.hsCtx.hOut = NewHandshakeLayerTLS(c.hsCtx, c.out)
} else {
c.in = NewRecordLayerDTLS(c.conn, directionRead)
c.out = NewRecordLayerDTLS(c.conn, directionWrite)
c.in = NewRecordLayerDTLS(c.conn, DirectionRead)
c.out = NewRecordLayerDTLS(c.conn, DirectionWrite)
c.hsCtx.hIn = NewHandshakeLayerDTLS(c.hsCtx, c.in)
c.hsCtx.hOut = NewHandshakeLayerDTLS(c.hsCtx, c.out)
c.hsCtx.timeoutMS = initialTimeout
c.hsCtx.timers = newTimerSet()
c.hsCtx.waitingNextFlight = true
}
c.in.label = c.label()
c.out.label = c.label()
c.in.SetLabel(c.label())
c.out.SetLabel(c.label())
c.hsCtx.hIn.nonblocking = c.config.NonBlocking
return c
}
@@ -598,7 +605,7 @@ func (c *Conn) takeAction(actionGeneric HandshakeAction) Alert {
logf(logTypeHandshake, "%s Rekey with data still in handshake buffers", label)
return AlertDecodeError
}
err := c.in.Rekey(action.epoch, action.KeySet.cipher, action.KeySet.key, action.KeySet.iv)
err := c.in.Rekey(action.epoch, action.KeySet.Cipher, &action.KeySet)
if err != nil {
logf(logTypeHandshake, "%s Unable to rekey inbound: %v", label, err)
return AlertInternalError
@@ -606,7 +613,7 @@ func (c *Conn) takeAction(actionGeneric HandshakeAction) Alert {
case RekeyOut:
logf(logTypeHandshake, "%s Rekeying out to %s: %+v", label, action.epoch.label(), action.KeySet)
err := c.out.Rekey(action.epoch, action.KeySet.cipher, action.KeySet.key, action.KeySet.iv)
err := c.out.Rekey(action.epoch, action.KeySet.Cipher, &action.KeySet)
if err != nil {
logf(logTypeHandshake, "%s Unable to rekey outbound: %v", label, err)
return AlertInternalError
@@ -906,7 +913,7 @@ func (c *Conn) Writable() bool {
}
// If we're a client in 0-RTT, then we're writable.
if c.isClient && c.out.cipher.epoch == EpochEarlyData {
if c.isClient && c.out.Epoch() == EpochEarlyData {
return true
}

View File

@@ -27,11 +27,11 @@ import (
var prng = rand.Reader
type aeadFactory func(key []byte) (cipher.AEAD, error)
type AeadFactory func(key []byte) (cipher.AEAD, error)
type CipherSuiteParams struct {
Suite CipherSuite
Cipher aeadFactory // Cipher factory
Cipher AeadFactory // Cipher factory
Hash crypto.Hash // Hash function
KeyLen int // Key length in octets
IvLen int // IV length in octets
@@ -546,8 +546,10 @@ const (
// opaque label<9..255>;
// opaque hash_value<0..255>;
// };
var HkdfLabelPrefix = "tls13 "
func hkdfEncodeLabel(labelIn string, hashValue []byte, outLen int) []byte {
label := "tls13 " + labelIn
label := HkdfLabelPrefix + labelIn
labelLen := len(label)
hashLen := len(hashValue)
@@ -604,18 +606,20 @@ func computeFinishedData(params CipherSuiteParams, baseKey []byte, input []byte)
return mac.Sum(nil)
}
type keySet struct {
cipher aeadFactory
key []byte
iv []byte
type KeySet struct {
Cipher AeadFactory
Key []byte
Iv []byte
Pn []byte
}
func makeTrafficKeys(params CipherSuiteParams, secret []byte) keySet {
func makeTrafficKeys(params CipherSuiteParams, secret []byte) KeySet {
logf(logTypeCrypto, "making traffic keys: secret=%x", secret)
return keySet{
cipher: params.Cipher,
key: HkdfExpandLabel(params.Hash, secret, "key", []byte{}, params.KeyLen),
iv: HkdfExpandLabel(params.Hash, secret, "iv", []byte{}, params.IvLen),
return KeySet{
Cipher: params.Cipher,
Key: HkdfExpandLabel(params.Hash, secret, "key", []byte{}, params.KeyLen),
Iv: HkdfExpandLabel(params.Hash, secret, "iv", []byte{}, params.IvLen),
Pn: HkdfExpandLabel(params.Hash, secret, "pn", []byte{}, params.KeyLen),
}
}

View File

@@ -120,7 +120,7 @@ func (h *HandshakeLayer) HandshakeMessageFromBody(body HandshakeMessageBody) (*H
type HandshakeLayer struct {
ctx *HandshakeContext // The handshake we are attached to
nonblocking bool // Should we operate in nonblocking mode
conn *RecordLayer // Used for reading/writing records
conn RecordLayer // Used for reading/writing records
frame *frameReader // The buffered frame reader
datagram bool // Is this DTLS?
msgSeq uint32 // The DTLS message sequence number
@@ -153,7 +153,7 @@ func (d handshakeLayerFrameDetails) frameLen(hdr []byte) (int, error) {
return int(val), nil
}
func NewHandshakeLayerTLS(c *HandshakeContext, r *RecordLayer) *HandshakeLayer {
func NewHandshakeLayerTLS(c *HandshakeContext, r RecordLayer) *HandshakeLayer {
h := HandshakeLayer{}
h.ctx = c
h.conn = r
@@ -163,7 +163,7 @@ func NewHandshakeLayerTLS(c *HandshakeContext, r *RecordLayer) *HandshakeLayer {
return &h
}
func NewHandshakeLayerDTLS(c *HandshakeContext, r *RecordLayer) *HandshakeLayer {
func NewHandshakeLayerDTLS(c *HandshakeContext, r RecordLayer) *HandshakeLayer {
h := HandshakeLayer{}
h.ctx = c
h.conn = r
@@ -174,8 +174,15 @@ func NewHandshakeLayerDTLS(c *HandshakeContext, r *RecordLayer) *HandshakeLayer
}
func (h *HandshakeLayer) readRecord() error {
logf(logTypeVerbose, "Trying to read record")
pt, err := h.conn.readRecordAnyEpoch()
var pt *TLSPlaintext
var err error
if h.datagram {
logf(logTypeVerbose, "Trying to read record")
pt, err = h.conn.(*RecordLayerImpl).ReadRecordAnyEpoch()
} else {
pt, err = h.conn.ReadRecord()
}
if err != nil {
return err
}
@@ -204,7 +211,7 @@ func (h *HandshakeLayer) readRecord() error {
}
assert(h.ctx.hIn.conn != nil)
if pt.epoch != h.ctx.hIn.conn.cipher.epoch {
if pt.epoch != h.ctx.hIn.conn.Epoch() {
// This is out of order but we're dropping it.
// TODO(ekr@rtfm.com): If server, need to retransmit Finished.
if pt.epoch == EpochClear || pt.epoch == EpochHandshakeData {
@@ -394,9 +401,13 @@ func (h *HandshakeLayer) ReadMessage() (*HandshakeMessage, error) {
}
func (h *HandshakeLayer) QueueMessage(hm *HandshakeMessage) error {
hm.cipher = h.conn.cipher
h.queued = append(h.queued, hm)
return nil
if h.datagram {
hm.cipher = h.conn.(*RecordLayerImpl).cipher
h.queued = append(h.queued, hm)
return nil
}
_, err := h.WriteMessages([]*HandshakeMessage{hm})
return err
}
func (h *HandshakeLayer) SendQueuedMessages() (int, error) {
@@ -456,22 +467,30 @@ func (h *HandshakeLayer) writeFragment(hm *HandshakeMessage, start int, room int
buf = body
}
var err error
if h.datagram {
// Remember that we sent this.
h.ctx.sentFragments = append(h.ctx.sentFragments, &SentHandshakeFragment{
hm.seq,
start,
len(body),
h.conn.cipher.combineSeq(true),
h.conn.(*RecordLayerImpl).cipher.combineSeq(true),
false,
})
err = h.conn.(*RecordLayerImpl).writeRecordWithPadding(
&TLSPlaintext{
contentType: RecordTypeHandshake,
fragment: buf,
},
hm.cipher, 0)
} else {
err = h.conn.WriteRecord(
&TLSPlaintext{
contentType: RecordTypeHandshake,
fragment: buf,
})
}
return true, start + bodylen, h.conn.writeRecordWithPadding(
&TLSPlaintext{
contentType: RecordTypeHandshake,
fragment: buf,
},
hm.cipher, 0)
return true, start + bodylen, err
}
func (h *HandshakeLayer) WriteMessage(hm *HandshakeMessage) (int, error) {

View File

@@ -406,7 +406,7 @@ func (cr *CertificateRequestBody) Unmarshal(data []byte) (int, error) {
type NewSessionTicketBody struct {
TicketLifetime uint32
TicketAgeAdd uint32
TicketNonce []byte `tls:"head=1,min=1"`
TicketNonce []byte `tls:"head=1"`
Ticket []byte `tls:"head=2,min=1"`
Extensions ExtensionList `tls:"head=2"`
}

File diff suppressed because one or more lines are too long

Before

Width:  |  Height:  |  Size: 16 KiB

View File

@@ -9,9 +9,9 @@ import (
func VersionNegotiation(offered, supported []uint16) (bool, uint16) {
for _, offeredVersion := range offered {
for _, supportedVersion := range supported {
logf(logTypeHandshake, "[server] version offered by client [%04x] <> [%04x]", offeredVersion, supportedVersion)
if offeredVersion == supportedVersion {
for _, tls13Version := range supported {
logf(logTypeHandshake, "[server] version offered by client [%04x] <> [%04x]", offeredVersion, tls13Version)
if offeredVersion == tls13Version {
// XXX: Should probably be highest supported version, but for now, we
// only support one version, so it doesn't really matter.
return true, offeredVersion

View File

@@ -20,11 +20,11 @@ func (err DecryptError) Error() string {
return string(err)
}
type direction uint8
type Direction uint8
const (
directionWrite = direction(1)
directionRead = direction(2)
DirectionWrite = Direction(1)
DirectionRead = Direction(2)
)
// struct {
@@ -42,6 +42,18 @@ type TLSPlaintext struct {
fragment []byte
}
func NewTLSPlaintext(ct RecordType, epoch Epoch, fragment []byte) *TLSPlaintext {
return &TLSPlaintext{
contentType: ct,
epoch: epoch,
fragment: fragment,
}
}
func (t TLSPlaintext) Fragment() []byte {
return t.fragment
}
type cipherState struct {
epoch Epoch // DTLS epoch
ivLength int // Length of the seq and nonce fields
@@ -50,10 +62,28 @@ type cipherState struct {
cipher cipher.AEAD // AEAD cipher
}
type RecordLayer struct {
type RecordLayerFactory interface {
NewLayer(conn io.ReadWriter, dir Direction) RecordLayer
}
type RecordLayer interface {
Lock()
Unlock()
SetVersion(v uint16)
SetLabel(s string)
Rekey(epoch Epoch, factory AeadFactory, keys *KeySet) error
ResetClear(seq uint64)
DiscardReadKey(epoch Epoch)
PeekRecordType(block bool) (RecordType, error)
ReadRecord() (*TLSPlaintext, error)
WriteRecord(pt *TLSPlaintext) error
Epoch() Epoch
}
type RecordLayerImpl struct {
sync.Mutex
label string
direction direction
direction Direction
version uint16 // The current version number
conn io.ReadWriter // The underlying connection
frame *frameReader // The buffered frame reader
@@ -67,6 +97,10 @@ type RecordLayer struct {
datagram bool
}
func (r *RecordLayerImpl) Impl() *RecordLayerImpl {
return r
}
type recordLayerFrameDetails struct {
datagram bool
}
@@ -90,7 +124,7 @@ func newCipherStateNull() *cipherState {
return &cipherState{EpochClear, 0, 0, nil, nil}
}
func newCipherStateAead(epoch Epoch, factory aeadFactory, key []byte, iv []byte) (*cipherState, error) {
func newCipherStateAead(epoch Epoch, factory AeadFactory, key []byte, iv []byte) (*cipherState, error) {
cipher, err := factory(key)
if err != nil {
return nil, err
@@ -99,8 +133,8 @@ func newCipherStateAead(epoch Epoch, factory aeadFactory, key []byte, iv []byte)
return &cipherState{epoch, len(iv), 0, iv, cipher}, nil
}
func NewRecordLayerTLS(conn io.ReadWriter, dir direction) *RecordLayer {
r := RecordLayer{}
func NewRecordLayerTLS(conn io.ReadWriter, dir Direction) *RecordLayerImpl {
r := RecordLayerImpl{}
r.label = ""
r.direction = dir
r.conn = conn
@@ -110,8 +144,8 @@ func NewRecordLayerTLS(conn io.ReadWriter, dir direction) *RecordLayer {
return &r
}
func NewRecordLayerDTLS(conn io.ReadWriter, dir direction) *RecordLayer {
r := RecordLayer{}
func NewRecordLayerDTLS(conn io.ReadWriter, dir Direction) *RecordLayerImpl {
r := RecordLayerImpl{}
r.label = ""
r.direction = dir
r.conn = conn
@@ -123,29 +157,37 @@ func NewRecordLayerDTLS(conn io.ReadWriter, dir direction) *RecordLayer {
return &r
}
func (r *RecordLayer) SetVersion(v uint16) {
func (r *RecordLayerImpl) SetVersion(v uint16) {
r.version = v
}
func (r *RecordLayer) ResetClear(seq uint64) {
func (r *RecordLayerImpl) ResetClear(seq uint64) {
r.cipher = newCipherStateNull()
r.cipher.seq = seq
}
func (r *RecordLayer) Rekey(epoch Epoch, factory aeadFactory, key []byte, iv []byte) error {
cipher, err := newCipherStateAead(epoch, factory, key, iv)
func (r *RecordLayerImpl) Epoch() Epoch {
return r.cipher.epoch
}
func (r *RecordLayerImpl) SetLabel(s string) {
r.label = s
}
func (r *RecordLayerImpl) Rekey(epoch Epoch, factory AeadFactory, keys *KeySet) error {
cipher, err := newCipherStateAead(epoch, factory, keys.Key, keys.Iv)
if err != nil {
return err
}
r.cipher = cipher
if r.datagram && r.direction == directionRead {
if r.datagram && r.direction == DirectionRead {
r.readCiphers[epoch] = cipher
}
return nil
}
// TODO(ekr@rtfm.com): This is never used, which is a bug.
func (r *RecordLayer) DiscardReadKey(epoch Epoch) {
func (r *RecordLayerImpl) DiscardReadKey(epoch Epoch) {
if !r.datagram {
return
}
@@ -197,34 +239,29 @@ func (c *cipherState) overhead() int {
return c.cipher.Overhead()
}
func (r *RecordLayer) encrypt(cipher *cipherState, seq uint64, pt *TLSPlaintext, padLen int) *TLSPlaintext {
assert(r.direction == directionWrite)
func (r *RecordLayerImpl) encrypt(cipher *cipherState, seq uint64, header []byte, pt *TLSPlaintext, padLen int) []byte {
assert(r.direction == DirectionWrite)
logf(logTypeIO, "%s Encrypt seq=[%x]", r.label, seq)
// Expand the fragment to hold contentType, padding, and overhead
originalLen := len(pt.fragment)
plaintextLen := originalLen + 1 + padLen
ciphertextLen := plaintextLen + cipher.overhead()
// Assemble the revised plaintext
out := &TLSPlaintext{
contentType: RecordTypeApplicationData,
fragment: make([]byte, ciphertextLen),
}
copy(out.fragment, pt.fragment)
out.fragment[originalLen] = byte(pt.contentType)
ciphertext := make([]byte, ciphertextLen)
copy(ciphertext, pt.fragment)
ciphertext[originalLen] = byte(pt.contentType)
for i := 1; i <= padLen; i++ {
out.fragment[originalLen+i] = 0
ciphertext[originalLen+i] = 0
}
// Encrypt the fragment
payload := out.fragment[:plaintextLen]
cipher.cipher.Seal(payload[:0], cipher.computeNonce(seq), payload, nil)
return out
payload := ciphertext[:plaintextLen]
cipher.cipher.Seal(payload[:0], cipher.computeNonce(seq), payload, header)
return ciphertext
}
func (r *RecordLayer) decrypt(pt *TLSPlaintext, seq uint64) (*TLSPlaintext, int, error) {
assert(r.direction == directionRead)
func (r *RecordLayerImpl) decrypt(seq uint64, header []byte, pt *TLSPlaintext) (*TLSPlaintext, int, error) {
assert(r.direction == DirectionRead)
logf(logTypeIO, "%s Decrypt seq=[%x]", r.label, seq)
if len(pt.fragment) < r.cipher.overhead() {
msg := fmt.Sprintf("tls.record.decrypt: Record too short [%d] < [%d]", len(pt.fragment), r.cipher.overhead())
@@ -238,7 +275,7 @@ func (r *RecordLayer) decrypt(pt *TLSPlaintext, seq uint64) (*TLSPlaintext, int,
}
// Decrypt
_, err := r.cipher.cipher.Open(out.fragment[:0], r.cipher.computeNonce(seq), pt.fragment, nil)
_, err := r.cipher.cipher.Open(out.fragment[:0], r.cipher.computeNonce(seq), pt.fragment, header)
if err != nil {
logf(logTypeIO, "%s AEAD decryption failure [%x]", r.label, pt)
return nil, 0, DecryptError("tls.record.decrypt: AEAD decrypt failed")
@@ -259,7 +296,7 @@ func (r *RecordLayer) decrypt(pt *TLSPlaintext, seq uint64) (*TLSPlaintext, int,
return out, padLen, nil
}
func (r *RecordLayer) PeekRecordType(block bool) (RecordType, error) {
func (r *RecordLayerImpl) PeekRecordType(block bool) (RecordType, error) {
var pt *TLSPlaintext
var err error
@@ -275,7 +312,7 @@ func (r *RecordLayer) PeekRecordType(block bool) (RecordType, error) {
return pt.contentType, nil
}
func (r *RecordLayer) ReadRecord() (*TLSPlaintext, error) {
func (r *RecordLayerImpl) ReadRecord() (*TLSPlaintext, error) {
pt, err := r.nextRecord(false)
// Consume the cached record if there was one
@@ -285,7 +322,7 @@ func (r *RecordLayer) ReadRecord() (*TLSPlaintext, error) {
return pt, err
}
func (r *RecordLayer) readRecordAnyEpoch() (*TLSPlaintext, error) {
func (r *RecordLayerImpl) ReadRecordAnyEpoch() (*TLSPlaintext, error) {
pt, err := r.nextRecord(true)
// Consume the cached record if there was one
@@ -295,7 +332,7 @@ func (r *RecordLayer) readRecordAnyEpoch() (*TLSPlaintext, error) {
return pt, err
}
func (r *RecordLayer) nextRecord(allowOldEpoch bool) (*TLSPlaintext, error) {
func (r *RecordLayerImpl) nextRecord(allowOldEpoch bool) (*TLSPlaintext, error) {
cipher := r.cipher
if r.cachedRecord != nil {
logf(logTypeIO, "%s Returning cached record", r.label)
@@ -391,7 +428,7 @@ func (r *RecordLayer) nextRecord(allowOldEpoch bool) (*TLSPlaintext, error) {
if cipher.cipher != nil {
logf(logTypeIO, "%s RecordLayer.ReadRecord epoch=[%s] seq=[%x] [%d] ciphertext=[%x]", r.label, cipher.epoch.label(), seq, pt.contentType, pt.fragment)
pt, _, err = r.decrypt(pt, seq)
pt, _, err = r.decrypt(seq, header, pt)
if err != nil {
logf(logTypeIO, "%s Decryption failed", r.label)
return nil, err
@@ -411,46 +448,58 @@ func (r *RecordLayer) nextRecord(allowOldEpoch bool) (*TLSPlaintext, error) {
return pt, nil
}
func (r *RecordLayer) WriteRecord(pt *TLSPlaintext) error {
func (r *RecordLayerImpl) WriteRecord(pt *TLSPlaintext) error {
return r.writeRecordWithPadding(pt, r.cipher, 0)
}
func (r *RecordLayer) WriteRecordWithPadding(pt *TLSPlaintext, padLen int) error {
func (r *RecordLayerImpl) WriteRecordWithPadding(pt *TLSPlaintext, padLen int) error {
return r.writeRecordWithPadding(pt, r.cipher, padLen)
}
func (r *RecordLayer) writeRecordWithPadding(pt *TLSPlaintext, cipher *cipherState, padLen int) error {
func (r *RecordLayerImpl) writeRecordWithPadding(pt *TLSPlaintext, cipher *cipherState, padLen int) error {
seq := cipher.combineSeq(r.datagram)
if cipher.cipher != nil {
logf(logTypeIO, "%s RecordLayer.WriteRecord epoch=[%s] seq=[%x] [%d] plaintext=[%x]", r.label, cipher.epoch.label(), cipher.seq, pt.contentType, pt.fragment)
pt = r.encrypt(cipher, seq, pt, padLen)
} else if padLen > 0 {
return fmt.Errorf("tls.record: Padding can only be done on encrypted records")
}
if len(pt.fragment) > maxFragmentLen {
return fmt.Errorf("tls.record: Record size too big")
}
length := len(pt.fragment)
var contentType RecordType
if cipher.cipher != nil {
length += 1 + padLen + cipher.cipher.Overhead()
contentType = RecordTypeApplicationData
} else {
contentType = pt.contentType
}
var header []byte
if !r.datagram {
header = []byte{byte(pt.contentType),
header = []byte{byte(contentType),
byte(r.version >> 8), byte(r.version & 0xff),
byte(length >> 8), byte(length)}
} else {
header = make([]byte, 13)
version := dtlsConvertVersion(r.version)
copy(header, []byte{byte(pt.contentType),
copy(header, []byte{byte(contentType),
byte(version >> 8), byte(version & 0xff),
})
encodeUint(seq, 8, header[3:])
encodeUint(uint64(length), 2, header[11:])
}
record := append(header, pt.fragment...)
logf(logTypeIO, "%s RecordLayer.WriteRecord epoch=[%s] seq=[%x] [%d] ciphertext=[%x]", r.label, cipher.epoch.label(), cipher.seq, pt.contentType, pt.fragment)
var ciphertext []byte
if cipher.cipher != nil {
logf(logTypeIO, "%s RecordLayer.WriteRecord epoch=[%s] seq=[%x] [%d] plaintext=[%x]", r.label, cipher.epoch.label(), cipher.seq, pt.contentType, pt.fragment)
ciphertext = r.encrypt(cipher, seq, header, pt, padLen)
} else {
if padLen > 0 {
return fmt.Errorf("tls.record: Padding can only be done on encrypted records")
}
ciphertext = pt.fragment
}
if len(ciphertext) > maxFragmentLen {
return fmt.Errorf("tls.record: Record size too big")
}
record := append(header, ciphertext...)
logf(logTypeIO, "%s RecordLayer.WriteRecord epoch=[%s] seq=[%x] [%d] ciphertext=[%x]", r.label, cipher.epoch.label(), cipher.seq, contentType, ciphertext)
cipher.incrementSequenceNumber()
_, err := r.conn.Write(record)

View File

@@ -163,7 +163,7 @@ func (state serverStateStart) Next(hr handshakeMessageReader) (HandshakeState, [
logf(logTypeHandshake, "[ServerStateStart] Client did not send supported_versions")
return nil, nil, AlertProtocolVersion
}
versionOK, _ := VersionNegotiation(supportedVersions.Versions, []uint16{supportedVersion})
versionOK, _ := VersionNegotiation(supportedVersions.Versions, []uint16{tls13Version})
if !versionOK {
logf(logTypeHandshake, "[ServerStateStart] Client does not support the same version")
return nil, nil, AlertProtocolVersion
@@ -416,7 +416,7 @@ func (state *serverStateStart) generateHRR(cs CipherSuite, legacySessionId []byt
sv := &SupportedVersionsExtension{
HandshakeType: HandshakeTypeServerHello,
Versions: []uint16{supportedVersion},
Versions: []uint16{tls13Version},
}
if err := hrr.Extensions.Add(sv); err != nil {
@@ -483,7 +483,7 @@ func (state serverStateNegotiated) Next(_ handshakeMessageReader) (HandshakeStat
err := sh.Extensions.Add(&SupportedVersionsExtension{
HandshakeType: HandshakeTypeServerHello,
Versions: []uint16{supportedVersion},
Versions: []uint16{tls13Version},
})
if err != nil {
logf(logTypeHandshake, "[ServerStateNegotiated] Error adding supported_versions extension [%v]", err)
@@ -785,7 +785,7 @@ func (state serverStateWaitEOED) State() State {
func (state serverStateWaitEOED) Next(hr handshakeMessageReader) (HandshakeState, []HandshakeAction, Alert) {
for {
logf(logTypeHandshake, "Server reading early data...")
assert(state.hsCtx.hIn.conn.cipher.epoch == EpochEarlyData)
assert(state.hsCtx.hIn.conn.Epoch() == EpochEarlyData)
t, err := state.hsCtx.hIn.conn.PeekRecordType(!state.hsCtx.hIn.nonblocking)
if err == AlertWouldBlock {
return nil, nil, AlertWouldBlock

View File

@@ -19,12 +19,12 @@ type SendEarlyData struct{}
type RekeyIn struct {
epoch Epoch
KeySet keySet
KeySet KeySet
}
type RekeyOut struct {
epoch Epoch
KeySet keySet
KeySet KeySet
}
type ResetOut struct {
@@ -111,7 +111,7 @@ func (state stateConnected) State() State {
}
func (state *stateConnected) KeyUpdate(request KeyUpdateRequest) ([]HandshakeAction, Alert) {
var trafficKeys keySet
var trafficKeys KeySet
if state.isClient {
state.clientTrafficSecret = HkdfExpandLabel(state.cryptoParams.Hash, state.clientTrafficSecret,
labelClientApplicationTrafficSecret, []byte{}, state.cryptoParams.Hash.Size())
@@ -196,7 +196,7 @@ func (state stateConnected) ProcessMessage(hm *HandshakeMessage) (HandshakeState
switch body := bodyGeneric.(type) {
case *KeyUpdateBody:
var trafficKeys keySet
var trafficKeys KeySet
if !state.isClient {
state.clientTrafficSecret = HkdfExpandLabel(state.cryptoParams.Hash, state.clientTrafficSecret,
labelClientApplicationTrafficSecret, []byte{}, state.cryptoParams.Hash.Size())

View File

@@ -1,84 +0,0 @@
TLS Syntax
==========
TLS defines [its own syntax](https://tlswg.github.io/tls13-spec/#rfc.section.3)
for describing structures used in that protocol. To facilitate experimentation
with TLS in Go, this module maps that syntax to the Go structure syntax, taking
advantage of Go's type annotations to encode non-type information carried in the
TLS presentation format.
For example, in the TLS specification, a ClientHello message has the following
structure:
~~~~~
uint16 ProtocolVersion;
opaque Random[32];
uint8 CipherSuite[2];
enum { ... (65535)} ExtensionType;
struct {
ExtensionType extension_type;
opaque extension_data<0..2^16-1>;
} Extension;
struct {
ProtocolVersion legacy_version = 0x0303; /* TLS v1.2 */
Random random;
opaque legacy_session_id<0..32>;
CipherSuite cipher_suites<2..2^16-2>;
opaque legacy_compression_methods<1..2^8-1>;
Extension extensions<0..2^16-1>;
} ClientHello;
~~~~~
This maps to the following Go type definitions:
~~~~~
type protocolVersion uint16
type random [32]byte
type cipherSuite uint16 // or [2]byte
type extensionType uint16
type extension struct {
ExtensionType extensionType
ExtensionData []byte `tls:"head=2"`
}
type clientHello struct {
LegacyVersion protocolVersion
Random random
LegacySessionID []byte `tls:"head=1,max=32"`
CipherSuites []cipherSuite `tls:"head=2,min=2"`
LegacyCompressionMethods []byte `tls:"head=1,min=1"`
Extensions []extension `tls:"head=2"`
}
~~~~~
Then you can just declare, marshal, and unmarshal structs just like you would
with, say JSON.
The available annotations right now are all related to vectors:
* `head`: The number of bytes of length to use as a "header"
* `min`: The minimum length of the vector, in bytes
* `max`: The maximum length of the vector, in bytes
## Not supported
* The `select()` syntax for creating alternate version of the same struct (see,
e.g., the KeyShare extension)
* The backreference syntax for array lengths or select parameters, as in `opaque
fragment[TLSPlaintext.length]`. Note, however, that in cases where the length
immediately preceds the array, these can be reframed as vectors with
appropriate sizes.
QUIC Extensions Syntax
======================
syntax also supports some minor extensions to allow implementing QUIC.
* The `varint` annotation describes a QUIC-style varint
* `head=none` means no header, i.e., the bytes are encoded directly on the wire.
On reading, the decoder will consume all available data.
* `head=varint` means to encode the header as a varint

View File

@@ -1,22 +0,0 @@
# Compiled Object files, Static and Dynamic libs (Shared Objects)
*.o
*.a
*.so
# Folders
_obj
_test
# Architecture specific extensions/prefixes
*.[568vq]
[568vq].out
*.cgo1.go
*.cgo2.c
_cgo_defun.c
_cgo_gotypes.go
_cgo_export.*
_testmain.go
*.exe

View File

@@ -1,10 +0,0 @@
language: go
go:
- 1.7
- 1.x
- tip
before_install:
- go get github.com/mattn/goveralls
- go get golang.org/x/tools/cmd/cover
script:
- $HOME/gopath/bin/goveralls -service=travis-ci

View File

@@ -1,30 +0,0 @@
# Exponential Backoff [![GoDoc][godoc image]][godoc] [![Build Status][travis image]][travis] [![Coverage Status][coveralls image]][coveralls]
This is a Go port of the exponential backoff algorithm from [Google's HTTP Client Library for Java][google-http-java-client].
[Exponential backoff][exponential backoff wiki]
is an algorithm that uses feedback to multiplicatively decrease the rate of some process,
in order to gradually find an acceptable rate.
The retries exponentially increase and stop increasing when a certain threshold is met.
## Usage
See https://godoc.org/github.com/cenkalti/backoff#pkg-examples
## Contributing
* I would like to keep this library as small as possible.
* Please don't send a PR without opening an issue and discussing it first.
* If proposed change is not a common use case, I will probably not accept it.
[godoc]: https://godoc.org/github.com/cenkalti/backoff
[godoc image]: https://godoc.org/github.com/cenkalti/backoff?status.png
[travis]: https://travis-ci.org/cenkalti/backoff
[travis image]: https://travis-ci.org/cenkalti/backoff.png?branch=master
[coveralls]: https://coveralls.io/github/cenkalti/backoff?branch=master
[coveralls image]: https://coveralls.io/repos/github/cenkalti/backoff/badge.svg?branch=master
[google-http-java-client]: https://github.com/google/google-http-java-client/blob/da1aa993e90285ec18579f1553339b00e19b3ab5/google-http-client/src/main/java/com/google/api/client/util/ExponentialBackOff.java
[exponential backoff wiki]: http://en.wikipedia.org/wiki/Exponential_backoff
[advanced example]: https://godoc.org/github.com/cenkalti/backoff#example_

View File

@@ -2,7 +2,7 @@ ISC License
Copyright (c) 2012-2016 Dave Collins <dave@davec.name>
Permission to use, copy, modify, and distribute this software for any
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.

View File

@@ -16,7 +16,9 @@
// when the code is not running on Google App Engine, compiled by GopherJS, and
// "-tags safe" is not added to the go build command line. The "disableunsafe"
// tag is deprecated and thus should not be used.
// +build !js,!appengine,!safe,!disableunsafe
// Go versions prior to 1.4 are disabled because they use a different layout
// for interfaces which make the implementation of unsafeReflectValue more complex.
// +build !js,!appengine,!safe,!disableunsafe,go1.4
package spew
@@ -34,80 +36,49 @@ const (
ptrSize = unsafe.Sizeof((*byte)(nil))
)
var (
// offsetPtr, offsetScalar, and offsetFlag are the offsets for the
// internal reflect.Value fields. These values are valid before golang
// commit ecccf07e7f9d which changed the format. The are also valid
// after commit 82f48826c6c7 which changed the format again to mirror
// the original format. Code in the init function updates these offsets
// as necessary.
offsetPtr = uintptr(ptrSize)
offsetScalar = uintptr(0)
offsetFlag = uintptr(ptrSize * 2)
type flag uintptr
// flagKindWidth and flagKindShift indicate various bits that the
// reflect package uses internally to track kind information.
//
// flagRO indicates whether or not the value field of a reflect.Value is
// read-only.
//
// flagIndir indicates whether the value field of a reflect.Value is
// the actual data or a pointer to the data.
//
// These values are valid before golang commit 90a7c3c86944 which
// changed their positions. Code in the init function updates these
// flags as necessary.
flagKindWidth = uintptr(5)
flagKindShift = uintptr(flagKindWidth - 1)
flagRO = uintptr(1 << 0)
flagIndir = uintptr(1 << 1)
var (
// flagRO indicates whether the value field of a reflect.Value
// is read-only.
flagRO flag
// flagAddr indicates whether the address of the reflect.Value's
// value may be taken.
flagAddr flag
)
func init() {
// Older versions of reflect.Value stored small integers directly in the
// ptr field (which is named val in the older versions). Versions
// between commits ecccf07e7f9d and 82f48826c6c7 added a new field named
// scalar for this purpose which unfortunately came before the flag
// field, so the offset of the flag field is different for those
// versions.
//
// This code constructs a new reflect.Value from a known small integer
// and checks if the size of the reflect.Value struct indicates it has
// the scalar field. When it does, the offsets are updated accordingly.
vv := reflect.ValueOf(0xf00)
if unsafe.Sizeof(vv) == (ptrSize * 4) {
offsetScalar = ptrSize * 2
offsetFlag = ptrSize * 3
}
// flagKindMask holds the bits that make up the kind
// part of the flags field. In all the supported versions,
// it is in the lower 5 bits.
const flagKindMask = flag(0x1f)
// Commit 90a7c3c86944 changed the flag positions such that the low
// order bits are the kind. This code extracts the kind from the flags
// field and ensures it's the correct type. When it's not, the flag
// order has been changed to the newer format, so the flags are updated
// accordingly.
upf := unsafe.Pointer(uintptr(unsafe.Pointer(&vv)) + offsetFlag)
upfv := *(*uintptr)(upf)
flagKindMask := uintptr((1<<flagKindWidth - 1) << flagKindShift)
if (upfv&flagKindMask)>>flagKindShift != uintptr(reflect.Int) {
flagKindShift = 0
flagRO = 1 << 5
flagIndir = 1 << 6
// Different versions of Go have used different
// bit layouts for the flags type. This table
// records the known combinations.
var okFlags = []struct {
ro, addr flag
}{{
// From Go 1.4 to 1.5
ro: 1 << 5,
addr: 1 << 7,
}, {
// Up to Go tip.
ro: 1<<5 | 1<<6,
addr: 1 << 8,
}}
// Commit adf9b30e5594 modified the flags to separate the
// flagRO flag into two bits which specifies whether or not the
// field is embedded. This causes flagIndir to move over a bit
// and means that flagRO is the combination of either of the
// original flagRO bit and the new bit.
//
// This code detects the change by extracting what used to be
// the indirect bit to ensure it's set. When it's not, the flag
// order has been changed to the newer format, so the flags are
// updated accordingly.
if upfv&flagIndir == 0 {
flagRO = 3 << 5
flagIndir = 1 << 7
}
var flagValOffset = func() uintptr {
field, ok := reflect.TypeOf(reflect.Value{}).FieldByName("flag")
if !ok {
panic("reflect.Value has no flag field")
}
return field.Offset
}()
// flagField returns a pointer to the flag field of a reflect.Value.
func flagField(v *reflect.Value) *flag {
return (*flag)(unsafe.Pointer(uintptr(unsafe.Pointer(v)) + flagValOffset))
}
// unsafeReflectValue converts the passed reflect.Value into a one that bypasses
@@ -119,34 +90,56 @@ func init() {
// This allows us to check for implementations of the Stringer and error
// interfaces to be used for pretty printing ordinarily unaddressable and
// inaccessible values such as unexported struct fields.
func unsafeReflectValue(v reflect.Value) (rv reflect.Value) {
indirects := 1
vt := v.Type()
upv := unsafe.Pointer(uintptr(unsafe.Pointer(&v)) + offsetPtr)
rvf := *(*uintptr)(unsafe.Pointer(uintptr(unsafe.Pointer(&v)) + offsetFlag))
if rvf&flagIndir != 0 {
vt = reflect.PtrTo(v.Type())
indirects++
} else if offsetScalar != 0 {
// The value is in the scalar field when it's not one of the
// reference types.
switch vt.Kind() {
case reflect.Uintptr:
case reflect.Chan:
case reflect.Func:
case reflect.Map:
case reflect.Ptr:
case reflect.UnsafePointer:
default:
upv = unsafe.Pointer(uintptr(unsafe.Pointer(&v)) +
offsetScalar)
func unsafeReflectValue(v reflect.Value) reflect.Value {
if !v.IsValid() || (v.CanInterface() && v.CanAddr()) {
return v
}
flagFieldPtr := flagField(&v)
*flagFieldPtr &^= flagRO
*flagFieldPtr |= flagAddr
return v
}
// Sanity checks against future reflect package changes
// to the type or semantics of the Value.flag field.
func init() {
field, ok := reflect.TypeOf(reflect.Value{}).FieldByName("flag")
if !ok {
panic("reflect.Value has no flag field")
}
if field.Type.Kind() != reflect.TypeOf(flag(0)).Kind() {
panic("reflect.Value flag field has changed kind")
}
type t0 int
var t struct {
A t0
// t0 will have flagEmbedRO set.
t0
// a will have flagStickyRO set
a t0
}
vA := reflect.ValueOf(t).FieldByName("A")
va := reflect.ValueOf(t).FieldByName("a")
vt0 := reflect.ValueOf(t).FieldByName("t0")
// Infer flagRO from the difference between the flags
// for the (otherwise identical) fields in t.
flagPublic := *flagField(&vA)
flagWithRO := *flagField(&va) | *flagField(&vt0)
flagRO = flagPublic ^ flagWithRO
// Infer flagAddr from the difference between a value
// taken from a pointer and not.
vPtrA := reflect.ValueOf(&t).Elem().FieldByName("A")
flagNoPtr := *flagField(&vA)
flagPtr := *flagField(&vPtrA)
flagAddr = flagNoPtr ^ flagPtr
// Check that the inferred flags tally with one of the known versions.
for _, f := range okFlags {
if flagRO == f.ro && flagAddr == f.addr {
return
}
}
pv := reflect.NewAt(vt, upv)
rv = pv
for i := 0; i < indirects; i++ {
rv = rv.Elem()
}
return rv
panic("reflect.Value read-only flag has changed semantics")
}

View File

@@ -16,7 +16,7 @@
// when the code is running on Google App Engine, compiled by GopherJS, or
// "-tags safe" is added to the go build command line. The "disableunsafe"
// tag is deprecated and thus should not be used.
// +build js appengine safe disableunsafe
// +build js appengine safe disableunsafe !go1.4
package spew

View File

@@ -35,16 +35,16 @@ var (
// cCharRE is a regular expression that matches a cgo char.
// It is used to detect character arrays to hexdump them.
cCharRE = regexp.MustCompile("^.*\\._Ctype_char$")
cCharRE = regexp.MustCompile(`^.*\._Ctype_char$`)
// cUnsignedCharRE is a regular expression that matches a cgo unsigned
// char. It is used to detect unsigned character arrays to hexdump
// them.
cUnsignedCharRE = regexp.MustCompile("^.*\\._Ctype_unsignedchar$")
cUnsignedCharRE = regexp.MustCompile(`^.*\._Ctype_unsignedchar$`)
// cUint8tCharRE is a regular expression that matches a cgo uint8_t.
// It is used to detect uint8_t arrays to hexdump them.
cUint8tCharRE = regexp.MustCompile("^.*\\._Ctype_uint8_t$")
cUint8tCharRE = regexp.MustCompile(`^.*\._Ctype_uint8_t$`)
)
// dumpState contains information about the state of a dump operation.
@@ -143,10 +143,10 @@ func (d *dumpState) dumpPtr(v reflect.Value) {
// Display dereferenced value.
d.w.Write(openParenBytes)
switch {
case nilFound == true:
case nilFound:
d.w.Write(nilAngleBytes)
case cycleFound == true:
case cycleFound:
d.w.Write(circularBytes)
default:

View File

@@ -182,10 +182,10 @@ func (f *formatState) formatPtr(v reflect.Value) {
// Display dereferenced value.
switch {
case nilFound == true:
case nilFound:
f.fs.Write(nilAngleBytes)
case cycleFound == true:
case cycleFound:
f.fs.Write(circularShortBytes)
default:

View File

@@ -1,4 +0,0 @@
.DS_Store
bin

View File

@@ -1,13 +0,0 @@
language: go
script:
- go vet ./...
- go test -v ./...
go:
- 1.3
- 1.4
- 1.5
- 1.6
- 1.7
- tip

View File

@@ -1,97 +0,0 @@
## Migration Guide from v2 -> v3
Version 3 adds several new, frequently requested features. To do so, it introduces a few breaking changes. We've worked to keep these as minimal as possible. This guide explains the breaking changes and how you can quickly update your code.
### `Token.Claims` is now an interface type
The most requested feature from the 2.0 verison of this library was the ability to provide a custom type to the JSON parser for claims. This was implemented by introducing a new interface, `Claims`, to replace `map[string]interface{}`. We also included two concrete implementations of `Claims`: `MapClaims` and `StandardClaims`.
`MapClaims` is an alias for `map[string]interface{}` with built in validation behavior. It is the default claims type when using `Parse`. The usage is unchanged except you must type cast the claims property.
The old example for parsing a token looked like this..
```go
if token, err := jwt.Parse(tokenString, keyLookupFunc); err == nil {
fmt.Printf("Token for user %v expires %v", token.Claims["user"], token.Claims["exp"])
}
```
is now directly mapped to...
```go
if token, err := jwt.Parse(tokenString, keyLookupFunc); err == nil {
claims := token.Claims.(jwt.MapClaims)
fmt.Printf("Token for user %v expires %v", claims["user"], claims["exp"])
}
```
`StandardClaims` is designed to be embedded in your custom type. You can supply a custom claims type with the new `ParseWithClaims` function. Here's an example of using a custom claims type.
```go
type MyCustomClaims struct {
User string
*StandardClaims
}
if token, err := jwt.ParseWithClaims(tokenString, &MyCustomClaims{}, keyLookupFunc); err == nil {
claims := token.Claims.(*MyCustomClaims)
fmt.Printf("Token for user %v expires %v", claims.User, claims.StandardClaims.ExpiresAt)
}
```
### `ParseFromRequest` has been moved
To keep this library focused on the tokens without becoming overburdened with complex request processing logic, `ParseFromRequest` and its new companion `ParseFromRequestWithClaims` have been moved to a subpackage, `request`. The method signatues have also been augmented to receive a new argument: `Extractor`.
`Extractors` do the work of picking the token string out of a request. The interface is simple and composable.
This simple parsing example:
```go
if token, err := jwt.ParseFromRequest(tokenString, req, keyLookupFunc); err == nil {
fmt.Printf("Token for user %v expires %v", token.Claims["user"], token.Claims["exp"])
}
```
is directly mapped to:
```go
if token, err := request.ParseFromRequest(req, request.OAuth2Extractor, keyLookupFunc); err == nil {
claims := token.Claims.(jwt.MapClaims)
fmt.Printf("Token for user %v expires %v", claims["user"], claims["exp"])
}
```
There are several concrete `Extractor` types provided for your convenience:
* `HeaderExtractor` will search a list of headers until one contains content.
* `ArgumentExtractor` will search a list of keys in request query and form arguments until one contains content.
* `MultiExtractor` will try a list of `Extractors` in order until one returns content.
* `AuthorizationHeaderExtractor` will look in the `Authorization` header for a `Bearer` token.
* `OAuth2Extractor` searches the places an OAuth2 token would be specified (per the spec): `Authorization` header and `access_token` argument
* `PostExtractionFilter` wraps an `Extractor`, allowing you to process the content before it's parsed. A simple example is stripping the `Bearer ` text from a header
### RSA signing methods no longer accept `[]byte` keys
Due to a [critical vulnerability](https://auth0.com/blog/2015/03/31/critical-vulnerabilities-in-json-web-token-libraries/), we've decided the convenience of accepting `[]byte` instead of `rsa.PublicKey` or `rsa.PrivateKey` isn't worth the risk of misuse.
To replace this behavior, we've added two helper methods: `ParseRSAPrivateKeyFromPEM(key []byte) (*rsa.PrivateKey, error)` and `ParseRSAPublicKeyFromPEM(key []byte) (*rsa.PublicKey, error)`. These are just simple helpers for unpacking PEM encoded PKCS1 and PKCS8 keys. If your keys are encoded any other way, all you need to do is convert them to the `crypto/rsa` package's types.
```go
func keyLookupFunc(*Token) (interface{}, error) {
// Don't forget to validate the alg is what you expect:
if _, ok := token.Method.(*jwt.SigningMethodRSA); !ok {
return nil, fmt.Errorf("Unexpected signing method: %v", token.Header["alg"])
}
// Look up key
key, err := lookupPublicKey(token.Header["kid"])
if err != nil {
return nil, err
}
// Unpack key from PEM encoded PKCS8
return jwt.ParseRSAPublicKeyFromPEM(key)
}
```

View File

@@ -1,100 +0,0 @@
# jwt-go
[![Build Status](https://travis-ci.org/dgrijalva/jwt-go.svg?branch=master)](https://travis-ci.org/dgrijalva/jwt-go)
[![GoDoc](https://godoc.org/github.com/dgrijalva/jwt-go?status.svg)](https://godoc.org/github.com/dgrijalva/jwt-go)
A [go](http://www.golang.org) (or 'golang' for search engine friendliness) implementation of [JSON Web Tokens](http://self-issued.info/docs/draft-ietf-oauth-json-web-token.html)
**NEW VERSION COMING:** There have been a lot of improvements suggested since the version 3.0.0 released in 2016. I'm working now on cutting two different releases: 3.2.0 will contain any non-breaking changes or enhancements. 4.0.0 will follow shortly which will include breaking changes. See the 4.0.0 milestone to get an idea of what's coming. If you have other ideas, or would like to participate in 4.0.0, now's the time. If you depend on this library and don't want to be interrupted, I recommend you use your dependency mangement tool to pin to version 3.
**SECURITY NOTICE:** Some older versions of Go have a security issue in the cryotp/elliptic. Recommendation is to upgrade to at least 1.8.3. See issue #216 for more detail.
**SECURITY NOTICE:** It's important that you [validate the `alg` presented is what you expect](https://auth0.com/blog/2015/03/31/critical-vulnerabilities-in-json-web-token-libraries/). This library attempts to make it easy to do the right thing by requiring key types match the expected alg, but you should take the extra step to verify it in your usage. See the examples provided.
## What the heck is a JWT?
JWT.io has [a great introduction](https://jwt.io/introduction) to JSON Web Tokens.
In short, it's a signed JSON object that does something useful (for example, authentication). It's commonly used for `Bearer` tokens in Oauth 2. A token is made of three parts, separated by `.`'s. The first two parts are JSON objects, that have been [base64url](http://tools.ietf.org/html/rfc4648) encoded. The last part is the signature, encoded the same way.
The first part is called the header. It contains the necessary information for verifying the last part, the signature. For example, which encryption method was used for signing and what key was used.
The part in the middle is the interesting bit. It's called the Claims and contains the actual stuff you care about. Refer to [the RFC](http://self-issued.info/docs/draft-jones-json-web-token.html) for information about reserved keys and the proper way to add your own.
## What's in the box?
This library supports the parsing and verification as well as the generation and signing of JWTs. Current supported signing algorithms are HMAC SHA, RSA, RSA-PSS, and ECDSA, though hooks are present for adding your own.
## Examples
See [the project documentation](https://godoc.org/github.com/dgrijalva/jwt-go) for examples of usage:
* [Simple example of parsing and validating a token](https://godoc.org/github.com/dgrijalva/jwt-go#example-Parse--Hmac)
* [Simple example of building and signing a token](https://godoc.org/github.com/dgrijalva/jwt-go#example-New--Hmac)
* [Directory of Examples](https://godoc.org/github.com/dgrijalva/jwt-go#pkg-examples)
## Extensions
This library publishes all the necessary components for adding your own signing methods. Simply implement the `SigningMethod` interface and register a factory method using `RegisterSigningMethod`.
Here's an example of an extension that integrates with the Google App Engine signing tools: https://github.com/someone1/gcp-jwt-go
## Compliance
This library was last reviewed to comply with [RTF 7519](http://www.rfc-editor.org/info/rfc7519) dated May 2015 with a few notable differences:
* In order to protect against accidental use of [Unsecured JWTs](http://self-issued.info/docs/draft-ietf-oauth-json-web-token.html#UnsecuredJWT), tokens using `alg=none` will only be accepted if the constant `jwt.UnsafeAllowNoneSignatureType` is provided as the key.
## Project Status & Versioning
This library is considered production ready. Feedback and feature requests are appreciated. The API should be considered stable. There should be very few backwards-incompatible changes outside of major version updates (and only with good reason).
This project uses [Semantic Versioning 2.0.0](http://semver.org). Accepted pull requests will land on `master`. Periodically, versions will be tagged from `master`. You can find all the releases on [the project releases page](https://github.com/dgrijalva/jwt-go/releases).
While we try to make it obvious when we make breaking changes, there isn't a great mechanism for pushing announcements out to users. You may want to use this alternative package include: `gopkg.in/dgrijalva/jwt-go.v3`. It will do the right thing WRT semantic versioning.
**BREAKING CHANGES:***
* Version 3.0.0 includes _a lot_ of changes from the 2.x line, including a few that break the API. We've tried to break as few things as possible, so there should just be a few type signature changes. A full list of breaking changes is available in `VERSION_HISTORY.md`. See `MIGRATION_GUIDE.md` for more information on updating your code.
## Usage Tips
### Signing vs Encryption
A token is simply a JSON object that is signed by its author. this tells you exactly two things about the data:
* The author of the token was in the possession of the signing secret
* The data has not been modified since it was signed
It's important to know that JWT does not provide encryption, which means anyone who has access to the token can read its contents. If you need to protect (encrypt) the data, there is a companion spec, `JWE`, that provides this functionality. JWE is currently outside the scope of this library.
### Choosing a Signing Method
There are several signing methods available, and you should probably take the time to learn about the various options before choosing one. The principal design decision is most likely going to be symmetric vs asymmetric.
Symmetric signing methods, such as HSA, use only a single secret. This is probably the simplest signing method to use since any `[]byte` can be used as a valid secret. They are also slightly computationally faster to use, though this rarely is enough to matter. Symmetric signing methods work the best when both producers and consumers of tokens are trusted, or even the same system. Since the same secret is used to both sign and validate tokens, you can't easily distribute the key for validation.
Asymmetric signing methods, such as RSA, use different keys for signing and verifying tokens. This makes it possible to produce tokens with a private key, and allow any consumer to access the public key for verification.
### Signing Methods and Key Types
Each signing method expects a different object type for its signing keys. See the package documentation for details. Here are the most common ones:
* The [HMAC signing method](https://godoc.org/github.com/dgrijalva/jwt-go#SigningMethodHMAC) (`HS256`,`HS384`,`HS512`) expect `[]byte` values for signing and validation
* The [RSA signing method](https://godoc.org/github.com/dgrijalva/jwt-go#SigningMethodRSA) (`RS256`,`RS384`,`RS512`) expect `*rsa.PrivateKey` for signing and `*rsa.PublicKey` for validation
* The [ECDSA signing method](https://godoc.org/github.com/dgrijalva/jwt-go#SigningMethodECDSA) (`ES256`,`ES384`,`ES512`) expect `*ecdsa.PrivateKey` for signing and `*ecdsa.PublicKey` for validation
### JWT and OAuth
It's worth mentioning that OAuth and JWT are not the same thing. A JWT token is simply a signed JSON object. It can be used anywhere such a thing is useful. There is some confusion, though, as JWT is the most common type of bearer token used in OAuth2 authentication.
Without going too far down the rabbit hole, here's a description of the interaction of these technologies:
* OAuth is a protocol for allowing an identity provider to be separate from the service a user is logging in to. For example, whenever you use Facebook to log into a different service (Yelp, Spotify, etc), you are using OAuth.
* OAuth defines several options for passing around authentication data. One popular method is called a "bearer token". A bearer token is simply a string that _should_ only be held by an authenticated user. Thus, simply presenting this token proves your identity. You can probably derive from here why a JWT might make a good bearer token.
* Because bearer tokens are used for authentication, it's important they're kept secret. This is why transactions that use bearer tokens typically happen over SSL.
## More
Documentation can be found [on godoc.org](http://godoc.org/github.com/dgrijalva/jwt-go).
The command line utility included in this project (cmd/jwt) provides a straightforward example of token creation and parsing as well as a useful tool for debugging your own integration. You'll also find several implementation examples in the documentation.

View File

@@ -1,118 +0,0 @@
## `jwt-go` Version History
#### 3.2.0
* Added method `ParseUnverified` to allow users to split up the tasks of parsing and validation
* HMAC signing method returns `ErrInvalidKeyType` instead of `ErrInvalidKey` where appropriate
* Added options to `request.ParseFromRequest`, which allows for an arbitrary list of modifiers to parsing behavior. Initial set include `WithClaims` and `WithParser`. Existing usage of this function will continue to work as before.
* Deprecated `ParseFromRequestWithClaims` to simplify API in the future.
#### 3.1.0
* Improvements to `jwt` command line tool
* Added `SkipClaimsValidation` option to `Parser`
* Documentation updates
#### 3.0.0
* **Compatibility Breaking Changes**: See MIGRATION_GUIDE.md for tips on updating your code
* Dropped support for `[]byte` keys when using RSA signing methods. This convenience feature could contribute to security vulnerabilities involving mismatched key types with signing methods.
* `ParseFromRequest` has been moved to `request` subpackage and usage has changed
* The `Claims` property on `Token` is now type `Claims` instead of `map[string]interface{}`. The default value is type `MapClaims`, which is an alias to `map[string]interface{}`. This makes it possible to use a custom type when decoding claims.
* Other Additions and Changes
* Added `Claims` interface type to allow users to decode the claims into a custom type
* Added `ParseWithClaims`, which takes a third argument of type `Claims`. Use this function instead of `Parse` if you have a custom type you'd like to decode into.
* Dramatically improved the functionality and flexibility of `ParseFromRequest`, which is now in the `request` subpackage
* Added `ParseFromRequestWithClaims` which is the `FromRequest` equivalent of `ParseWithClaims`
* Added new interface type `Extractor`, which is used for extracting JWT strings from http requests. Used with `ParseFromRequest` and `ParseFromRequestWithClaims`.
* Added several new, more specific, validation errors to error type bitmask
* Moved examples from README to executable example files
* Signing method registry is now thread safe
* Added new property to `ValidationError`, which contains the raw error returned by calls made by parse/verify (such as those returned by keyfunc or json parser)
#### 2.7.0
This will likely be the last backwards compatible release before 3.0.0, excluding essential bug fixes.
* Added new option `-show` to the `jwt` command that will just output the decoded token without verifying
* Error text for expired tokens includes how long it's been expired
* Fixed incorrect error returned from `ParseRSAPublicKeyFromPEM`
* Documentation updates
#### 2.6.0
* Exposed inner error within ValidationError
* Fixed validation errors when using UseJSONNumber flag
* Added several unit tests
#### 2.5.0
* Added support for signing method none. You shouldn't use this. The API tries to make this clear.
* Updated/fixed some documentation
* Added more helpful error message when trying to parse tokens that begin with `BEARER `
#### 2.4.0
* Added new type, Parser, to allow for configuration of various parsing parameters
* You can now specify a list of valid signing methods. Anything outside this set will be rejected.
* You can now opt to use the `json.Number` type instead of `float64` when parsing token JSON
* Added support for [Travis CI](https://travis-ci.org/dgrijalva/jwt-go)
* Fixed some bugs with ECDSA parsing
#### 2.3.0
* Added support for ECDSA signing methods
* Added support for RSA PSS signing methods (requires go v1.4)
#### 2.2.0
* Gracefully handle a `nil` `Keyfunc` being passed to `Parse`. Result will now be the parsed token and an error, instead of a panic.
#### 2.1.0
Backwards compatible API change that was missed in 2.0.0.
* The `SignedString` method on `Token` now takes `interface{}` instead of `[]byte`
#### 2.0.0
There were two major reasons for breaking backwards compatibility with this update. The first was a refactor required to expand the width of the RSA and HMAC-SHA signing implementations. There will likely be no required code changes to support this change.
The second update, while unfortunately requiring a small change in integration, is required to open up this library to other signing methods. Not all keys used for all signing methods have a single standard on-disk representation. Requiring `[]byte` as the type for all keys proved too limiting. Additionally, this implementation allows for pre-parsed tokens to be reused, which might matter in an application that parses a high volume of tokens with a small set of keys. Backwards compatibilty has been maintained for passing `[]byte` to the RSA signing methods, but they will also accept `*rsa.PublicKey` and `*rsa.PrivateKey`.
It is likely the only integration change required here will be to change `func(t *jwt.Token) ([]byte, error)` to `func(t *jwt.Token) (interface{}, error)` when calling `Parse`.
* **Compatibility Breaking Changes**
* `SigningMethodHS256` is now `*SigningMethodHMAC` instead of `type struct`
* `SigningMethodRS256` is now `*SigningMethodRSA` instead of `type struct`
* `KeyFunc` now returns `interface{}` instead of `[]byte`
* `SigningMethod.Sign` now takes `interface{}` instead of `[]byte` for the key
* `SigningMethod.Verify` now takes `interface{}` instead of `[]byte` for the key
* Renamed type `SigningMethodHS256` to `SigningMethodHMAC`. Specific sizes are now just instances of this type.
* Added public package global `SigningMethodHS256`
* Added public package global `SigningMethodHS384`
* Added public package global `SigningMethodHS512`
* Renamed type `SigningMethodRS256` to `SigningMethodRSA`. Specific sizes are now just instances of this type.
* Added public package global `SigningMethodRS256`
* Added public package global `SigningMethodRS384`
* Added public package global `SigningMethodRS512`
* Moved sample private key for HMAC tests from an inline value to a file on disk. Value is unchanged.
* Refactored the RSA implementation to be easier to read
* Exposed helper methods `ParseRSAPrivateKeyFromPEM` and `ParseRSAPublicKeyFromPEM`
#### 1.0.2
* Fixed bug in parsing public keys from certificates
* Added more tests around the parsing of keys for RS256
* Code refactoring in RS256 implementation. No functional changes
#### 1.0.1
* Fixed panic if RS256 signing method was passed an invalid key
#### 1.0.0
* First versioned release
* API stabilized
* Supports creating, signing, parsing, and validating JWT tokens
* Supports RS256 and HS256 signing methods

View File

@@ -1,42 +0,0 @@
# Working on the Engine API
The Engine API is an HTTP API used by the command-line client to communicate with the daemon. It can also be used by third-party software to control the daemon.
It consists of various components in this repository:
- `api/swagger.yaml` A Swagger definition of the API.
- `api/types/` Types shared by both the client and server, representing various objects, options, responses, etc. Most are written manually, but some are automatically generated from the Swagger definition. See [#27919](https://github.com/docker/docker/issues/27919) for progress on this.
- `cli/` The command-line client.
- `client/` The Go client used by the command-line client. It can also be used by third-party Go programs.
- `daemon/` The daemon, which serves the API.
## Swagger definition
The API is defined by the [Swagger](http://swagger.io/specification/) definition in `api/swagger.yaml`. This definition can be used to:
1. To automatically generate documentation.
2. To automatically generate the Go server and client. (A work-in-progress.)
3. Provide a machine readable version of the API for introspecting what it can do, automatically generating clients for other languages, etc.
## Updating the API documentation
The API documentation is generated entirely from `api/swagger.yaml`. If you make updates to the API, you'll need to edit this file to represent the change in the documentation.
The file is split into two main sections:
- `definitions`, which defines re-usable objects used in requests and responses
- `paths`, which defines the API endpoints (and some inline objects which don't need to be reusable)
To make an edit, first look for the endpoint you want to edit under `paths`, then make the required edits. Endpoints may reference reusable objects with `$ref`, which can be found in the `definitions` section.
There is hopefully enough example material in the file for you to copy a similar pattern from elsewhere in the file (e.g. adding new fields or endpoints), but for the full reference, see the [Swagger specification](https://github.com/docker/docker/issues/27919)
`swagger.yaml` is validated by `hack/validate/swagger` to ensure it is a valid Swagger definition. This is useful for when you are making edits to ensure you are doing the right thing.
## Viewing the API documentation
When you make edits to `swagger.yaml`, you may want to check the generated API documentation to ensure it renders correctly.
Run `make swagger-docs` and a preview will be running at `http://localhost`. Some of the styling may be incorrect, but you'll be able to ensure that it is generating the correct documentation.
The production documentation is generated by vendoring `swagger.yaml` into [docker/docker.github.io](https://github.com/docker/docker.github.io).

View File

@@ -1,12 +0,0 @@
layout:
models:
- name: definition
source: asset:model
target: "{{ joinFilePath .Target .ModelPackage }}"
file_name: "{{ (snakize (pascalize .Name)) }}.go"
operations:
- name: handler
source: asset:serverOperation
target: "{{ joinFilePath .Target .APIPackage .Package }}"
file_name: "{{ (snakize (pascalize .Name)) }}.go"

File diff suppressed because it is too large Load Diff

View File

@@ -1,14 +0,0 @@
# Legacy API type versions
This package includes types for legacy API versions. The stable version of the API types live in `api/types/*.go`.
Consider moving a type here when you need to keep backwards compatibility in the API. This legacy types are organized by the latest API version they appear in. For instance, types in the `v1p19` package are valid for API versions below or equal `1.19`. Types in the `v1p20` package are valid for the API version `1.20`, since the versions below that will use the legacy types in `v1p19`.
## Package name conventions
The package name convention is to use `v` as a prefix for the version number and `p`(patch) as a separator. We use this nomenclature due to a few restrictions in the Go package name convention:
1. We cannot use `.` because it's interpreted by the language, think of `v1.20.CallFunction`.
2. We cannot use `_` because golint complains about it. The code is actually valid, but it looks probably more weird: `v1_20.CallFunction`.
For instance, if you want to modify a type that was available in the version `1.21` of the API but it will have different fields in the version `1.22`, you want to create a new package under `api/types/versions/v1p21`.

View File

@@ -1,35 +0,0 @@
# Go client for the Docker Engine API
The `docker` command uses this package to communicate with the daemon. It can also be used by your own Go applications to do anything the command-line interface does  running containers, pulling images, managing swarms, etc.
For example, to list running containers (the equivalent of `docker ps`):
```go
package main
import (
"context"
"fmt"
"github.com/docker/docker/api/types"
"github.com/docker/docker/client"
)
func main() {
cli, err := client.NewEnvClient()
if err != nil {
panic(err)
}
containers, err := cli.ContainerList(context.Background(), types.ContainerListOptions{})
if err != nil {
panic(err)
}
for _, container := range containers {
fmt.Printf("%s %s\n", container.ID[:10], container.Image)
}
}
```
[Full documentation is available on GoDoc.](https://godoc.org/github.com/docker/docker/client)

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