提交 47bf8820 编写于 作者: J jeff

Initial commit

上级

要显示的变更太多。

To preserve performance only 1000 of 1000+ files are displayed.
DATA_PATH=./tmp
KUBESPHERE_LOG_LEVEL=debug
pkg/cmd/api/spec/api.swagger.json linguist-generated=true
pkg/cmd/api/spec/static.go linguist-generated=true
# Number of days of inactivity before an issue becomes stale
daysUntilStale: 30
# Number of days of inactivity before a stale issue is closed
daysUntilClose: 14
# Issues with these labels will never be considered stale
exemptLabels:
- lifecycle/frozen
staleLabel: lifecycle/stale
# Comment to post when marking an issue as stale. Set to `false` to disable
markComment: >
This issue has been automatically marked as stale because it has not had
recent activity. It will be closed if no further activity occurs. Any further update will
cause the issue/pull request to no longer be considered stale. Thank you for your contributions.
# Comment to post when closing a stale issue. Set to `false` to disable
closeComment: >
This issue is being automatically closed due to inactivity.
---
name: Bug report
about: Create a report to help us improve
---
**General remarks**
> Please delete this section including header before submitting
> 也可以使用中文
>
> This form is to report bugs. For general usage questions refer to our Slack channel
> [KubeSphere-users](https://join.slack.com/t/kubesphere/shared_invite/enQtNTE3MDIxNzUxNzQ0LTdkNTc3OTdmNzdiODViZjViNTU5ZDY3M2I2MzY4MTI4OGZlOTJmMDg5ZTFiMDAwYzNlZDY5NjA0NzZlNDU5NmY)
**Describe the bug(描述下问题)**
A clear and concise description of what the bug is.
For UI issues please also add a screenshot that shows the issue.
**Versions used(KubeSphere/Kubernetes的版本)**
KubeSphere:
Kubernetes: (If KubeSphere installer used, you can skip this)
**Environment(环境的硬件配置)**
How many nodes and their hardware configuration:
For example:
3 masters: 8cpu/8g
3 nodes: 8cpu/16g
(and other info are welcomed to help us debugging)
**To Reproduce(复现步骤)**
Steps to reproduce the behavior:
1. Go to '...'
2. Click on '....'
3. Scroll down to '....'
4. See error
**Expected behavior(预期行为)**
A clear and concise description of what you expected to happen.
# Binaries for programs and plugins
*.exe
*.exe~
*.dll
*.so
*.dylib
# Test binary, build with `go test -c`
*.test
# Output of the go coverage tool, specifically when used with LiteIDE
*.out
# Files generated by JetBrains IDEs, e.g. IntelliJ IDEA
.idea/
*.iml
bin/
# Vscode files
.vscode/
tmp/
# OSX trash
.DS_Store
services:
- docker
language: go
git:
depth: false
go:
- 1.10
go_import_path: kubesphere.io/kubesphere
before_install:
- curl https://raw.githubusercontent.com/golang/dep/master/install.sh | sh
before_script:
- dep ensure -v
- docker --version
- dep ensure -v
script:
- make fmt-check && make build
deploy:
skip_cleanup: true
provider: script
script: bash install/scripts/docker_push
on:
branch: master
FROM golang:1.10.3 as builder
# Copy in the go src
WORKDIR /go/src/kubesphere.io/kubesphere
COPY pkg/ pkg/
COPY cmd/ cmd/
COPY vendor/ vendor/
RUN CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build -a -o ks-apiserver kubesphere.io/kubesphere/cmd/ks-apiserver
FROM alpine:3.6
WORKDIR /
COPY --from=builder /go/src/kubesphere.io/kubesphere/ks-apiserver .
COPY ./install/ingress-controller /etc/kubesphere/ingress-controller
COPY ./install/swagger-ui /usr/lib/kubesphere/swagger-ui
CMD ["ks-apiserver"]
此差异已折叠。
# 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
[[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 = "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"
[[constraint]]
name = "k8s.io/client-go"
version = "kubernetes-1.12.3"
[[constraint]]
name = "k8s.io/kubernetes"
version = "1.12.3"
[[constraint]]
name="sigs.k8s.io/controller-runtime"
version="v0.1.9"
[[override]]
name="sigs.k8s.io/controller-tools"
version="v0.1.9"
[[override]]
name="k8s.io/component-base"
branch="master"
[prune]
go-tests = true
unused-packages = true
# To use reference package:
# vendor/github.com/docker/docker/client/container_commit.go:17: undefined: reference.ParseNormalizedNamed
# vendor/github.com/docker/docker/client/container_commit.go:25: undefined: reference.TagNameOnly
# vendor/github.com/docker/docker/client/container_commit.go:30: undefined: reference.FamiliarNam
[[override]]
name = "github.com/docker/distribution"
branch = "master"
# To use reference package:
# vendor/github.com/docker/docker/registry/registry.go:30: cannot call non-function tlsconfig.ServerDefault (type tls.Config)
# vendor/github.com/docker/docker/registry/registry.go:66: undefined: tlsconfig.SystemCertPool
# vendor/github.com/docker/docker/registry/registry.go:168: cannot call non-function tlsconfig.ServerDefault (type tls.Config)
# vendor/github.com/docker/docker/registry/service_v2.go:11: cannot call non-function tlsconfig.ServerDefault (type tls.Config)
[[override]]
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"
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
1. Definitions.
"License" shall mean the terms and conditions for use, reproduction,
and distribution as defined by Sections 1 through 9 of this document.
"Licensor" shall mean the copyright owner or entity authorized by
the copyright owner that is granting the License.
"Legal Entity" shall mean the union of the acting entity and all
other entities that control, are controlled by, or are under common
control with that entity. For the purposes of this definition,
"control" means (i) the power, direct or indirect, to cause the
direction or management of such entity, whether by contract or
otherwise, or (ii) ownership of fifty percent (50%) or more of the
outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity
exercising permissions granted by this License.
"Source" form shall mean the preferred form for making modifications,
including but not limited to software source code, documentation
source, and configuration files.
"Object" form shall mean any form resulting from mechanical
transformation or translation of a Source form, including but
not limited to compiled object code, generated documentation,
and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or
Object form, made available under the License, as indicated by a
copyright notice that is included in or attached to the work
(an example is provided in the Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object
form, that is based on (or derived from) the Work and for which the
editorial revisions, annotations, elaborations, or other modifications
represent, as a whole, an original work of authorship. For the purposes
of this License, Derivative Works shall not include works that remain
separable from, or merely link (or bind by name) to the interfaces of,
the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including
the original version of the Work and any modifications or additions
to that Work or Derivative Works thereof, that is intentionally
submitted to Licensor for inclusion in the Work by the copyright owner
or by an individual or Legal Entity authorized to submit on behalf of
the copyright owner. For the purposes of this definition, "submitted"
means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems,
and issue tracking systems that are managed by, or on behalf of, the
Licensor for the purpose of discussing and improving the Work, but
excluding communication that is conspicuously marked or otherwise
designated in writing by the copyright owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity
on behalf of whom a Contribution has been received by Licensor and
subsequently incorporated within the Work.
2. Grant of Copyright License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the
Work and such Derivative Works in Source or Object form.
3. Grant of Patent License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
(except as stated in this section) patent license to make, have made,
use, offer to sell, sell, import, and otherwise transfer the Work,
where such license applies only to those patent claims licensable
by such Contributor that are necessarily infringed by their
Contribution(s) alone or by combination of their Contribution(s)
with the Work to which such Contribution(s) was submitted. If You
institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work
or a Contribution incorporated within the Work constitutes direct
or contributory patent infringement, then any patent licenses
granted to You under this License for that Work shall terminate
as of the date such litigation is filed.
4. Redistribution. You may reproduce and distribute copies of the
Work or Derivative Works thereof in any medium, with or without
modifications, and in Source or Object form, provided that You
meet the following conditions:
(a) You must give any other recipients of the Work or
Derivative Works a copy of this License; and
(b) You must cause any modified files to carry prominent notices
stating that You changed the files; and
(c) You must retain, in the Source form of any Derivative Works
that You distribute, all copyright, patent, trademark, and
attribution notices from the Source form of the Work,
excluding those notices that do not pertain to any part of
the Derivative Works; and
(d) If the Work includes a "NOTICE" text file as part of its
distribution, then any Derivative Works that You distribute must
include a readable copy of the attribution notices contained
within such NOTICE file, excluding those notices that do not
pertain to any part of the Derivative Works, in at least one
of the following places: within a NOTICE text file distributed
as part of the Derivative Works; within the Source form or
documentation, if provided along with the Derivative Works; or,
within a display generated by the Derivative Works, if and
wherever such third-party notices normally appear. The contents
of the NOTICE file are for informational purposes only and
do not modify the License. You may add Your own attribution
notices within Derivative Works that You distribute, alongside
or as an addendum to the NOTICE text from the Work, provided
that such additional attribution notices cannot be construed
as modifying the License.
You may add Your own copyright statement to Your modifications and
may provide additional or different license terms and conditions
for use, reproduction, or distribution of Your modifications, or
for any such Derivative Works as a whole, provided Your use,
reproduction, and distribution of the Work otherwise complies with
the conditions stated in this License.
5. Submission of Contributions. Unless You explicitly state otherwise,
any Contribution intentionally submitted for inclusion in the Work
by You to the Licensor shall be under the terms and conditions of
this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify
the terms of any separate license agreement you may have executed
with Licensor regarding such Contributions.
6. Trademarks. This License does not grant permission to use the trade
names, trademarks, service marks, or product names of the Licensor,
except as required for reasonable and customary use in describing the
origin of the Work and reproducing the content of the NOTICE file.
7. Disclaimer of Warranty. Unless required by applicable law or
agreed to in writing, Licensor provides the Work (and each
Contributor provides its Contributions) on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied, including, without limitation, any warranties or conditions
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
PARTICULAR PURPOSE. You are solely responsible for determining the
appropriateness of using or redistributing the Work and assume any
risks associated with Your exercise of permissions under this License.
8. Limitation of Liability. In no event and under no legal theory,
whether in tort (including negligence), contract, or otherwise,
unless required by applicable law (such as deliberate and grossly
negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special,
incidental, or consequential damages of any character arising as a
result of this License or out of the use or inability to use the
Work (including but not limited to damages for loss of goodwill,
work stoppage, computer failure or malfunction, or any and all
other commercial damages or losses), even if such Contributor
has been advised of the possibility of such damages.
9. Accepting Warranty or Additional Liability. While redistributing
the Work or Derivative Works thereof, You may choose to offer,
and charge a fee for, acceptance of support, warranty, indemnity,
or other liability obligations and/or rights consistent with this
License. However, in accepting such obligations, You may act only
on Your own behalf and on Your sole responsibility, not on behalf
of any other Contributor, and only if You agree to indemnify,
defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason
of your accepting any such warranty or additional liability.
END OF TERMS AND CONDITIONS
APPENDIX: How to apply the Apache License to your work.
To apply the Apache License to your work, attach the following
boilerplate notice, with the fields enclosed by brackets "[]"
replaced with your own identifying information. (Don't include
the brackets!) The text should be enclosed in the appropriate
comment syntax for the file format. We also recommend that a
file or class name and description of purpose be included on the
same "printed page" as the copyright notice for easier
identification within third-party archives.
Copyright [yyyy] [name of copyright owner]
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
# 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.
# The binary to build
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.
#
# Args:
# WHAT: Directory names to build. If any of these directories has a 'main'
# package, the build will produce executable files under $(OUT_DIR).
# If not specified, "everything" will be built.
# GOFLAGS: Extra flags to pass to 'go' when building.
# GOLDFLAGS: Extra linking flags passed to 'go' when building.
# GOGCFLAGS: Additional go compile flags passed to 'go' when building.
#
# Example:
# make
# make all
# make all WHAT=cmd/ks-apiserver
# Note: Use the -N -l options to disable compiler optimizations an inlining.
# Using these build options allows you to subsequently use source
# debugging tools like delve.
endef
.PHONY: all
all: ks-apiserver test
# Build ks-apiserver binary
ks-apiserver: generate fmt vet
hack/gobuild.sh cmd/ks-apiserver
# Run go fmt against code
fmt:
go fmt ./pkg/... ./cmd/...
# Run go vet against code
vet:
go vet ./pkg/... ./cmd/...
# Generate code
generate:
ifndef GOPATH
$(error GOPATH not defined, please define GOPATH. Run "go help gopath" to learn more about GOPATH)
endif
go generate ./pkg/... ./cmd/...
# Build the docker image
docker-build: test
docker build . -t ${IMG}
# Run tests
test: generate fmt vet
go test ./pkg/... ./cmd/... -coverprofile cover.out
.PHONY: clean
clean:
-make -C ./pkg/version clean
@echo "ok"
version: "1"
domain: kubesphere.io
repo: kubesphere.io/kubesphere
# KubeSphere
[![License](http://img.shields.io/badge/license-apache%20v2-blue.svg)](https://github.com/KubeSphere/KubeSphere/blob/master/LICENSE)
[![Build Status](https://travis-ci.org/kubesphere/kubesphere.svg?branch=master)](https://travis-ci.org/kubesphere/kubesphere)
----
***KubeSphere*** is a distribution of [Kubernetes](https://kubernetes.io), aimed to provide quick setup, friendly and easily use, and powerful management features for Kubernetes clusters, which could help both personal and enterprise users, reduce their learning curve of Kubernetes, accelerate their transform process from other container platforms to Kubernetes.  
**Features:**
- Multiple IaaS platform support, including baremetal/KVM/QingCloud, and more will be supported in future release.
- Easy setup of Kubernetes standalone(only one master node) and cluster environment(including High Availability support).
- Powerful management console to help business users to manage and monitor the Kubernetes.
- Integrate with [OpenPitrix](https://github.com/openpitrix) to provide full life cycle of application management and be compatible of helm package.
- Support popular open source network solutions, including calico and flannel, also could use [qingcloud hostnic solution](https://github.com/yunify/hostnic-cni) if the Kubernetes is deployed on QingCloud platform.
- Support popular open source storage solutions, including Glusterfs and Cephfs, also could use [qingcloud storage solution](https://github.com/yunify/qingcloud-csi) or [qingstor storage solution](https://github.com/yunify/qingstor-csi) if the Kubernetes is deployed on QingCloud platform or QingStor NeonSAN.
- CI/CD support.
- Service Mesh support.
- Multiple image registries support.
- Integrate with QingCloud IAM.
----
## Motivation
The project originates from the requirement and pains we heard from our customers on public and private QingCloud platform, who have strong will to deploy Kubernetes in their IT system but struggle on completed setup process and long learning curve. With help of KubeSphere, their IT operators could setup Kubernetes environment quickly and use an easy management UI interface to mange their applications, also KubeSphere provides more features to help customers to handle daily business more easily, including CI/CD, micro services management...etc.
Getting Started
---------------
**TBD**
## Design
## Contributing to the project
All members of the KubeSphere community must abide by [Code of Conduct](docs/code-of-conduct.md). Only by respecting each other can we develop a productive, collaborative community.
You can then find out more detail [here](docs/welcome-toKubeSphere-new-developer-guide.md).
ls /go/bin
go version
exit
# 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.2-alpine3.7 as builder
RUN apk add --no-cache git curl openssl
RUN go get github.com/tools/godep
#RUN go get github.com/emicklei/go-restful
#RUN go get github.com/golang/glog
#RUN go get github.com/spf13/pflag
RUN go get golang.org/x/tools/cmd/goimports
FROM golang:1.10.2-alpine3.7
RUN apk add --no-cache git make curl openssl jq rsync godep
COPY --from=builder /go/bin /go/bin
# 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.
default:
docker build -t kubesphere/kubesphere-builder .
@echo "ok"
pull:
docker pull kubesphere/kubesphere-builder
@echo "ok"
run:
docker run --rm -it -v `pwd`:/root kubesphere/kubesphere-builder
clean:
@echo "ok"
/*
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 main
import (
"flag"
"os"
_ "k8s.io/client-go/plugin/pkg/client/auth/gcp"
"sigs.k8s.io/controller-runtime/pkg/client/config"
"sigs.k8s.io/controller-runtime/pkg/manager"
logf "sigs.k8s.io/controller-runtime/pkg/runtime/log"
"sigs.k8s.io/controller-runtime/pkg/runtime/signals"
"kubesphere.io/kubesphere/pkg/apis"
"kubesphere.io/kubesphere/pkg/controller"
"kubesphere.io/kubesphere/pkg/webhook"
)
func main() {
var metricsAddr string
flag.StringVar(&metricsAddr, "metrics-addr", ":8080", "The address the metric endpoint binds to.")
flag.Parse()
logf.SetLogger(logf.ZapLogger(false))
log := logf.Log.WithName("entrypoint")
// Get a config to talk to the apiserver
log.Info("setting up client for manager")
cfg, err := config.GetConfig()
if err != nil {
log.Error(err, "unable to set up client config")
os.Exit(1)
}
// Create a new Cmd to provide shared dependencies and start components
log.Info("setting up manager")
mgr, err := manager.New(cfg, manager.Options{})
if err != nil {
log.Error(err, "unable to set up overall controller manager")
os.Exit(1)
}
log.Info("Registering Components.")
// Setup Scheme for all resources
log.Info("setting up scheme")
if err := apis.AddToScheme(mgr.GetScheme()); err != nil {
log.Error(err, "unable add APIs to scheme")
os.Exit(1)
}
// Setup all Controllers
log.Info("Setting up controller")
if err := controller.AddToManager(mgr); err != nil {
log.Error(err, "unable to register controllers to the manager")
os.Exit(1)
}
log.Info("setting up webhooks")
if err := webhook.AddToManager(mgr); err != nil {
log.Error(err, "unable to register webhooks to the manager")
os.Exit(1)
}
controller.Run(signals.SetupSignalHandler())
// Start the Cmd
log.Info("Starting the Cmd.")
if err := mgr.Start(signals.SetupSignalHandler()); err != nil {
log.Error(err, "unable to run the manager")
os.Exit(1)
}
}
package main
import (
"fmt"
"kubesphere.io/kubesphere/cmd/ks-apiserver/app"
"os"
// Install apis
_ "kubesphere.io/kubesphere/pkg/apis/metrics/install"
_ "kubesphere.io/kubesphere/pkg/apis/operations/install"
_ "kubesphere.io/kubesphere/pkg/apis/resources/install"
)
func main() {
cmd := app.NewAPIServerCommand()
if err := cmd.Execute(); err != nil {
fmt.Fprintf(os.Stderr, "error: %v\n", err)
os.Exit(1)
}
}
package options
import (
"fmt"
"github.com/spf13/pflag"
"os"
)
type ServerRunOptions struct {
// server bind address
BindAddress string
// insecure port number
InsecurePort int
// secure port number
SecurePort int
// OpenPitrix api gateway service url
OpenPitrixAddress string
// database connection string in MySQL like
// user:password@tcp(host)/dbname?charset=utf8&parseTime=True
DatabaseConnectionString string
// tls cert file
TlsCertFile string
// tls private key file
TlsPrivateKey string
// host openapi doc
ApiDoc bool
// kubeconfig file path
KubeConfig string
}
func NewServerRunOptions() *ServerRunOptions {
// create default server run options
s := ServerRunOptions{
BindAddress: "0.0.0.0",
InsecurePort: 9090,
SecurePort: 0,
OpenPitrixAddress: "openpitrix-api-gateway.openpitrix-system.svc",
DatabaseConnectionString: "",
TlsCertFile: "",
TlsPrivateKey: "",
ApiDoc: true,
}
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.OpenPitrixAddress, "openpitrix", "openpitrix-api-gateway.openpitrix-system.svc", "openpitrix api gateway address")
fs.StringVar(&s.DatabaseConnectionString, "database-connection", "", "database connection string")
fs.StringVar(&s.TlsCertFile, "tls-cert-file", "", "tls cert file")
fs.StringVar(&s.TlsPrivateKey, "tls-private-key", "", "tls private key")
fs.BoolVar(&s.ApiDoc, "api-doc", true, "host OpenAPI doc")
fs.StringVar(&s.KubeConfig, "kubeconfig", fmt.Sprintf("%s/.kube/config", os.Getenv("HOME")), "path to kubeconfig file")
}
package app
import (
"fmt"
"github.com/emicklei/go-restful-openapi"
"github.com/spf13/cobra"
"kubesphere.io/kubesphere/cmd/ks-apiserver/app/options"
"kubesphere.io/kubesphere/pkg/apiserver/runtime"
"kubesphere.io/kubesphere/pkg/client"
"kubesphere.io/kubesphere/pkg/filter"
"kubesphere.io/kubesphere/pkg/informers"
"kubesphere.io/kubesphere/pkg/signals"
"log"
"net/http"
)
func NewAPIServerCommand() *cobra.Command {
s := options.NewServerRunOptions()
cmd := &cobra.Command{
Use: "ks-apiserver",
Long: `The KubeSphere API server validates and configures data
for the api objects. The API Server services REST operations and provides the frontend to the
cluster's shared state through which all other components interact.`,
RunE: func(cmd *cobra.Command, args []string) error {
//s.AddFlags(cmd.Flags())
return Run(s)
},
}
s.AddFlags(cmd.Flags())
return cmd
}
func Run(s *options.ServerRunOptions) error {
var err error
stopChan := signals.SetupSignalHandler()
informers.SharedInformerFactory().Start(stopChan)
informers.SharedInformerFactory().WaitForCacheSync(stopChan)
log.Println("resources sync success")
container := runtime.Container
container.Filter(filter.Logging)
if len(s.KubeConfig) > 0 {
client.KubeConfigFile = s.KubeConfig
}
if s.ApiDoc {
config := restfulspec.Config{
WebServices: container.RegisteredWebServices(),
APIPath: "/apidoc.json",
}
container.Add(restfulspec.NewOpenAPIService(config))
}
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.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)
}
return err
}
# Adds namespace to all resources.
namespace: t-system
# Value of this field is prepended to the
# names of all resources, e.g. a deployment named
# "wordpress" becomes "alices-wordpress".
# Note that it should also match with the prefix (text before '-') of the namespace
# field above.
namePrefix: t-
# Labels to add to all resources and selectors.
#commonLabels:
# someName: someValue
# Each entry in this list must resolve to an existing
# resource definition in YAML. These are the resource
# files that kustomize reads, modifies and emits as a
# YAML string, with resources separated by document
# markers ("---").
resources:
- ../rbac/rbac_role.yaml
- ../rbac/rbac_role_binding.yaml
- ../manager/manager.yaml
# 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
patches:
- manager_image_patch.yaml
# Protect the /metrics endpoint by putting it behind auth.
# Only one of manager_auth_proxy_patch.yaml and
# manager_prometheus_metrics_patch.yaml should be enabled.
- manager_auth_proxy_patch.yaml
# If you want your controller-manager to expose the /metrics
# endpoint w/o any authn/z, uncomment the following line and
# comment manager_auth_proxy_patch.yaml.
# Only one of manager_auth_proxy_patch.yaml and
# manager_prometheus_metrics_patch.yaml should be enabled.
#- manager_prometheus_metrics_patch.yaml
vars:
- name: WEBHOOK_SECRET_NAME
objref:
kind: Secret
name: webhook-server-secret
apiVersion: v1
# This patch inject a sidecar container which is a HTTP proxy for the controller manager,
# it performs RBAC authorization against the Kubernetes API using SubjectAccessReviews.
apiVersion: apps/v1
kind: StatefulSet
metadata:
name: controller-manager
namespace: system
spec:
template:
spec:
containers:
- name: kube-rbac-proxy
image: gcr.io/kubebuilder/kube-rbac-proxy:v0.4.0
args:
- "--secure-listen-address=0.0.0.0:8443"
- "--upstream=http://127.0.0.1:8080/"
- "--logtostderr=true"
- "--v=10"
ports:
- containerPort: 8443
name: https
- name: manager
args:
- "--metrics-addr=127.0.0.1:8080"
apiVersion: apps/v1
kind: StatefulSet
metadata:
name: controller-manager
namespace: system
spec:
template:
spec:
containers:
# Change the value of image field below to your controller image URL
- image: IMAGE_URL
name: manager
# This patch enables Prometheus scraping for the manager pod.
apiVersion: apps/v1
kind: StatefulSet
metadata:
name: controller-manager
namespace: system
spec:
template:
metadata:
annotations:
prometheus.io/scrape: 'true'
spec:
containers:
# Expose the prometheus metrics on default port
- name: manager
ports:
- containerPort: 8080
name: metrics
protocol: TCP
apiVersion: v1
kind: Namespace
metadata:
labels:
control-plane: controller-manager
controller-tools.k8s.io: "1.0"
name: system
---
apiVersion: v1
kind: Service
metadata:
name: controller-manager-service
namespace: system
labels:
control-plane: controller-manager
controller-tools.k8s.io: "1.0"
spec:
selector:
control-plane: controller-manager
controller-tools.k8s.io: "1.0"
ports:
- port: 443
---
apiVersion: apps/v1
kind: StatefulSet
metadata:
name: controller-manager
namespace: system
labels:
control-plane: controller-manager
controller-tools.k8s.io: "1.0"
spec:
selector:
matchLabels:
control-plane: controller-manager
controller-tools.k8s.io: "1.0"
serviceName: controller-manager-service
template:
metadata:
labels:
control-plane: controller-manager
controller-tools.k8s.io: "1.0"
spec:
containers:
- command:
- /manager
image: controller:latest
imagePullPolicy: Always
name: manager
env:
- name: POD_NAMESPACE
valueFrom:
fieldRef:
fieldPath: metadata.namespace
- name: SECRET_NAME
value: $(WEBHOOK_SECRET_NAME)
resources:
limits:
cpu: 100m
memory: 30Mi
requests:
cpu: 100m
memory: 20Mi
ports:
- containerPort: 9876
name: webhook-server
protocol: TCP
volumeMounts:
- mountPath: /tmp/cert
name: cert
readOnly: true
terminationGracePeriodSeconds: 10
volumes:
- name: cert
secret:
defaultMode: 420
secretName: webhook-server-secret
---
apiVersion: v1
kind: Secret
metadata:
name: webhook-server-secret
namespace: system
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
name: proxy-role
rules:
- apiGroups: ["authentication.k8s.io"]
resources:
- tokenreviews
verbs: ["create"]
- apiGroups: ["authorization.k8s.io"]
resources:
- subjectaccessreviews
verbs: ["create"]
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
name: proxy-rolebinding
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: ClusterRole
name: proxy-role
subjects:
- kind: ServiceAccount
name: default
namespace: system
apiVersion: v1
kind: Service
metadata:
annotations:
prometheus.io/port: "8443"
prometheus.io/scheme: https
prometheus.io/scrape: "true"
labels:
control-plane: controller-manager
controller-tools.k8s.io: "1.0"
name: controller-manager-metrics-service
namespace: system
spec:
ports:
- name: https
port: 8443
targetPort: https
selector:
control-plane: controller-manager
controller-tools.k8s.io: "1.0"
// Copyright 2017 The OpenPitrix Authors. All rights reserved.
// Use of this source code is governed by a Apache license
// that can be found in the LICENSE file.
// Package openpitrix provides the best Paas and Iaas platform.
package kubesphere
# KubeSphere Code of Conduct
KubeSphere follows the [CNCF Code of Conduct](https://github.com/cncf/foundation/blob/master/code-of-conduct.md).
# Best practice of committing code
Besides following above conduct from CNCF, we also hope every contributor in this project could help us to improve the quality of code, something you should know before checking in any new code:
- As gopher, make sure you already read [the conduct of Go language](https://golang.org/conduct) and [the instruction of writting Go](https://golang.org/doc/effective_go.html).
- Fork the project under your account and make the changes you want there.
- Execute 'go fmt' for every piece of new code.
- Every pulling request(PR) would be better constructed with only one commit, this could help code reviewer to go through your code efficiently, also helpful for every follower of this project to understand what happens in this PR. If you need to make any further code change to address the comments from reviewers, which means some new commits will be generated under this PR, you need to use 'git rebase' to combine those commits together.
- Every PR should only solve one problem or provide one feature, don't put several different fixes into one PR.
- At lease two code reviewers should involve into code reviewing process.
- Please introduce new third-party packages as little as possible to reduce the vendor dependency of this project. For example, don't import a full unit converting package but only use one function from it. For this case, you'd better write that function by yourself.
- more.
\ No newline at end of file
# Architecture
Basic idea is to decouple application repository and runtime environment. The runtime environment an application can run is by matching the labels of runtime environment and the selector of the repository where the application is from.
## Design key points:
// Copyright 2017 The OpenPitrix Authors. All rights reserved.
// Use of this source code is governed by a Apache license
// that can be found in the LICENSE file.
// dot -Tpng -o output.png input.dot
digraph G {
rankdir = LR;
subgraph clusterClient {
node [
fixedsize = true,
width = 1, height = 1,
]
WebUI [shape = doublecircle];
MobileApp [shape = doublecircle];
XClient [shape = doublecircle];
}
WebUI -> ApiGateway[
label = "rest api",
dir = both,
style = bold,
];
MobileApp -> ApiGateway[
label = "rest api",
dir = both,
style = bold,
];
XClient -> ApiGateway[
label = "rest api",
dir = both,
style = bold,
];
subgraph clusterOpenpitrix {
// rest api gateway
ApiGateway [shape = rect,
fixedsize = true,
width = 1.4, height = 6.2,
];
// microservice
subgraph clusterServices {
node [
shape=record,
fixedsize = true,
width = 2.6, height = 1.3,
];
Cluster [shape = Mrecord];
Runtime [shape = Mrecord,
label="Runtime |{ plugin |{k8s|QingCloud|Other} }"
];
App [shape = Mrecord];
Repo [shape = Mrecord];
}
// service database
subgraph clusterDB {
node [
fixedsize = true,
width = 2.6, height = 1.3,
];
RepoDB [shape = cylinder];
AppDB [shape = cylinder];
RuntimeDB [shape = cylinder];
ClusterDB [shape = cylinder];
}
// api gateway
ApiGateway -> Cluster [
label = "grpc",
dir = both,
style = bold,
];
ApiGateway -> Repo [
label = "grpc",
dir = both,
style = bold,
];
ApiGateway -> App [
label = "grpc",
dir = both,
style = bold,
];
ApiGateway -> Runtime [
label = "grpc",
dir = both,
style = bold,
];
Repo -> RepoDB [label="SQL"];
App -> AppDB [label="SQL"];
Runtime -> RuntimeDB [label="SQL"];
Cluster -> ClusterDB [label="SQL"];
}
}
# Developing for KubeSphere [deprecated]
This document is intended to be the canonical source of truth for things like
supported toolchain versions for building KubeSphere.
If you find a requirement that this doc does not capture, or if you find other
docs with references to requirements that are not simply links to this doc,
please [submit an issue](https://github.com/kubesphere/kubesphere/issues/new).
This document is intended to be relative to the branch in which it is found.
It is guaranteed that requirements will change over time for the development
branch, but release branches should not change.
- [Prerequisites](#prerequisites)
- [Setting up Go](#setting-up-go)
- [To start developing KubeSphere](#to-start-developing-kubesphere)
- [DevOps](#devops)
## Prerequisites
KubeSphere only has few external dependencies you need to setup before being
able to build and run the code.
### Setting up Go
KubeSphere written in the [Go](http://golang.org) programming language.
To build, you'll need a Go (version 1.9+) development environment.
If you haven't set up a Go development environment, please follow
[these instructions](https://golang.org/doc/install)
to install the Go tools.
Set up your GOPATH and add a path entry for Go binaries to your PATH. Typically
added to your ~/.profile:
```shell
$ export GOPATH=~/go
$ export PATH=$PATH:$GOPATH/bin
```
## To start developing KubeSphere
There are two options to get KubeSphere source code and build the project:
**You have a working Go environment.**
```shell
$ go get -d kubesphere.io/kubesphere
$ cd $GOPATH/src/kubesphere.io/kubesphere
$ make all
```
**You have a working Docker environment.**
```shell
$ git clone https://github.com/kubesphere/kubesphere
$ cd kubesphere
$ make
```
# Pull Request Process
This doc explains the process and best practices for submitting a PR to the [KubeSphere project](https://github.com/kubeSphere/kubeSphere). It should serve as a reference for all contributors, and be useful especially to new and infrequent submitters.
- [Before You Submit a PR](#before-you-submit-a-pr)
* [Run Local Verifications](#run-local-verifications)
- [The PR Submit Process](#the-pr-submit-process)
* [Write Release Notes if Needed](#write-release-notes-if-needed)
* [The Testing and Merge Workflow](#the-testing-and-merge-workflow)
* [Marking Unfinished Pull Requests](#marking-unfinished-pull-requests)
* [Comment Commands Reference](#comment-commands-reference)
* [Automation](#automation)
* [How the e2e Tests Work](#how-the-e2e-tests-work)
- [Why was my PR closed?](#why-was-my-pr-closed)
- [Why is my PR not getting reviewed?](#why-is-my-pr-not-getting-reviewed)
- [Best Practices for Faster Reviews](#best-practices-for-faster-reviews)
* [0. Familiarize yourself with project conventions](#0-familiarize-yourself-with-project-conventions)
* [1. Is the feature wanted? Make a Design Doc or Sketch PR](#1-is-the-feature-wanted-make-a-design-doc-or-sketch-pr)
* [2. Smaller Is Better: Small Commits, Small PRs](#2-smaller-is-better-small-commits-small-prs)
* [3. Open a Different PR for Fixes and Generic Features](#3-open-a-different-pr-for-fixes-and-generic-features)
* [4. Comments Matter](#4-comments-matter)
* [5. Test](#5-test)
* [6. Squashing and Commit Titles](#6-squashing-and-commit-titles)
* [7. KISS, YAGNI, MVP, etc.](#7-kiss-yagni-mvp-etc)
* [8. It's OK to Push Back](#8-its-ok-to-push-back)
* [9. Common Sense and Courtesy](#9-common-sense-and-courtesy)
# Before You Submit a PR
This guide is for contributors who already have a PR to submit. If you're looking for information on setting up your developer environment and creating code to contribute to KubeSphere, see the [development guide](development.md).
**Make sure your PR adheres to our best practices. These include following project conventions, making small PRs, and commenting thoroughly. Please read the more detailed section on [Best Practices for Faster Reviews](#best-practices-for-faster-reviews) at the end of this doc.**
## Run Local Verifications
You can run these local verifications before you submit your PR to predict the
pass or fail of continuous integration.
# The PR Submit Process
Merging a PR requires the following steps to be completed before the PR will be merged automatically. For details about each step, see the [The Testing and Merge Workflow](#the-testing-and-merge-workflow) section below.
- Make the PR
- Release notes - do one of the following:
- Add notes in the release notes block, or
- Update the release note label
- Pass all tests
- Get a `/lgtm` from a reviewer
- Get approval from an owner
If your PR meets all of the steps above, it will enter the submit queue to be merged. When it is next in line to be merged, the tests will run a second time. If all tests pass, the PR will be merged automatically.
## Write Release Notes if Needed
Release notes are required for any PR with user-visible changes, such as bug-fixes, feature additions, and output format changes.
If you don't add release notes in the PR template, the `do-not-merge/release-note-label-needed` label is added to your PR automatically after you create it. There are a few ways to update it.
To add a release-note section to the PR description:
For PRs with a release note:
```release-note
Your release note here
```
For PRs that require additional action from users switching to the new release, include the string "action required" (case insensitive) in the release note:
```release-note
action required: your release note here
```
For PRs that don't need to be mentioned at release time, just write "NONE" (case insensitive):
```release-note
NONE
```
The `/release-note-none` comment command can still be used as an alternative to writing "NONE" in the release-note block if it is left empty.
To see how to format your release notes, view the [PR template](https://github.com/) for a brief example. PR titles and body comments can be modified at any time prior to the release to make them friendly for release notes.
// PR template TODO
Release notes apply to PRs on the master branch. For cherry-pick PRs, see the [cherry-pick instructions](cherry-picks.md). The only exception to these rules is when a PR is not a cherry-pick and is targeted directly to the non-master branch. In this case, a `release-note-*` label is required for that non-master PR.
// cherry-pick TODO
Now that your release notes are in shape, let's look at how the PR gets tested and merged.
## The Testing and Merge Workflow
The KubeSphere merge workflow uses comments to run tests and labels for merging PRs.
NOTE: For pull requests that are in progress but not ready for review,
prefix the PR title with `WIP` or `[WIP]` and track any remaining TODOs
in a checklist in the pull request description.
Here's the process the PR goes through on its way from submission to merging:
1. Make the pull request
1. `@o8x-merge-robot` assigns reviewers //TODO
If you're **not** a member of the KubeSphere organization:
1. Reviewer/KubeSphere Member checks that the PR is safe to test. If so, they comment `/ok-to-test`
1. Reviewer suggests edits
1. Push edits to your PR branch
1. Repeat the prior two steps as needed
1. (Optional) Some reviewers prefer that you squash commits at this step
1. Owner is assigned and will add the `/approve` label to the PR
If you are a member, or a member comments `/ok-to-test`, the PR will be considered to be trusted. Then the pre-submit tests will run:
1. Automatic tests run. See the current list of tests on the
1. If tests fail, resolve issues by pushing edits to your PR branch
1. If the failure is a flake, anyone on trusted PRs can comment `/retest` to rerun failed tests
Once the tests pass, all failures are commented as flakes, or the reviewer adds the labels `lgtm` and `approved`, the PR enters the final merge queue. The merge queue is needed to make sure no incompatible changes have been introduced by other PRs since the tests were last run on your PR.
Either the [on call contributor](on-call-rotations.md) will manage the merge queue manually. //TODO
1. The PR enters the merge queue ([http://submit-queue.KubeSphere.io]())
1. The merge queue triggers a test re-run with the comment `/test all [submit-queue is verifying that this PR is safe to merge]`
1. Author has signed the CLA (`cncf-cla: yes` label added to PR)
1. No changes made since last `lgtm` label applied
1. If tests fail, resolve issues by pushing edits to your PR branch
1. If the failure is a flake, anyone can comment `/retest` if the PR is trusted
1. If tests pass, the merge queue automatically merges the PR
That's the last step. Your PR is now merged.
## Marking Unfinished Pull Requests
If you want to solicit reviews before the implementation of your pull request is complete, you should hold your pull request to ensure that the merge queue does not pick it up and attempt to merge it. There are two methods to achieve this:
1. You may add the `/hold` or `/hold cancel` comment commands
2. You may add or remove a `WIP` or `[WIP]` prefix to your pull request title
The GitHub robots will add and remove the `do-not-merge/hold` label as you use the comment commands and the `do-not-merge/work-in-progress` label as you edit your title. While either label is present, your pull request will not be considered for merging.
## Comment Commands Reference//TODO
[The commands doc]() contains a reference for all comment commands. //TODO
## Automation//TODO
The KubeSphere developer community uses a variety of automation to manage pull requests. This automation is described in detail [in the automation doc](automation.md). //TODO
## How the Tests Work//TODO
The tests will post the status results to the PR. If an e2e test fails,
`@o8x-ci-robot` will comment on the PR with the test history and the
comment-command to re-run that test. e.g.
> The following tests failed, say /retest to rerun them all.
# Why was my PR closed?
Pull requests older than 90 days will be closed. Exceptions can be made for PRs that have active review comments, or that are awaiting other dependent PRs. Closed pull requests are easy to recreate, and little work is lost by closing a pull request that subsequently needs to be reopened. We want to limit the total number of PRs in flight to:
* Maintain a clean project
* Remove old PRs that would be difficult to rebase as the underlying code has changed over time
* Encourage code velocity
# Why is my PR not getting reviewed?
A few factors affect how long your PR might wait for review.
If it's the last few weeks of a milestone, we need to reduce churn and stabilize.
Or, it could be related to best practices. One common issue is that the PR is too big to review. Let's say you've touched 39 files and have 8657 insertions. When your would-be reviewers pull up the diffs, they run away - this PR is going to take 4 hours to review and they don't have 4 hours right now. They'll get to it later, just as soon as they have more free time (ha!).
There is a detailed rundown of best practices, including how to avoid too-lengthy PRs, in the next section.
But, if you've already followed the best practices and you still aren't getting any PR love, here are some
things you can do to move the process along:
* Make sure that your PR has an assigned reviewer (assignee in GitHub). If not, reply to the PR comment stream asking for a reviewer to be assigned.
* Ping the assignee (@username) on the PR comment stream, and ask for an estimate of when they can get to the review.
* Ping the assignee on [Slack](http://KubeSphere.slack.com). Remember that a person's GitHub username might not be the same as their Slack username.
* Ping the assignee by email (many of us have publicly available email addresses).
* If you're a member of the organization ping the [team](https://github.com/orgs/KubeSphere/teams) (via @team-name) that works in the area you're submitting code.
* If you have fixed all the issues from a review, and you haven't heard back, you should ping the assignee on the comment stream with a "please take another look" (`PTAL`) or similar comment indicating that you are ready for another review.
Read on to learn more about how to get faster reviews by following best practices.
# Best Practices for Faster Reviews
Most of this section is not specific to KubeSphere, but it's good to keep these best practices in mind when you're making a PR.
You've just had a brilliant idea on how to make KubeSphere better. Let's call that idea Feature-X. Feature-X is not even that complicated. You have a pretty good idea of how to implement it. You jump in and implement it, fixing a bunch of stuff along the way. You send your PR - this is awesome! And it sits. And sits. A week goes by and nobody reviews it. Finally, someone offers a few comments, which you fix up and wait for more review. And you wait. Another week or two go by. This is horrible.
Let's talk about best practices so your PR gets reviewed quickly.
## 0. Familiarize yourself with project conventions
* [Development guide](code-of-conduct.md)
## 1. Is the feature wanted? Make a Design Doc or Sketch PR
Are you sure Feature-X is something the KubeSphere team wants or will accept? Is it implemented to fit with other changes in flight? Are you willing to bet a few days or weeks of work on it?
It's better to get confirmation beforehand. There are two ways to do this:
- Make a proposal doc (in docs/proposals; for example [the QoS proposal]()
- Coordinate your effort with [SIG Docs]() ahead of time. //TODO
- Make a sketch PR (e.g., just the API or Go interface). Write or code up just enough to express the idea and the design and why you made those choices
Or, do all of the above.
Be clear about what type of feedback you are asking for when you submit a proposal doc or sketch PR.
Now, if we ask you to change the design, you won't have to re-write it all.
## 2. Smaller Is Better: Small Commits, Small PRs
Small commits and small PRs get reviewed faster and are more likely to be correct than big ones.
Attention is a scarce resource. If your PR takes 60 minutes to review, the reviewer's eye for detail is not as keen in the last 30 minutes as it was in the first. It might not get reviewed at all if it requires a large continuous block of time from the reviewer.
**Breaking up commits**
Break up your PR into multiple commits, at logical break points.
Making a series of discrete commits is a powerful way to express the evolution of an idea or the
different ideas that make up a single feature. Strive to group logically distinct ideas into separate commits.
For example, if you found that Feature-X needed some prefactoring to fit in, make a commit that JUST does that prefactoring. Then make a new commit for Feature-X.
Strike a balance with the number of commits. A PR with 25 commits is still very cumbersome to review, so use
judgment.
**Breaking up PRs**
Or, going back to our prefactoring example, you could also fork a new branch, do the prefactoring there and send a PR for that. If you can extract whole ideas from your PR and send those as PRs of their own, you can avoid the painful problem of continually rebasing.
KubeSphere is a fast-moving codebase - lock in your changes ASAP with your small PR, and make merges be someone else's problem.
Multiple small PRs are often better than multiple commits. Don't worry about flooding us with PRs. We'd rather have 100 small, obvious PRs than 10 unreviewable monoliths.
We want every PR to be useful on its own, so use your best judgment on what should be a PR vs. a commit.
As a rule of thumb, if your PR is directly related to Feature-X and nothing else, it should probably be part of the Feature-X PR. If you can explain why you are doing seemingly no-op work ("it makes the Feature-X change easier, I promise") we'll probably be OK with it. If you can imagine someone finding value independently of Feature-X, try it as a PR. (Do not link pull requests by `#` in a commit description, because GitHub creates lots of spam. Instead, reference other PRs via the PR your commit is in.)
## 3. Open a Different PR for Fixes and Generic Features
**Put changes that are unrelated to your feature into a different PR.**
Often, as you are implementing Feature-X, you will find bad comments, poorly named functions, bad structure, weak type-safety, etc.
You absolutely should fix those things (or at least file issues, please) - but not in the same PR as your feature. Otherwise, your diff will have way too many changes, and your reviewer won't see the forest for the trees.
**Look for opportunities to pull out generic features.**
For example, if you find yourself touching a lot of modules, think about the dependencies you are introducing between packages. Can some of what you're doing be made more generic and moved up and out of the Feature-X package? Do you need to use a function or type from an otherwise unrelated package? If so, promote! We have places for hosting more generic code.
Likewise, if Feature-X is similar in form to Feature-W which was checked in last month, and you're duplicating some tricky stuff from Feature-W, consider prefactoring the core logic out and using it in both Feature-W and
Feature-X. (Do that in its own commit or PR, please.)
## 4. Comments Matter
In your code, if someone might not understand why you did something (or you won't remember why later), comment it. Many code-review comments are about this exact issue.
If you think there's something pretty obvious that we could follow up on, add a TODO.
Read up on [GoDoc](https://blog.golang.org/godoc-documenting-go-code) - follow those general rules for comments.
## 5. Test
Nothing is more frustrating than starting a review, only to find that the tests are inadequate or absent. Very few PRs can touch code and NOT touch tests.
If you don't know how to test Feature-X, please ask! We'll be happy to help you design things for easy testing or to suggest appropriate test cases.
## 6. Squashing and Commit Titles
Your reviewer has finally sent you feedback on Feature-X.
Make the fixups, and don't squash yet. Put them in a new commit, and re-push. That way your reviewer can look at the new commit on its own, which is much faster than starting over.
We might still ask you to clean up your commits at the very end for the sake of a more readable history, but don't do this until asked: typically at the point where the PR would otherwise be tagged `LGTM`.
Each commit should have a good title line (<70 characters) and include an additional description paragraph describing in more detail the change intended.
**General squashing guidelines:**
* Sausage => squash
Do squash when there are several commits to fix bugs in the original commit(s), address reviewer feedback, etc. Really we only want to see the end state and commit message for the whole PR.
* Layers => don't squash
Don't squash when there are independent changes layered to achieve a single goal. For instance, writing a code munger could be one commit, applying it could be another, and adding a precommit check could be a third. One could argue they should be separate PRs, but there's really no way to test/review the munger without seeing it applied, and there needs to be a precommit check to ensure the munged output doesn't immediately get out of date.
A commit, as much as possible, should be a single logical change.
## 7. KISS, YAGNI, MVP, etc.
Sometimes we need to remind each other of core tenets of software design - Keep It Simple, You Aren't Gonna Need It, Minimum Viable Product, and so on. Adding a feature "because we might need it later" is antithetical to software that ships. Add the things you need NOW and (ideally) leave room for things you might need later - but don't implement them now.
## 8. It's OK to Push Back
Sometimes reviewers make mistakes. It's OK to push back on changes your reviewer requested. If you have a good reason for doing something a certain way, you are absolutely allowed to debate the merits of a requested change. Both the reviewer and reviewee should strive to discuss these issues in a polite and respectful manner.
You might be overruled, but you might also prevail. We're pretty reasonable people. Mostly.
Another phenomenon of open-source projects (where anyone can comment on any issue) is the dog-pile - your PR gets so many comments from so many people it becomes hard to follow. In this situation, you can ask the primary reviewer (assignee) whether they want you to fork a new PR to clear out all the comments. You don't HAVE to fix every issue raised by every person who feels like commenting, but you should answer reasonable comments with an explanation.
## 9. Common Sense and Courtesy
No document can take the place of common sense and good taste. Use your best judgment, while you put
a bit of thought into how your work can be made easier to review. If you do these things your PRs will get merged with less friction.
Welcome to KubeSphere! (New Developer Guide)
============================================
_This document assumes that you know what KubeSphere does.
Introduction
------------
This
document will help you understand the organization of the KubeSphere project and
direct you to the best places to get started. By the end of this doc, you'll be
able to pick up issues, write code to fix them, and get your work reviewed and
merged.
If you have questions about the development process, feel free to jump into our
[Slack workspace](http://KubeSphere.slack.com/). If you join the
Slack workspace it is recommended to set your Slack display name to your GitHub
account handle.
Downloading, Building, and Testing KubeSphere
---------------------------------------------
This guide is non-technical, so it does not cover the technical details of
working KubeSphere. We have plenty of documentation available under
[docs.kubesphere.io](https://docs.kubesphere.io).
Pull-Request Process
--------------------
The pull-request process is documented in [pull-requests.md](pull-requests.md).
As described in that document, you must sign the CLA before
KubeSphere can accept your contribution.
Thanks for reading!
/*
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.
*/
\ No newline at end of file
#!/usr/bin/env bash
# Push image to dockerhub, need to support multiple push
echo "$DOCKER_PASSWORD" | docker login -u "$DOCKER_USERNAME" --password-stdin
docker push kubespheredev/ks-apiserver:latest
\ No newline at end of file
#!/usr/bin/env bash
# Copyright 2017 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.
#
# This script builds and link stamps the output
set -o errexit
set -o nounset
set -o pipefail
VERBOSE=${VERBOSE:-"0"}
V=""
if [[ "${VERBOSE}" == "1" ]];then
V="-x"
set -x
fi
ROOTDIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
OUTPUT_DIR=${ROOTDIR}/bin
BUILDPATH=${ROOTDIR}/${1:?"path to build"}
OUT=${OUTPUT_DIR}/${1:?"output path"}
set -e
BUILD_GOOS=${GOOS:-linux}
BUILD_GOARCH=${GOARCH:-amd64}
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}
\ No newline at end of file
apiVersion: v1
kind: Service
metadata:
name: kubesphere-router-gateway
labels:
app: kubesphere
component: ks-router
tier: backend
spec:
selector:
app: kubesphere
component: ks-router
tier: backend
type: LoadBalancer
ports:
- name: http
protocol: TCP
port: 80
targetPort: 80
- name: https
protocol: TCP
port: 443
targetPort: 443
apiVersion: extensions/v1beta1
kind: Deployment
metadata:
name: ks-router
spec:
replicas: 1
selector:
matchLabels:
app: kubesphere
component: ks-router
tier: backend
template:
metadata:
labels:
app: kubesphere
component: ks-router
tier: backend
annotations:
prometheus.io/port: '10254'
prometheus.io/scrape: 'true'
spec:
serviceAccountName: kubesphere-router-serviceaccount
containers:
- name: nginx-ingress-controller
image: quay.io/kubernetes-ingress-controller/nginx-ingress-controller:0.16.2
args:
- /nginx-ingress-controller
- --default-backend-service=$(POD_NAMESPACE)/default-http-backend
- --configmap=$(POD_NAMESPACE)/nginx-configuration
- --annotations-prefix=nginx.ingress.kubernetes.io
- --force-namespace-isolation
- --update-status
- --update-status-on-shutdown
env:
- name: POD_NAME
valueFrom:
fieldRef:
fieldPath: metadata.name
- name: POD_NAMESPACE
valueFrom:
fieldRef:
fieldPath: metadata.namespace
ports:
- name: http
containerPort: 80
- name: https
containerPort: 443
livenessProbe:
failureThreshold: 3
httpGet:
path: /healthz
port: 10254
scheme: HTTP
initialDelaySeconds: 10
periodSeconds: 10
successThreshold: 1
timeoutSeconds: 1
readinessProbe:
failureThreshold: 3
httpGet:
path: /healthz
port: 10254
scheme: HTTP
periodSeconds: 10
successThreshold: 1
timeoutSeconds: 1
securityContext:
runAsNonRoot: false
#!/bin/bash
echo "$DOCKER_PASSWORD" | docker login -u "$DOCKER_USERNAME" --password-stdin
docker push kubespheredev/ks-apiserver:latest
<!-- HTML for static distribution bundle build -->
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Swagger UI</title>
<link rel="stylesheet" type="text/css" href="./swagger-ui.css" >
<link rel="icon" type="image/png" href="./favicon-32x32.png" sizes="32x32" />
<link rel="icon" type="image/png" href="./favicon-16x16.png" sizes="16x16" />
<style>
html
{
box-sizing: border-box;
overflow: -moz-scrollbars-vertical;
overflow-y: scroll;
}
*,
*:before,
*:after
{
box-sizing: inherit;
}
body
{
margin:0;
background: #fafafa;
}
</style>
</head>
<body>
<div id="swagger-ui"></div>
<script src="./swagger-ui-bundle.js"> </script>
<script src="./swagger-ui-standalone-preset.js"> </script>
<script>
window.onload = function() {
// Build a system
const ui = SwaggerUIBundle({
url: "/swagger-ui/api.json",
dom_id: '#swagger-ui',
deepLinking: true,
presets: [
SwaggerUIBundle.presets.apis,
SwaggerUIStandalonePreset
],
plugins: [
SwaggerUIBundle.plugins.DownloadUrl
],
layout: "StandaloneLayout"
})
window.ui = ui
}
</script>
</body>
</html>
<!doctype html>
<html lang="en-US">
<body onload="run()">
</body>
</html>
<script>
'use strict';
function run () {
var oauth2 = window.opener.swaggerUIRedirectOauth2;
var sentState = oauth2.state;
var redirectUrl = oauth2.redirectUrl;
var isValid, qp, arr;
if (/code|token|error/.test(window.location.hash)) {
qp = window.location.hash.substring(1);
} else {
qp = location.search.substring(1);
}
arr = qp.split("&")
arr.forEach(function (v,i,_arr) { _arr[i] = '"' + v.replace('=', '":"') + '"';})
qp = qp ? JSON.parse('{' + arr.join() + '}',
function (key, value) {
return key === "" ? value : decodeURIComponent(value)
}
) : {}
isValid = qp.state === sentState
if ((
oauth2.auth.schema.get("flow") === "accessCode"||
oauth2.auth.schema.get("flow") === "authorizationCode"
) && !oauth2.auth.code) {
if (!isValid) {
oauth2.errCb({
authId: oauth2.auth.name,
source: "auth",
level: "warning",
message: "Authorization may be unsafe, passed state was changed in server Passed state wasn't returned from auth server"
});
}
if (qp.code) {
delete oauth2.state;
oauth2.auth.code = qp.code;
oauth2.callback({auth: oauth2.auth, redirectUrl: redirectUrl});
} else {
let oauthErrorMsg
if (qp.error) {
oauthErrorMsg = "["+qp.error+"]: " +
(qp.error_description ? qp.error_description+ ". " : "no accessCode received from the server. ") +
(qp.error_uri ? "More info: "+qp.error_uri : "");
}
oauth2.errCb({
authId: oauth2.auth.name,
source: "auth",
level: "error",
message: oauthErrorMsg || "[Authorization failed]: no accessCode received from the server"
});
}
} else {
oauth2.callback({auth: oauth2.auth, token: qp, isValid: isValid, redirectUrl: redirectUrl});
}
window.close();
}
</script>
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
{"version":3,"sources":[],"names":[],"mappings":"","file":"swagger-ui.css","sourceRoot":""}
\ No newline at end of file
此差异已折叠。
此差异已折叠。
/*
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 contains KubeSphere API groups.
package apis
import (
"k8s.io/apimachinery/pkg/runtime"
)
// AddToSchemes may be used to add all resources defined in the project to a Scheme
var AddToSchemes runtime.SchemeBuilder
// AddToScheme adds all Resources to the Scheme
func AddToScheme(s *runtime.Scheme) error {
return AddToSchemes.AddToScheme(s)
}
/*
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 metrics
/*
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 install
import (
"github.com/emicklei/go-restful"
urlruntime "k8s.io/apimachinery/pkg/util/runtime"
metrcisv1alpha2 "kubesphere.io/kubesphere/pkg/apis/metrics/v1alpha2"
"kubesphere.io/kubesphere/pkg/apiserver/runtime"
)
func init() {
Install(runtime.Container)
}
func Install(container *restful.Container) {
urlruntime.Must(metrcisv1alpha2.AddToContainer(container))
}
/*
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/emicklei/go-restful"
"k8s.io/apimachinery/pkg/runtime/schema"
"kubesphere.io/kubesphere/pkg/apiserver/metrics"
"kubesphere.io/kubesphere/pkg/apiserver/runtime"
)
const GroupName = "metrics.kubesphere.io"
var GroupVersion = schema.GroupVersion{Group: GroupName, Version: "v1alpha2"}
var (
WebServiceBuilder = runtime.NewContainerBuilder(addWebService)
AddToContainer = WebServiceBuilder.AddToContainer
)
func addWebService(c *restful.Container) error {
webservice := runtime.NewWebService(GroupVersion)
webservice.Route(webservice.GET("/storageclasses/{storageclass}").To(metrics.GetScMetrics))
webservice.Route(webservice.GET("/metrics/storageclass").To(metrics.GetScMetricsList))
c.Add(webservice)
return nil
}
/*
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 operations
/*
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 install
import (
"github.com/emicklei/go-restful"
urlruntime "k8s.io/apimachinery/pkg/util/runtime"
operationsv1alpha2 "kubesphere.io/kubesphere/pkg/apis/operations/v1alpha2"
"kubesphere.io/kubesphere/pkg/apiserver/runtime"
)
func init() {
Install(runtime.Container)
}
func Install(container *restful.Container) {
urlruntime.Must(operationsv1alpha2.AddToContainer(container))
}
/*
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/emicklei/go-restful"
"github.com/emicklei/go-restful-openapi"
"k8s.io/apimachinery/pkg/runtime/schema"
"kubesphere.io/kubesphere/pkg/apiserver/operations"
"kubesphere.io/kubesphere/pkg/apiserver/runtime"
)
const GroupName = "operations.kubesphere.io"
var GroupVersion = schema.GroupVersion{Group: GroupName, Version: "v1alpha2"}
var (
WebServiceBuilder = runtime.NewContainerBuilder(addWebService)
AddToContainer = WebServiceBuilder.AddToContainer
)
func addWebService(c *restful.Container) error {
webservice := runtime.NewWebService(GroupVersion)
webservice.Route(webservice.POST("/nodes/{node}/drainage").To(operations.DrainNode))
webservice.Route(webservice.POST("/namespaces/{namespace}/jobs/{job}").
To(operations.RerunJob).
Metadata(restfulspec.KeyOpenAPITags, []string{"jobs"}).
Doc("Handle job operation").
Param(webservice.PathParameter("job", "job name").
DataType("string")).
Param(webservice.PathParameter("namespace", "job's namespace").
DataType("string")).
Param(webservice.QueryParameter("a", "action").
DataType("string")).
Writes(""))
c.Add(webservice)
return nil
}
/*
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 metrics
/*
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 install
import (
"github.com/emicklei/go-restful"
urlruntime "k8s.io/apimachinery/pkg/util/runtime"
resourcev1alpha2 "kubesphere.io/kubesphere/pkg/apis/resources/v1alpha2"
"kubesphere.io/kubesphere/pkg/apiserver/runtime"
)
func init() {
Install(runtime.Container)
}
func Install(c *restful.Container) {
urlruntime.Must(resourcev1alpha2.AddToContainer(c))
}
/*
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/emicklei/go-restful"
"github.com/emicklei/go-restful-openapi"
"k8s.io/apimachinery/pkg/runtime/schema"
"kubesphere.io/kubesphere/pkg/apiserver/resources"
"kubesphere.io/kubesphere/pkg/apiserver/runtime"
)
const GroupName = "resources.kubesphere.io"
var GroupVersion = schema.GroupVersion{Group: GroupName, Version: "v1alpha2"}
var (
WebServiceBuilder = runtime.NewContainerBuilder(addWebService)
AddToContainer = WebServiceBuilder.AddToContainer
)
func addWebService(c *restful.Container) error {
webservice := runtime.NewWebService(GroupVersion)
webservice.Route(webservice.GET("/namespaces/{namespace}/{resources}").To(resources.NamespaceResourceHandler))
webservice.Route(webservice.GET("/{resources}").To(resources.ClusterResourceHandler))
webservice.Route(webservice.GET("/storageclasses/{storageclass}/persistentvolumeclaims").To(resources.GetPvcListBySc))
webservice.Route(webservice.GET("/namespaces/{namespace}/persistentvolumeclaims/{pvc}/pods").To(resources.GetPodListByPvc))
tags := []string{"users"}
webservice.Route(webservice.GET("/users/{username}/kubectl").Doc("get user's kubectl pod").Param(webservice.PathParameter("username",
"username").DataType("string")).Metadata(restfulspec.KeyOpenAPITags, tags).To(resources.GetKubectl))
webservice.Route(webservice.GET("/users/{username}/kubeconfig").Doc("get users' kubeconfig").Param(webservice.PathParameter("username",
"username").DataType("string")).Metadata(restfulspec.KeyOpenAPITags, tags).To(resources.GetKubeconfig))
c.Add(webservice)
return nil
}
/*
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 components
import (
"github.com/emicklei/go-restful"
"kubesphere.io/kubesphere/pkg/errors"
"kubesphere.io/kubesphere/pkg/models/components"
)
func V1Alpha2(ws *restful.WebService) {
ws.Route(ws.GET("/components").To(getComponents))
ws.Route(ws.GET("/components/{component}").To(getComponentStatus))
ws.Route(ws.GET("/health").To(getSystemHealthStatus))
}
func getSystemHealthStatus(request *restful.Request, response *restful.Response) {
result, err := components.GetAllComponentsStatus()
if errors.HandlerError(err, response) {
return
}
response.WriteAsJson(result)
}
// get a specific component status
func getComponentStatus(request *restful.Request, response *restful.Response) {
component := request.PathParameter("component")
result, err := components.GetComponentStatus(component)
if errors.HandlerError(err, response) {
return
}
response.WriteAsJson(result)
}
// get all componentsHandler
func getComponents(request *restful.Request, response *restful.Response) {
result, err := components.GetAllComponentsStatus()
if errors.HandlerError(err, response) {
return
}
response.WriteAsJson(result)
}
/*
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 hpa
import (
"github.com/emicklei/go-restful"
"github.com/emicklei/go-restful-openapi"
"k8s.io/api/autoscaling/v1"
"kubesphere.io/kubesphere/pkg/errors"
"kubesphere.io/kubesphere/pkg/models/hpa"
)
func V1Alpha2(ws *restful.WebService) {
ws.Route(ws.GET("/namespaces/{namespace}/horizontalpodautoscalers/{horizontalpodautoscaler}").
To(getHpa).
Metadata(restfulspec.KeyOpenAPITags, []string{"hpa"}).
Doc("get horizontalpodautoscalers").
Param(ws.PathParameter("namespace", "horizontalpodautoscalers's namespace").
DataType("string")).
Param(ws.PathParameter("horizontalpodautoscaler", "horizontalpodautoscaler's name")).
Writes(v1.HorizontalPodAutoscaler{}))
}
func getHpa(req *restful.Request, resp *restful.Response) {
name := req.PathParameter("horizontalpodautoscaler")
namespace := req.PathParameter("namespace")
result, err := hpa.GetHPA(namespace, name)
if errors.HandlerError(err, resp) {
return
}
resp.WriteAsJson(result)
}
/*
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 metrics
import (
"github.com/emicklei/go-restful"
"kubesphere.io/kubesphere/pkg/errors"
"kubesphere.io/kubesphere/pkg/models/storage"
)
type scMetricsItem struct {
Name string `json:"name"`
Metrics *storage.ScMetrics `json:"metrics"`
}
// Get StorageClass item
// Extended API URL: "GET /api/v1alpha1/storage/storageclasses/{storageclass}/metrics"
func GetScMetrics(request *restful.Request, response *restful.Response) {
scName := request.PathParameter("storageclass")
metrics, err := storage.GetScMetrics(scName)
if errors.HandlerError(err, response) {
return
}
result := scMetricsItem{
Name: scName, Metrics: metrics,
}
response.WriteAsJson(result)
}
// Get StorageClass item list
// Extended API URL: "GET /api/v1alpha1/storage/storageclasses/metrics"
func GetScMetricsList(request *restful.Request, response *restful.Response) {
scList, err := storage.GetScList()
if errors.HandlerError(err, response) {
return
}
// Set return value
items := make([]scMetricsItem, 0)
for _, v := range scList {
metrics, err := storage.GetScMetrics(v.GetName())
if errors.HandlerError(err, response) {
return
}
item := scMetricsItem{
Name: v.GetName(), Metrics: metrics,
}
items = append(items, item)
}
response.WriteAsJson(items)
}
/*
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 operations
import (
"net/http"
"kubesphere.io/kubesphere/pkg/errors"
"kubesphere.io/kubesphere/pkg/models/workloads"
"github.com/emicklei/go-restful"
"fmt"
)
func RerunJob(req *restful.Request, resp *restful.Response) {
var err error
job := req.PathParameter("job")
namespace := req.PathParameter("namespace")
action := req.QueryParameter("a")
switch action {
case "rerun":
err = workloads.JobReRun(namespace, job)
default:
resp.WriteHeaderAndEntity(http.StatusBadRequest, errors.New(errors.InvalidArgument, fmt.Sprintf("invalid operation %s", action)))
return
}
if errors.HandlerError(err, resp) {
return
}
resp.WriteAsJson(errors.None)
}
/*
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 operations
import (
"github.com/emicklei/go-restful"
"kubesphere.io/kubesphere/pkg/errors"
"kubesphere.io/kubesphere/pkg/models/nodes"
)
func DrainNode(request *restful.Request, response *restful.Response) {
nodeName := request.PathParameter("node")
err := nodes.DrainNode(nodeName)
if errors.HandlerError(err, response) {
return
}
response.WriteAsJson(errors.None)
}
/*
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 quotas
import (
"github.com/emicklei/go-restful"
"github.com/emicklei/go-restful-openapi"
"kubesphere.io/kubesphere/pkg/errors"
"kubesphere.io/kubesphere/pkg/models/quotas"
)
func V1Alpha2(ws *restful.WebService) {
tags := []string{"quotas"}
ws.Route(ws.GET("/quotas").
To(getClusterQuotas).
Doc("get whole cluster's resource usage").
Writes(quotas.ResourceQuota{}).
Metadata(restfulspec.KeyOpenAPITags, tags))
ws.Route(ws.GET("/namespaces/{namespace}/quotas").
Doc("get specified namespace's resource quota and usage").
Param(ws.PathParameter("namespace", "namespace's name").
DataType("string")).
Writes(quotas.ResourceQuota{}).
Metadata(restfulspec.KeyOpenAPITags, tags).
To(getNamespaceQuotas))
}
func getNamespaceQuotas(req *restful.Request, resp *restful.Response) {
namespace := req.PathParameter("namespace")
quota, err := quotas.GetNamespaceQuotas(namespace)
if errors.HandlerError(err, resp) {
return
}
resp.WriteAsJson(quota)
}
func getClusterQuotas(req *restful.Request, resp *restful.Response) {
quota, err := quotas.GetClusterQuotas()
if errors.HandlerError(err, resp) {
return
}
resp.WriteAsJson(quota)
}
/*
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 registries
import (
"github.com/emicklei/go-restful"
"kubesphere.io/kubesphere/pkg/errors"
"kubesphere.io/kubesphere/pkg/models/registries"
)
func V1Alpha2(ws *restful.WebService) {
ws.Route(ws.POST("registries/verify").To(registryVerify))
}
func registryVerify(request *restful.Request, response *restful.Response) {
authInfo := registries.AuthInfo{}
err := request.ReadEntity(&authInfo)
if errors.HandlerError(err, response) {
return
}
err = registries.RegistryVerify(authInfo)
if errors.HandlerError(err, response) {
return
}
response.WriteAsJson(errors.None)
}
//func (c *registriesHandler) handlerImageSearch(request *restful.Request, response *restful.Response) {
//
// registry := request.PathParameter("name")
// searchWord := request.PathParameter("searchWord")
// namespace := request.PathParameter("namespace")
//
// res := c.registries.ImageSearch(namespace, registry, searchWord)
//
// response.WriteAsJson(res)
//
//}
//
//func (c *registriesHandler) handlerGetImageTags(request *restful.Request, response *restful.Response) {
//
// registry := request.PathParameter("name")
// image := request.QueryParameter("image")
// namespace := request.PathParameter("namespace")
//
// res := c.registries.GetImageTags(namespace, registry, image)
//
// response.WriteAsJson(res)
//}
/*
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 resources
import (
"github.com/emicklei/go-restful"
"kubesphere.io/kubesphere/pkg/errors"
"kubesphere.io/kubesphere/pkg/models/resources"
"kubesphere.io/kubesphere/pkg/params"
)
func ClusterResourceHandler(req *restful.Request, resp *restful.Response) {
resourceName := req.PathParameter("resources")
conditions := req.QueryParameter(params.Conditions)
orderBy := req.QueryParameter(params.OrderBy)
limit, offset := params.ParsePaging(req.QueryParameter(params.Paging))
reverse := params.ParseReserve(req.QueryParameter(params.Reserve))
result, err := resources.ListClusterResource(resourceName, conditions, orderBy, reverse, limit, offset)
if errors.HandlerError(err, resp) {
return
}
resp.WriteAsJson(result)
}
/*
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 resources
import (
"github.com/emicklei/go-restful"
"kubesphere.io/kubesphere/pkg/errors"
"kubesphere.io/kubesphere/pkg/models/resources"
"kubesphere.io/kubesphere/pkg/params"
)
func NamespaceResourceHandler(req *restful.Request, resp *restful.Response) {
namespace := req.PathParameter("namespace")
resourceName := req.PathParameter("resources")
conditions := req.QueryParameter(params.Conditions)
orderBy := req.QueryParameter(params.OrderBy)
limit, offset := params.ParsePaging(req.QueryParameter(params.Paging))
reverse := params.ParseReserve(req.QueryParameter(params.Reserve))
result, err := resources.ListNamespaceResource(namespace, resourceName, conditions, orderBy, reverse, limit, offset)
if errors.HandlerError(err, resp) {
return
}
resp.WriteAsJson(result)
}
/*
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 resources
import (
"github.com/emicklei/go-restful"
"k8s.io/api/core/v1"
"kubesphere.io/kubesphere/pkg/errors"
"kubesphere.io/kubesphere/pkg/models/storage"
)
type pvcList struct {
Name string `json:"name"`
Items []*v1.PersistentVolumeClaim `json:"items"`
}
type podListByPvc struct {
Name string `json:"name"`
Namespace string `json:"namespace"`
Pods []*v1.Pod `json:"pods"`
}
// List all pods of a specific PVC
// Extended API URL: "GET /api/v1alpha2/namespaces/{namespace}/persistentvolumeclaims/{name}/pods"
func GetPodListByPvc(request *restful.Request, response *restful.Response) {
pvcName := request.PathParameter("pvc")
nsName := request.PathParameter("namespace")
pods, err := storage.GetPodListByPvc(pvcName, nsName)
if errors.HandlerError(err, response) {
return
}
result := podListByPvc{Name: pvcName, Namespace: nsName, Pods: pods}
response.WriteAsJson(result)
}
// List all PersistentVolumeClaims of a specific StorageClass
// Extended API URL: "GET /api/v1alpha2/storageclasses/{storageclass}/persistentvolumeclaims"
func GetPvcListBySc(request *restful.Request, response *restful.Response) {
scName := request.PathParameter("storageclass")
claims, err := storage.GetPvcListBySc(scName)
if errors.HandlerError(err, response) {
return
}
result := pvcList{
Name: scName, Items: claims,
}
response.WriteAsJson(result)
}
/*
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 resources
import (
"github.com/emicklei/go-restful"
"kubesphere.io/kubesphere/pkg/errors"
"kubesphere.io/kubesphere/pkg/models/kubeconfig"
"kubesphere.io/kubesphere/pkg/models/kubectl"
)
func GetKubectl(req *restful.Request, resp *restful.Response) {
user := req.PathParameter("username")
kubectlPod, err := kubectl.GetKubectlPod(user)
if errors.HandlerError(err, resp) {
return
}
resp.WriteAsJson(kubectlPod)
}
func GetKubeconfig(req *restful.Request, resp *restful.Response) {
user := req.PathParameter("username")
kubectlConfig, err := kubeconfig.GetKubeConfig(user)
if errors.HandlerError(err, resp) {
return
}
resp.WriteAsJson(kubectlConfig)
}
/*
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 revisions
import (
"net/http"
"strconv"
"github.com/emicklei/go-restful"
"github.com/emicklei/go-restful-openapi"
"k8s.io/api/apps/v1"
"kubesphere.io/kubesphere/pkg/errors"
"kubesphere.io/kubesphere/pkg/models/revisions"
)
func V1Alpha2(ws *restful.WebService) {
ws.Route(ws.GET("/namespaces/{namespace}/daemonsets/{daemonset}/revisions/{revision}").
To(getDaemonSetRevision).
Metadata(restfulspec.KeyOpenAPITags, []string{"daemonsets", "revision"}).
Doc("Handle daemonset operation").
Param(ws.PathParameter("daemonset", "daemonset's name").
DataType("string")).
Param(ws.PathParameter("namespace", "daemonset's namespace").
DataType("string")).
Param(ws.PathParameter("revision", "daemonset's revision")).
Writes(v1.DaemonSet{}))
ws.Route(ws.GET("/namespaces/{namespace}/deployments/{deployment}/revisions/{revision}").
To(getDeployRevision).
Metadata(restfulspec.KeyOpenAPITags, []string{"deployments", "revision"}).
Doc("Handle deployment operation").
Param(ws.PathParameter("deployment", "deployment's name").
DataType("string")).
Param(ws.PathParameter("namespace",
"deployment's namespace").
DataType("string")).
Param(ws.PathParameter("deployment", "deployment's name")).
Writes(v1.ReplicaSet{}))
ws.Route(ws.GET("/namespaces/{namespace}/statefulsets/{statefulset}/revisions/{revision}").
To(getStatefulSetRevision).
Metadata(restfulspec.KeyOpenAPITags, []string{"statefulsets", "revisions"}).
Doc("Handle statefulset operation").
Param(ws.PathParameter("statefulset", "statefulset's name").
DataType("string")).
Param(ws.PathParameter("namespace", "statefulset's namespace").
DataType("string")).
Param(ws.PathParameter("revision", "statefulset's revision")).
Writes(v1.StatefulSet{}))
}
func getDaemonSetRevision(req *restful.Request, resp *restful.Response) {
daemonset := req.PathParameter("daemonset")
namespace := req.PathParameter("namespace")
revision, err := strconv.Atoi(req.PathParameter("revision"))
if err != nil {
resp.WriteHeaderAndEntity(http.StatusBadRequest, errors.New(errors.InvalidArgument, err.Error()))
return
}
result, err := revisions.GetDaemonSetRevision(namespace, daemonset, revision)
if errors.HandlerError(err, resp) {
return
}
resp.WriteAsJson(result)
}
func getDeployRevision(req *restful.Request, resp *restful.Response) {
deploy := req.PathParameter("deployment")
namespace := req.PathParameter("namespace")
revision := req.PathParameter("revision")
result, err := revisions.GetDeployRevision(namespace, deploy, revision)
if errors.HandlerError(err, resp) {
return
}
resp.WriteAsJson(result)
}
func getStatefulSetRevision(req *restful.Request, resp *restful.Response) {
statefulset := req.PathParameter("statefulset")
namespace := req.PathParameter("namespace")
revision, err := strconv.Atoi(req.PathParameter("revision"))
if err != nil {
resp.WriteHeaderAndEntity(http.StatusBadRequest, errors.New(errors.InvalidArgument, err.Error()))
return
}
result, err := revisions.GetStatefulSetRevision(namespace, statefulset, revision)
if errors.HandlerError(err, resp) {
return
}
resp.WriteAsJson(result)
}
/*
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 routers
import (
"github.com/emicklei/go-restful"
"kubesphere.io/kubesphere/pkg/errors"
"net/http"
"strings"
"github.com/golang/glog"
"k8s.io/api/core/v1"
"kubesphere.io/kubesphere/pkg/models/routers"
)
func V1Alpha2(ws *restful.WebService) {
ws.Route(ws.GET("/routers").To(getAllRouters).
Doc("Get all routers"))
ws.Route(ws.GET("/users/{username}/routers").To(getAllRoutersOfUser).
Doc("Get routers for user"))
ws.Route(ws.GET("/namespaces/{namespace}/router").To(getRouter).
Doc("Get router of a specified project").
Param(ws.PathParameter("namespace", "name of the project").
DataType("string")))
ws.Route(ws.DELETE("/namespaces/{namespace}/router").To(deleteRouter).
Doc("Get router of a specified project").
Param(ws.PathParameter("namespace", "name of the project").
DataType("string")))
ws.Route(ws.POST("/namespaces/{namespace}/router").To(createRouter).
Doc("Create a router for a specified project").
Param(ws.PathParameter("namespace", "name of the project").
DataType("string")))
ws.Route(ws.PUT("/namespaces/{namespace}/router").To(updateRouter).
Doc("Update a router for a specified project").
Param(ws.PathParameter("namespace", "name of the project").
DataType("string")))
}
type Router struct {
RouterType string `json:"type"`
Annotations map[string]string `json:"annotations"`
}
// Get all namespace ingress controller services
func getAllRouters(request *restful.Request, response *restful.Response) {
routers, err := routers.GetAllRouters()
if errors.HandlerError(err, response) {
return
}
response.WriteAsJson(routers)
}
// Get all namespace ingress controller services for user
func getAllRoutersOfUser(request *restful.Request, response *restful.Response) {
username := request.PathParameter("username")
routers, err := routers.GetAllRoutersOfUser(username)
if errors.HandlerError(err, response) {
return
}
response.WriteAsJson(routers)
}
// Get ingress controller service for specified namespace
func getRouter(request *restful.Request, response *restful.Response) {
namespace := request.PathParameter("namespace")
router, err := routers.GetRouter(namespace)
if errors.HandlerError(err, response) {
return
}
response.WriteAsJson(router)
}
// Create ingress controller and related services
func createRouter(request *restful.Request, response *restful.Response) {
namespace := request.PathParameter("namespace")
newRouter := Router{}
err := request.ReadEntity(&newRouter)
if err != nil {
response.WriteAsJson(err)
return
}
var router *v1.Service
serviceType, annotationMap, err := ParseParameter(newRouter)
if err != nil {
glog.Error("Wrong annotations, missing key or value")
response.WriteHeaderAndEntity(http.StatusBadRequest,
errors.New(errors.InvalidArgument, "Wrong annotations, missing key or value"))
return
}
router, err = routers.CreateRouter(namespace, serviceType, annotationMap)
if errors.HandlerError(err, response) {
return
}
response.WriteAsJson(router)
}
// Delete ingress controller and services
func deleteRouter(request *restful.Request, response *restful.Response) {
namespace := request.PathParameter("namespace")
router, err := routers.DeleteRouter(namespace)
if errors.HandlerError(err, response) {
return
}
response.WriteAsJson(router)
}
func updateRouter(request *restful.Request, response *restful.Response) {
namespace := request.PathParameter("namespace")
newRouter := Router{}
err := request.ReadEntity(&newRouter)
if err != nil {
glog.Error(err)
response.WriteHeaderAndEntity(http.StatusBadRequest, errors.New(errors.InvalidArgument, err.Error()))
return
}
serviceType, annotationMap, err := ParseParameter(newRouter)
router, err := routers.UpdateRouter(namespace, serviceType, annotationMap)
if errors.HandlerError(err, response) {
return
}
response.WriteAsJson(router)
}
func ParseParameter(router Router) (routerType v1.ServiceType, annotationMap map[string]string, err error) {
routerType = v1.ServiceTypeNodePort
if strings.Compare(strings.ToLower(router.RouterType), "loadbalancer") == 0 {
return v1.ServiceTypeLoadBalancer, router.Annotations, nil
} else {
return v1.ServiceTypeNodePort, make(map[string]string, 0), nil
}
}
/*
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 runtime
import (
"github.com/emicklei/go-restful"
"k8s.io/apimachinery/pkg/runtime/schema"
)
const (
ApiRootPath = "/apis"
)
// container holds all webservice of apiserver
var Container = restful.NewContainer()
type ContainerBuilder []func(c *restful.Container) error
//
func NewWebService(gv schema.GroupVersion) *restful.WebService {
webservice := restful.WebService{}
webservice.Path(ApiRootPath + "/" + gv.String())
return &webservice
}
func (cb *ContainerBuilder) AddToContainer(c *restful.Container) error {
for _, f := range *cb {
if err := f(c); err != nil {
return err
}
}
return nil
}
func (cb *ContainerBuilder) Register(funcs ...func(*restful.Container) error) {
for _, f := range funcs {
*cb = append(*cb, f)
}
}
//
func NewContainerBuilder(funcs ...func(*restful.Container) error) ContainerBuilder {
var cb ContainerBuilder
cb.Register(funcs...)
return cb
}
/*
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 workloadstatuses
import (
"github.com/emicklei/go-restful"
"github.com/emicklei/go-restful-openapi"
"kubesphere.io/kubesphere/pkg/errors"
"kubesphere.io/kubesphere/pkg/models/status"
)
func V1Alpha2(ws *restful.WebService) {
tags := []string{"workloadStatus"}
ws.Route(ws.GET("/workloadstatuses").
Doc("get abnormal workloads' count of whole cluster").
Metadata(restfulspec.KeyOpenAPITags, tags).
To(getClusterResourceStatus))
ws.Route(ws.GET("/namespaces/{namespace}/workloadstatuses").
Doc("get abnormal workloads' count of specified namespace").
Param(ws.PathParameter("namespace", "the name of namespace").
DataType("string")).
Metadata(restfulspec.KeyOpenAPITags, tags).
To(getNamespacesResourceStatus))
}
func getClusterResourceStatus(req *restful.Request, resp *restful.Response) {
res, err := status.GetClusterResourceStatus()
if errors.HandlerError(err, resp) {
return
}
resp.WriteAsJson(res)
}
func getNamespacesResourceStatus(req *restful.Request, resp *restful.Response) {
res, err := status.GetNamespacesResourceStatus(req.PathParameter("namespace"))
if errors.HandlerError(err, resp) {
return
}
resp.WriteAsJson(res)
}
/*
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 workspaces
import (
"net/http"
"kubesphere.io/kubesphere/pkg/errors"
"kubesphere.io/kubesphere/pkg/models"
"kubesphere.io/kubesphere/pkg/models/metrics"
"github.com/emicklei/go-restful"
"k8s.io/api/core/v1"
"fmt"
"strings"
"strconv"
"regexp"
"sort"
"kubesphere.io/kubesphere/pkg/models/iam"
"kubesphere.io/kubesphere/pkg/models/workspaces"
)
const UserNameHeader = "X-Token-Username"
func V1Alpha2(ws *restful.WebService) {
ws.Route(ws.GET("/workspaces").To(UserWorkspaceListHandler))
ws.Route(ws.POST("/workspaces").To(WorkspaceCreateHandler))
ws.Route(ws.DELETE("/workspaces/{name}").To(DeleteWorkspaceHandler))
ws.Route(ws.GET("/workspaces/{name}").To(WorkspaceDetailHandler))
ws.Route(ws.PUT("/workspaces/{name}").To(WorkspaceEditHandler))
ws.Route(ws.GET("/workspaces/{workspace}/namespaces").To(UserNamespaceListHandler))
ws.Route(ws.GET("/workspaces/{workspace}/members/{username}/namespaces").To(UserNamespaceListHandler))
ws.Route(ws.POST("/workspaces/{name}/namespaces").To(NamespaceCreateHandler))
ws.Route(ws.DELETE("/workspaces/{name}/namespaces/{namespace}").To(NamespaceDeleteHandler))
ws.Route(ws.GET("/workspaces/{name}/namespaces/{namespace}").To(NamespaceCheckHandler))
ws.Route(ws.GET("/namespaces/{namespace}").To(NamespaceCheckHandler))
ws.Route(ws.GET("/workspaces/{name}/devops").To(DevOpsProjectHandler))
ws.Route(ws.GET("/workspaces/{name}/members/{username}/devops").To(DevOpsProjectHandler))
ws.Route(ws.POST("/workspaces/{name}/devops").To(DevOpsProjectCreateHandler))
ws.Route(ws.DELETE("/workspaces/{name}/devops/{id}").To(DevOpsProjectDeleteHandler))
ws.Route(ws.GET("/workspaces/{name}/members").To(MembersHandler))
ws.Route(ws.GET("/workspaces/{name}/members/{member}").To(MemberHandler))
ws.Route(ws.GET("/workspaces/{name}/roles").To(RolesHandler))
// TODO /workspaces/{name}/roles/{role}
ws.Route(ws.POST("/workspaces/{name}/members").To(MembersInviteHandler))
ws.Route(ws.DELETE("/workspaces/{name}/members").To(MembersRemoveHandler))
}
func RolesHandler(req *restful.Request, resp *restful.Response) {
name := req.PathParameter("name")
workspace, err := workspaces.Detail(name)
if errors.HandlerError(err, resp) {
return
}
roles, err := workspaces.Roles(workspace)
if errors.HandlerError(err, resp) {
return
}
resp.WriteAsJson(roles)
}
func MembersHandler(req *restful.Request, resp *restful.Response) {
workspace := req.PathParameter("name")
keyword := req.QueryParameter("keyword")
users, err := workspaces.GetWorkspaceMembers(workspace, keyword)
if errors.HandlerError(err, resp) {
return
}
resp.WriteAsJson(users)
}
func MemberHandler(req *restful.Request, resp *restful.Response) {
workspace := req.PathParameter("name")
username := req.PathParameter("member")
user, err := iam.GetUser(username)
if errors.HandlerError(err, resp) {
return
}
namespaces, err := workspaces.Namespaces(workspace)
if errors.HandlerError(err, resp) {
return
}
user.WorkspaceRole = user.WorkspaceRoles[workspace]
roles := make(map[string]string)
for _, namespace := range namespaces {
if role := user.Roles[namespace.Name]; role != "" {
roles[namespace.Name] = role
}
}
user.Roles = roles
user.Rules = nil
user.WorkspaceRules = nil
user.WorkspaceRoles = nil
user.ClusterRules = nil
resp.WriteAsJson(user)
}
func MembersInviteHandler(req *restful.Request, resp *restful.Response) {
var users []workspaces.UserInvite
workspace := req.PathParameter("name")
err := req.ReadEntity(&users)
if errors.HandlerError(err, resp) {
return
}
err = workspaces.Invite(workspace, users)
if errors.HandlerError(err, resp) {
return
}
resp.WriteAsJson(errors.None)
}
func MembersRemoveHandler(req *restful.Request, resp *restful.Response) {
query := req.QueryParameter("name")
workspace := req.PathParameter("name")
names := strings.Split(query, ",")
err := workspaces.RemoveMembers(workspace, names)
if errors.HandlerError(err, resp) {
return
}
resp.WriteAsJson(errors.None)
}
func NamespaceCheckHandler(req *restful.Request, resp *restful.Response) {
namespace := req.PathParameter("namespace")
exist, err := workspaces.NamespaceExistCheck(namespace)
if errors.HandlerError(err, resp) {
return
}
resp.WriteAsJson(map[string]bool{"exist": exist})
}
func NamespaceDeleteHandler(req *restful.Request, resp *restful.Response) {
namespace := req.PathParameter("namespace")
workspace := req.PathParameter("name")
err := workspaces.DeleteNamespace(workspace, namespace)
if errors.HandlerError(err, resp) {
return
}
resp.WriteAsJson(errors.None)
}
func DevOpsProjectDeleteHandler(req *restful.Request, resp *restful.Response) {
devops := req.PathParameter("id")
workspace := req.PathParameter("name")
force := req.QueryParameter("force")
username := req.HeaderParameter(UserNameHeader)
err := workspaces.UnBindDevopsProject(workspace, devops)
if err != nil && force != "true" {
resp.WriteHeaderAndEntity(http.StatusInternalServerError, errors.New(errors.Internal, err.Error()))
return
}
err = workspaces.DeleteDevopsProject(username, devops)
if errors.HandlerError(err, resp) {
return
}
resp.WriteAsJson(errors.None)
}
func DevOpsProjectCreateHandler(req *restful.Request, resp *restful.Response) {
workspace := req.PathParameter("name")
username := req.HeaderParameter(UserNameHeader)
var devops workspaces.DevopsProject
err := req.ReadEntity(&devops)
if err != nil {
resp.WriteHeaderAndEntity(http.StatusBadRequest, errors.New(errors.InvalidArgument, err.Error()))
return
}
project, err := workspaces.CreateDevopsProject(username, workspace, devops)
if errors.HandlerError(err, resp) {
return
}
resp.WriteAsJson(project)
}
func NamespaceCreateHandler(req *restful.Request, resp *restful.Response) {
workspace := req.PathParameter("name")
username := req.HeaderParameter(UserNameHeader)
namespace := &v1.Namespace{}
err := req.ReadEntity(namespace)
if err != nil {
resp.WriteHeaderAndEntity(http.StatusBadRequest, errors.New(errors.InvalidArgument, err.Error()))
return
}
if namespace.Annotations == nil {
namespace.Annotations = make(map[string]string, 0)
}
namespace.Annotations["creator"] = username
namespace.Annotations["workspace"] = workspace
if namespace.Labels == nil {
namespace.Labels = make(map[string]string, 0)
}
namespace.Labels["kubesphere.io/workspace"] = workspace
namespace, err = workspaces.CreateNamespace(namespace)
if err != nil {
resp.WriteHeaderAndEntity(http.StatusBadRequest, errors.New(errors.InvalidArgument, err.Error()))
return
}
resp.WriteAsJson(namespace)
}
func DevOpsProjectHandler(req *restful.Request, resp *restful.Response) {
workspace := req.PathParameter("name")
username := req.PathParameter("username")
keyword := req.QueryParameter("keyword")
if username == "" {
username = req.HeaderParameter(UserNameHeader)
}
limit := 65535
offset := 0
orderBy := "createTime"
reverse := true
if groups := regexp.MustCompile(`^limit=(\d+),page=(\d+)$`).FindStringSubmatch(req.QueryParameter("paging")); len(groups) == 3 {
limit, _ = strconv.Atoi(groups[1])
page, _ := strconv.Atoi(groups[2])
offset = (page - 1) * limit
}
if groups := regexp.MustCompile(`^(createTime|name)$`).FindStringSubmatch(req.QueryParameter("order")); len(groups) == 2 {
orderBy = groups[1]
reverse = false
}
if q := req.QueryParameter("reverse"); q != "" {
b, err := strconv.ParseBool(q)
if err == nil {
reverse = b
}
}
total, devOpsProjects, err := workspaces.ListDevopsProjectsByUser(username, workspace, keyword, orderBy, reverse, limit, offset)
if errors.HandlerError(err, resp) {
return
}
result := models.PageableResponse{}
result.TotalCount = total
result.Items = make([]interface{}, 0)
for _, n := range devOpsProjects {
result.Items = append(result.Items, n)
}
resp.WriteAsJson(result)
}
func WorkspaceCreateHandler(req *restful.Request, resp *restful.Response) {
var workspace workspaces.Workspace
username := req.HeaderParameter(UserNameHeader)
err := req.ReadEntity(&workspace)
if err != nil {
resp.WriteHeaderAndEntity(http.StatusBadRequest, errors.New(errors.InvalidArgument, err.Error()))
return
}
if workspace.Name == "" || strings.Contains(workspace.Name, ":") {
resp.WriteHeaderAndEntity(http.StatusBadRequest, errors.New(errors.InvalidArgument, "invalid workspace name"))
return
}
workspace.Path = workspace.Name
workspace.Members = nil
if workspace.Admin != "" {
workspace.Creator = workspace.Admin
} else {
workspace.Creator = username
}
created, err := workspaces.Create(&workspace)
if errors.HandlerError(err, resp) {
return
}
resp.WriteAsJson(created)
}
func DeleteWorkspaceHandler(req *restful.Request, resp *restful.Response) {
name := req.PathParameter("name")
if name == "" || strings.Contains(name, ":") {
resp.WriteHeaderAndEntity(http.StatusBadRequest, errors.New(errors.InvalidArgument, "invalid workspace name"))
return
}
workspace, err := workspaces.Detail(name)
if errors.HandlerError(err, resp) {
return
}
err = workspaces.Delete(workspace)
if errors.HandlerError(err, resp) {
return
}
resp.WriteAsJson(errors.None)
}
func WorkspaceEditHandler(req *restful.Request, resp *restful.Response) {
var workspace workspaces.Workspace
name := req.PathParameter("name")
err := req.ReadEntity(&workspace)
if err != nil {
resp.WriteHeaderAndEntity(http.StatusBadRequest, errors.New(errors.InvalidArgument, err.Error()))
return
}
if name != workspace.Name {
resp.WriteError(http.StatusBadRequest, fmt.Errorf("the name of workspace (%s) does not match the name on the URL (%s)", workspace.Name, name))
return
}
if workspace.Name == "" || strings.Contains(workspace.Name, ":") {
resp.WriteHeaderAndEntity(http.StatusBadRequest, errors.New(errors.InvalidArgument, "invalid workspace name"))
return
}
workspace.Path = workspace.Name
workspace.Members = nil
edited, err := workspaces.Edit(&workspace)
if errors.HandlerError(err, resp) {
return
}
resp.WriteAsJson(edited)
}
func WorkspaceDetailHandler(req *restful.Request, resp *restful.Response) {
name := req.PathParameter("name")
workspace, err := workspaces.Detail(name)
if errors.HandlerError(err, resp) {
return
}
resp.WriteAsJson(workspace)
}
// List all workspaces for the current user
func UserWorkspaceListHandler(req *restful.Request, resp *restful.Response) {
keyword := req.QueryParameter("keyword")
username := req.HeaderParameter(UserNameHeader)
ws, err := workspaces.ListWorkspaceByUser(username, keyword)
if errors.HandlerError(err, resp) {
return
}
sort.Slice(ws, func(i, j int) bool {
t1, err := ws[i].GetCreateTime()
if err != nil {
return false
}
t2, err := ws[j].GetCreateTime()
if err != nil {
return true
}
return t1.After(t2)
})
resp.WriteAsJson(ws)
}
func UserNamespaceListHandler(req *restful.Request, resp *restful.Response) {
withMetrics, err := strconv.ParseBool(req.QueryParameter("metrics"))
if err != nil {
withMetrics = false
}
username := req.PathParameter("username")
keyword := req.QueryParameter("keyword")
if username == "" {
username = req.HeaderParameter(UserNameHeader)
}
limit := 65535
offset := 0
orderBy := "createTime"
reverse := true
if groups := regexp.MustCompile(`^limit=(\d+),page=(\d+)$`).FindStringSubmatch(req.QueryParameter("paging")); len(groups) == 3 {
limit, _ = strconv.Atoi(groups[1])
page, _ := strconv.Atoi(groups[2])
if page < 0 {
page = 1
}
offset = (page - 1) * limit
}
if groups := regexp.MustCompile(`^(createTime|name)$`).FindStringSubmatch(req.QueryParameter("order")); len(groups) == 2 {
orderBy = groups[1]
reverse = false
}
if q := req.QueryParameter("reverse"); q != "" {
b, err := strconv.ParseBool(q)
if err == nil {
reverse = b
}
}
workspaceName := req.PathParameter("workspace")
total, namespaces, err := workspaces.ListNamespaceByUser(workspaceName, username, keyword, orderBy, reverse, limit, offset)
if withMetrics {
namespaces = metrics.GetNamespacesWithMetrics(namespaces)
}
if errors.HandlerError(err, resp) {
return
}
result := models.PageableResponse{}
result.TotalCount = total
result.Items = make([]interface{}, 0)
for _, n := range namespaces {
result.Items = append(result.Items, n)
}
resp.WriteAsJson(result)
}
/*
Copyright 2018 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 client
import (
"fmt"
_ "github.com/go-sql-driver/mysql"
"github.com/golang/glog"
"github.com/jinzhu/gorm"
)
var dbClient *gorm.DB
func NewDBClient() *gorm.DB {
conn := fmt.Sprintf("%s:%s@tcp(%s)/%s?charset=utf8mb4&parseTime=True&loc=Local", "", "", "", "")
db, err := gorm.Open("mysql", conn)
if err != nil {
glog.Error(err)
panic(err)
}
return db
}
func NewSharedDBClient() *gorm.DB {
if dbClient != nil {
err := dbClient.DB().Ping()
if err == nil {
return dbClient
} else {
glog.Error(err)
panic(err)
}
}
return NewDBClient()
}
/*
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 client
import (
"fmt"
"os"
"sync"
"github.com/mitchellh/go-homedir"
"github.com/golang/glog"
"k8s.io/client-go/kubernetes"
"k8s.io/client-go/rest"
"k8s.io/client-go/tools/clientcmd"
)
var (
KubeConfigFile string
k8sClient *kubernetes.Clientset
k8sClientOnce sync.Once
KubeConfig *rest.Config
)
func K8sClient() *kubernetes.Clientset {
k8sClientOnce.Do(func() {
config, err := getKubeConfig()
if err != nil {
glog.Fatalf("cannot load kubeconfig: %v", err)
}
k8sClient, err = kubernetes.NewForConfig(config)
if err != nil {
glog.Fatalf("cannot create k8s client: %v", err)
}
KubeConfig = config
})
return k8sClient
}
func getKubeConfig() (kubeConfig *rest.Config, err error) {
if KubeConfigFile == "" {
if env := os.Getenv("KUBECONFIG"); env != "" {
KubeConfigFile = env
} else {
if home, err := homedir.Dir(); err == nil {
KubeConfigFile = fmt.Sprintf("%s/.kube/config", home)
}
}
}
if KubeConfigFile != "" {
kubeConfig, err = clientcmd.BuildConfigFromFlags("", KubeConfigFile)
if err != nil {
return nil, err
}
} else {
kubeConfig, err = rest.InClusterConfig()
if err != nil {
return nil, err
}
}
kubeConfig.QPS = 1e6
kubeConfig.Burst = 1e6
return kubeConfig, nil
}
/*
Copyright 2018 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 client
import (
"io/ioutil"
"net/http"
"net/url"
"strconv"
"strings"
"time"
"os"
"github.com/emicklei/go-restful"
"github.com/golang/glog"
)
const (
DefaultScheme = "http"
DefaultPrometheusPort = "9090"
PrometheusApiPath = "/api/v1/"
DefaultQueryStep = "10m"
DefaultQueryTimeout = "10s"
RangeQueryType = "query_range?"
DefaultQueryType = "query?"
PrometheusAPIServerEnv = "PROMETHEUS_API_SERVER"
)
var PrometheusAPIServer = "prometheus-k8s.kubesphere-monitoring-system.svc"
var PrometheusEndpointUrl string
func init() {
if env := os.Getenv(PrometheusAPIServerEnv); env != "" {
PrometheusAPIServer = env
}
PrometheusEndpointUrl = DefaultScheme + "://" + PrometheusAPIServer + ":" + DefaultPrometheusPort + PrometheusApiPath
}
type MonitoringRequestParams struct {
Params url.Values
QueryType string
SortMetricName string
SortType string
PageNum string
LimitNum string
Tp string
MetricsFilter string
NodesFilter string
WsFilter string
NsFilter string
PodsFilter string
ContainersFilter string
MetricsName string
WorkloadName string
WlFilter string
NodeId string
WsName string
NsName string
PodName string
ContainerName string
WorkloadKind string
}
var client = &http.Client{}
func SendMonitoringRequest(queryType string, params string) string {
epurl := PrometheusEndpointUrl + queryType + params
response, err := client.Get(epurl)
if err != nil {
glog.Error(err)
} else {
defer response.Body.Close()
contents, err := ioutil.ReadAll(response.Body)
if err != nil {
glog.Error(err)
}
return string(contents)
}
return ""
}
func ParseMonitoringRequestParams(request *restful.Request) *MonitoringRequestParams {
instantTime := strings.Trim(request.QueryParameter("time"), " ")
start := strings.Trim(request.QueryParameter("start"), " ")
end := strings.Trim(request.QueryParameter("end"), " ")
step := strings.Trim(request.QueryParameter("step"), " ")
timeout := strings.Trim(request.QueryParameter("timeout"), " ")
sortMetricName := strings.Trim(request.QueryParameter("sort_metric"), " ")
sortType := strings.Trim(request.QueryParameter("sort_type"), " ")
pageNum := strings.Trim(request.QueryParameter("page"), " ")
limitNum := strings.Trim(request.QueryParameter("limit"), " ")
tp := strings.Trim(request.QueryParameter("type"), " ")
metricsFilter := strings.Trim(request.QueryParameter("metrics_filter"), " ")
nodesFilter := strings.Trim(request.QueryParameter("nodes_filter"), " ")
wsFilter := strings.Trim(request.QueryParameter("workspaces_filter"), " ")
nsFilter := strings.Trim(request.QueryParameter("namespaces_filter"), " ")
wlFilter := strings.Trim(request.QueryParameter("workloads_filter"), " ")
podsFilter := strings.Trim(request.QueryParameter("pods_filter"), " ")
containersFilter := strings.Trim(request.QueryParameter("containers_filter"), " ")
metricsName := strings.Trim(request.QueryParameter("metrics_name"), " ")
workloadName := strings.Trim(request.QueryParameter("workload_name"), " ")
nodeId := strings.Trim(request.PathParameter("node_id"), " ")
wsName := strings.Trim(request.PathParameter("workspace_name"), " ")
nsName := strings.Trim(request.PathParameter("ns_name"), " ")
podName := strings.Trim(request.PathParameter("pod_name"), " ")
containerName := strings.Trim(request.PathParameter("container_name"), " ")
workloadKind := strings.Trim(request.PathParameter("workload_kind"), " ")
var requestParams = MonitoringRequestParams{
SortMetricName: sortMetricName,
SortType: sortType,
PageNum: pageNum,
LimitNum: limitNum,
Tp: tp,
MetricsFilter: metricsFilter,
NodesFilter: nodesFilter,
WsFilter: wsFilter,
NsFilter: nsFilter,
PodsFilter: podsFilter,
ContainersFilter: containersFilter,
MetricsName: metricsName,
WorkloadName: workloadName,
WlFilter: wlFilter,
NodeId: nodeId,
WsName: wsName,
NsName: nsName,
PodName: podName,
ContainerName: containerName,
WorkloadKind: workloadKind,
}
if timeout == "" {
timeout = DefaultQueryTimeout
}
if step == "" {
step = DefaultQueryStep
}
// Whether query or query_range request
u := url.Values{}
if start != "" && end != "" {
u.Set("start", convertTimeGranularity(start))
u.Set("end", convertTimeGranularity(end))
u.Set("step", step)
u.Set("timeout", timeout)
requestParams.QueryType = RangeQueryType
requestParams.Params = u
return &requestParams
}
if instantTime != "" {
u.Set("time", instantTime)
u.Set("timeout", timeout)
requestParams.QueryType = DefaultQueryType
requestParams.Params = u
return &requestParams
} else {
//u.Set("time", strconv.FormatInt(int64(time.Now().Unix()), 10))
u.Set("timeout", timeout)
requestParams.QueryType = DefaultQueryType
requestParams.Params = u
return &requestParams
}
}
func convertTimeGranularity(ts string) string {
timeFloat, err := strconv.ParseFloat(ts, 64)
if err != nil {
glog.Errorf("convert second timestamp %s to minute timestamp failed", ts)
return strconv.FormatInt(int64(time.Now().Unix()), 10)
}
timeInt := int64(timeFloat)
// convert second timestamp to minute timestamp
secondTime := time.Unix(timeInt, 0).Truncate(time.Minute).Unix()
return strconv.FormatInt(secondTime, 10)
}
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
package errors
import "testing"
func TestCode_String(t *testing.T) {
t.Log(Code(1).String())
}
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册