Merge pull request #11017 from swordqiu/automated-cherry-pick-of-#11016-upstream-release-3.7

Automated cherry pick of #11016: fix: init cloud shell by apigateway
This commit is contained in:
Zexi Li
2021-05-10 12:02:45 +08:00
committed by GitHub
11 changed files with 152 additions and 25 deletions
+3
View File
@@ -0,0 +1,3 @@
echo "Welcome to Cloud Shell :-) You may execute climc and other command tools in this shell."
echo "Please exec 'climc' to get started"
echo ""
+3 -1
View File
@@ -1,5 +1,7 @@
FROM registry.cn-beijing.aliyuncs.com/yunionio/climc-base:20200820
FROM registry.cn-beijing.aliyuncs.com/yunionio/climc-base:20210508
ADD ./build/climc/root/opt /opt
ADD ./build/climc/root/root /root
ADD ./_output/alpine-build/bin/climc ./_output/alpine-build/bin/*cli /opt/yunion/bin/
+3 -1
View File
@@ -6,7 +6,9 @@ ENV TZ Asia/Shanghai
RUN mkdir -p /opt/yunion/bin
RUN apk add --no-cache bash bash-completion tzdata ca-certificates vim && \
RUN echo http://dl-cdn.alpinelinux.org/alpine/edge/testing >>/etc/apk/repositories
RUN apk add --no-cache bash bash-completion tzdata ca-certificates vim ipmitool kubectl && \
rm -rf /var/cache/apk/*
RUN cp /usr/share/zoneinfo/Asia/Shanghai /etc/localtime
+4
View File
@@ -1,3 +1,7 @@
debian10-base:
docker buildx build --platform linux/arm64,linux/amd64 --push \
-t registry.cn-beijing.aliyuncs.com/yunionio/debian10-base:1.0 -f ./Dockerfile.debian-base .
climc-base:
docker buildx build --platform linux/arm64,linux/amd64 --push \
-t registry.cn-beijing.aliyuncs.com/yunionio/climc-base:$(VERSION) -f ./Dockerfile.climc-base .
+6 -6
View File
@@ -24,7 +24,7 @@ import (
webconsole_api "yunion.io/x/onecloud/pkg/apis/webconsole"
"yunion.io/x/onecloud/pkg/mcclient"
"yunion.io/x/onecloud/pkg/mcclient/modules"
"yunion.io/x/onecloud/pkg/mcclient/modules/webconsole"
o "yunion.io/x/onecloud/pkg/mcclient/options"
"yunion.io/x/onecloud/pkg/webconsole/command"
)
@@ -70,7 +70,7 @@ func init() {
if err != nil {
return err
}
ret, err := modules.WebConsole.DoK8sShellConnect(s, args.NAME, params)
ret, err := webconsole.WebConsole.DoK8sShellConnect(s, args.NAME, params)
if err != nil {
return err
}
@@ -83,7 +83,7 @@ func init() {
if err != nil {
return err
}
ret, err := modules.WebConsole.DoK8sLogConnect(s, args.NAME, params)
ret, err := webconsole.WebConsole.DoK8sLogConnect(s, args.NAME, params)
if err != nil {
return err
}
@@ -92,7 +92,7 @@ func init() {
})
R(&o.WebConsoleBaremetalOptions{}, "webconsole-baremetal", "Connect baremetal host webconsole", func(s *mcclient.ClientSession, args *o.WebConsoleBaremetalOptions) error {
ret, err := modules.WebConsole.DoBaremetalConnect(s, args.ID, nil)
ret, err := webconsole.WebConsole.DoBaremetalConnect(s, args.ID, nil)
if err != nil {
return err
}
@@ -105,7 +105,7 @@ func init() {
if err != nil {
return err
}
ret, err := modules.WebConsole.DoSshConnect(s, args.IP, params)
ret, err := webconsole.WebConsole.DoSshConnect(s, args.IP, params)
if err != nil {
return err
}
@@ -114,7 +114,7 @@ func init() {
})
R(&o.WebConsoleServerOptions{}, "webconsole-server", "Connect server remote graphic console", func(s *mcclient.ClientSession, args *o.WebConsoleServerOptions) error {
ret, err := modules.WebConsole.DoServerConnect(s, args.ID, nil)
ret, err := webconsole.WebConsole.DoServerConnect(s, args.ID, nil)
if err != nil {
return err
}
+1
View File
@@ -22,6 +22,7 @@ import (
"yunion.io/x/onecloud/pkg/mcclient/modules/k8s"
_ "yunion.io/x/onecloud/pkg/mcclient/modules/monitor"
_ "yunion.io/x/onecloud/pkg/mcclient/modules/notify"
_ "yunion.io/x/onecloud/pkg/mcclient/modules/webconsole"
_ "yunion.io/x/onecloud/pkg/mcclient/modules/yunionconf"
)
+28
View File
@@ -0,0 +1,28 @@
// Copyright 2019 Yunion
//
// 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 webconsole
type SK8sRequest struct {
Cluster string `json:"cluster"`
Namespace string `json:"namespace"`
Container string `json:"container"`
}
type SK8sShellRequest struct {
SK8sRequest
Command string `json:"command"`
Env map[string]string `json:"env"`
}
+1
View File
@@ -0,0 +1 @@
package webconsole // import "yunion.io/x/onecloud/pkg/mcclient/modules/webconsole"
@@ -12,15 +12,20 @@
// See the License for the specific language governing permissions and
// limitations under the License.
package modules
package webconsole
import (
"fmt"
"yunion.io/x/jsonutils"
"yunion.io/x/pkg/errors"
webconsole_api "yunion.io/x/onecloud/pkg/apis/webconsole"
"yunion.io/x/onecloud/pkg/httperrors"
"yunion.io/x/onecloud/pkg/mcclient"
"yunion.io/x/onecloud/pkg/mcclient/auth"
"yunion.io/x/onecloud/pkg/mcclient/modulebase"
"yunion.io/x/onecloud/pkg/mcclient/modules/k8s"
)
var (
@@ -30,7 +35,7 @@ var (
func init() {
WebConsole = WebConsoleManager{NewWebConsoleManager()}
register(&WebConsole)
modulebase.Register("v1", &WebConsole)
}
type WebConsoleManager struct {
@@ -64,6 +69,64 @@ func (m WebConsoleManager) DoK8sShellConnect(s *mcclient.ClientSession, id strin
return m.DoK8sConnect(s, id, "shell", params)
}
func (m WebConsoleManager) DoCloudShell(s *mcclient.ClientSession, _ jsonutils.JSONObject) (jsonutils.JSONObject, error) {
adminSession := auth.GetAdminSession(s.GetContext(), s.GetRegion(), "")
query := jsonutils.NewDict()
query.Add(jsonutils.JSONTrue, "system")
query.Add(jsonutils.NewString("system"), "scope")
query.Add(jsonutils.NewString("system-default"), "name")
clusters, err := k8s.KubeClusters.List(adminSession, query)
if err != nil {
return nil, errors.Wrap(err, "KubeClusters")
}
if len(clusters.Data) == 0 {
return nil, httperrors.NewNotFoundError("cluster system-default not found")
}
clusterId, _ := clusters.Data[0].GetString("id")
if len(clusterId) == 0 {
return nil, httperrors.NewNotFoundError("cluster system-default no id")
}
query = jsonutils.NewDict()
query.Add(jsonutils.NewString(clusterId), "cluster")
query.Add(jsonutils.NewString("onecloud"), "namespace")
query.Add(jsonutils.NewString("climc"), "search")
pods, err := k8s.Pods.List(adminSession, query)
if err != nil {
return nil, errors.Wrap(err, "Pods")
}
if len(pods.Data) == 0 {
return nil, httperrors.NewNotFoundError("pod climc not found")
}
podName, _ := pods.Data[0].GetString("name")
if len(podName) == 0 {
return nil, httperrors.NewNotFoundError("pod climc no name")
}
req := webconsole_api.SK8sShellRequest{}
req.Cluster = clusterId
req.Namespace = "onecloud"
req.Container = "climc"
req.Command = "/bin/bash"
req.Env = map[string]string{
"OS_AUTH_TOKEN": s.GetToken().GetTokenString(),
"OS_PROJECT_NAME": s.GetProjectName(),
"OS_PROJECT_DOMAIN": s.GetProjectDomain(),
"OS_AUTH_URL": "https://default-keystone:30500/v3",
"OS_ENDPOINT_TYPE": "internal",
"YUNION_USE_CACHED_TOKEN": "false",
"YUNION_INSECURE": "true",
"OS_USERNAME": "",
"OS_PASSWORD": "",
"OS_DOMAIN_NAME": "",
"OS_ACCESS_KEY": "",
"OS_SECRET_KEY": "",
"OS_TRY_TERM_WIDTH": "false",
}
return m.DoK8sConnect(s, podName, "shell", jsonutils.Marshal(req))
}
func (m WebConsoleManager) DoK8sLogConnect(s *mcclient.ClientSession, id string, params jsonutils.JSONObject) (jsonutils.JSONObject, error) {
return m.DoK8sConnect(s, id, "log", params)
}
+19 -1
View File
@@ -23,6 +23,7 @@ import (
"yunion.io/x/jsonutils"
"yunion.io/x/log"
webconsole_api "yunion.io/x/onecloud/pkg/apis/webconsole"
o "yunion.io/x/onecloud/pkg/webconsole/options"
)
@@ -114,12 +115,29 @@ func (c *KubectlExec) Command(cmd string, args ...string) *KubectlExec {
}
func NewPodBashCommand(env *K8sEnv) ICommand {
shellRequest := webconsole_api.SK8sShellRequest{}
err := env.Data.Unmarshal(&shellRequest)
if err != nil {
log.Errorf("env.Data.Unmarshal SK8sShellRequest: %s", err)
}
if shellRequest.Command == "" {
shellRequest.Command = "sh"
}
args := make([]string, 0)
if len(shellRequest.Env) > 0 {
for k, v := range shellRequest.Env {
args = append(args, fmt.Sprintf("%s=%s", k, v))
}
args = append(args, shellRequest.Command)
shellRequest.Command = "env"
}
return NewKubectlCommand(env.Kubeconfig, env.Namespace).Exec().
Stdin().
TTY().
Pod(env.Pod).
Container(env.Container).
Command("sh")
Command(shellRequest.Command, args...)
}
type KubectlLog struct {
+19 -14
View File
@@ -23,6 +23,7 @@ import (
"net/url"
"yunion.io/x/jsonutils"
"yunion.io/x/pkg/errors"
webconsole_api "yunion.io/x/onecloud/pkg/apis/webconsole"
"yunion.io/x/onecloud/pkg/appsrv"
@@ -54,21 +55,25 @@ func InitHandlers(app *appsrv.Application) {
func fetchK8sEnv(ctx context.Context, w http.ResponseWriter, r *http.Request) (*command.K8sEnv, error) {
params, _, body := appsrv.FetchEnv(ctx, w, r)
cluster, _ := body.GetString("cluster")
if cluster == "" {
cluster = "default"
k8sReq := webconsole_api.SK8sRequest{}
err := body.Unmarshal(&k8sReq)
if err != nil {
return nil, errors.Wrap(err, "body.Unmarshal SK8sRequest")
}
namespace, _ := body.GetString("namespace")
if namespace == "" {
namespace = "default"
if k8sReq.Cluster == "" {
k8sReq.Cluster = "default"
}
if k8sReq.Namespace == "" {
k8sReq.Namespace = "default"
}
podName := params["<podName>"]
container, _ := body.GetString("container")
adminSession := auth.GetAdminSession(ctx, o.Options.Region, "")
query := jsonutils.NewDict()
query.Add(jsonutils.NewString(namespace), "namespace")
query.Add(jsonutils.NewString(cluster), "cluster")
query.Add(jsonutils.NewString(k8sReq.Namespace), "namespace")
query.Add(jsonutils.NewString(k8sReq.Cluster), "cluster")
obj, err := k8s.Pods.Get(adminSession, podName, query)
if err != nil {
return nil, err
@@ -78,13 +83,13 @@ func fetchK8sEnv(ctx context.Context, w http.ResponseWriter, r *http.Request) (*
}
data := jsonutils.NewDict()
ret, err := k8s.KubeClusters.GetSpecific(adminSession, cluster, "kubeconfig", data)
ret, err := k8s.KubeClusters.GetSpecific(adminSession, k8sReq.Cluster, "kubeconfig", data)
if err != nil {
return nil, err
}
conf, err := ret.GetString("kubeconfig")
if err != nil {
return nil, httperrors.NewNotFoundError("Not found cluster %q kubeconfig", cluster)
return nil, httperrors.NewNotFoundError("Not found cluster %q kubeconfig", k8sReq.Cluster)
}
f, err := ioutil.TempFile("", "kubeconfig-")
if err != nil {
@@ -94,10 +99,10 @@ func fetchK8sEnv(ctx context.Context, w http.ResponseWriter, r *http.Request) (*
f.WriteString(conf)
return &command.K8sEnv{
Cluster: cluster,
Namespace: namespace,
Cluster: k8sReq.Cluster,
Namespace: k8sReq.Namespace,
Pod: podName,
Container: container,
Container: k8sReq.Container,
Kubeconfig: f.Name(),
Data: body,
}, nil