mirror of
https://github.com/niusmallnan/steve.git
synced 2025-06-05 04:41:47 +00:00
119 lines
2.9 KiB
Go
119 lines
2.9 KiB
Go
package clusters
|
|
|
|
import (
|
|
"context"
|
|
"net/http"
|
|
"net/http/httputil"
|
|
"time"
|
|
|
|
"github.com/rancher/steve/pkg/podimpersonation"
|
|
"github.com/rancher/steve/pkg/stores/proxy"
|
|
"github.com/rancher/wrangler/pkg/schemas/validation"
|
|
v1 "k8s.io/api/core/v1"
|
|
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
|
"k8s.io/apiserver/pkg/authentication/user"
|
|
"k8s.io/apiserver/pkg/endpoints/request"
|
|
"k8s.io/client-go/kubernetes"
|
|
"k8s.io/client-go/kubernetes/scheme"
|
|
"k8s.io/client-go/rest"
|
|
)
|
|
|
|
type shell struct {
|
|
namespace string
|
|
impersonator *podimpersonation.PodImpersonation
|
|
cg proxy.ClientGetter
|
|
}
|
|
|
|
func (s *shell) ServeHTTP(rw http.ResponseWriter, req *http.Request) {
|
|
ctx, user, client, err := s.contextAndClient(req)
|
|
if err != nil {
|
|
http.Error(rw, err.Error(), http.StatusInternalServerError)
|
|
return
|
|
}
|
|
|
|
pod, err := s.impersonator.CreatePod(ctx, user, s.createPod(), &podimpersonation.PodOptions{
|
|
Wait: true,
|
|
})
|
|
if err != nil {
|
|
http.Error(rw, err.Error(), http.StatusInternalServerError)
|
|
return
|
|
}
|
|
|
|
s.proxyRequest(rw, req, pod, client)
|
|
}
|
|
|
|
func (s *shell) proxyRequest(rw http.ResponseWriter, req *http.Request, pod *v1.Pod, client kubernetes.Interface) {
|
|
attachURL := client.CoreV1().RESTClient().
|
|
Get().
|
|
Namespace(pod.Namespace).
|
|
Resource("pods").
|
|
Name(pod.Name).
|
|
SubResource("attach").
|
|
VersionedParams(&v1.PodAttachOptions{
|
|
Stdin: true,
|
|
Stdout: true,
|
|
Stderr: true,
|
|
TTY: true,
|
|
Container: "shell",
|
|
}, scheme.ParameterCodec).URL()
|
|
|
|
httpClient := client.CoreV1().RESTClient().(*rest.RESTClient).Client
|
|
p := httputil.ReverseProxy{
|
|
Director: func(req *http.Request) {
|
|
req.URL = attachURL
|
|
req.Host = attachURL.Host
|
|
delete(req.Header, "Authorization")
|
|
delete(req.Header, "Cookie")
|
|
},
|
|
Transport: httpClient.Transport,
|
|
FlushInterval: time.Millisecond * 100,
|
|
}
|
|
|
|
p.ServeHTTP(rw, req)
|
|
}
|
|
|
|
func (s *shell) contextAndClient(req *http.Request) (context.Context, user.Info, kubernetes.Interface, error) {
|
|
ctx := req.Context()
|
|
client, err := s.cg.AdminK8sInterface()
|
|
if err != nil {
|
|
return ctx, nil, nil, err
|
|
}
|
|
|
|
user, ok := request.UserFrom(ctx)
|
|
if !ok {
|
|
return ctx, nil, nil, validation.Unauthorized
|
|
}
|
|
|
|
return ctx, user, client, nil
|
|
}
|
|
|
|
func (s *shell) createPod() *v1.Pod {
|
|
return &v1.Pod{
|
|
ObjectMeta: metav1.ObjectMeta{
|
|
GenerateName: "dashboard-shell-",
|
|
Namespace: s.namespace,
|
|
},
|
|
Spec: v1.PodSpec{
|
|
TerminationGracePeriodSeconds: new(int64),
|
|
RestartPolicy: v1.RestartPolicyNever,
|
|
Containers: []v1.Container{
|
|
{
|
|
Name: "shell",
|
|
TTY: true,
|
|
Stdin: true,
|
|
StdinOnce: true,
|
|
Env: []v1.EnvVar{
|
|
{
|
|
Name: "KUBECONFIG",
|
|
Value: "/home/shell/.kube/config",
|
|
},
|
|
},
|
|
Image: "ibuildthecloud/shell:v0.0.1",
|
|
ImagePullPolicy: v1.PullIfNotPresent,
|
|
Command: []string{"bash"},
|
|
},
|
|
},
|
|
},
|
|
}
|
|
}
|