// PortForwardLocation returns the port-forward URL for a pod. func PortForwardLocation( getter ResourceGetter, connInfo client.ConnectionInfoGetter, ctx api.Context, name string, ) (*url.URL, http.RoundTripper, error) { pod, err := getPod(getter, ctx, name) if err != nil { return nil, nil, err } nodeName := types.NodeName(pod.Spec.NodeName) if len(nodeName) == 0 { // If pod has not been assigned a host, return an empty location return nil, nil, errors.NewBadRequest(fmt.Sprintf("pod %s does not have a host assigned", name)) } nodeInfo, err := connInfo.GetConnectionInfo(ctx, nodeName) if err != nil { return nil, nil, err } loc := &url.URL{ Scheme: nodeInfo.Scheme, Host: net.JoinHostPort(nodeInfo.Hostname, nodeInfo.Port), Path: fmt.Sprintf("/portForward/%s/%s", pod.Namespace, pod.Name), } return loc, nodeInfo.Transport, nil }
// ResourceLocation returns an URL and transport which one can use to send traffic for the specified node. func ResourceLocation(getter ResourceGetter, connection client.ConnectionInfoGetter, proxyTransport http.RoundTripper, ctx api.Context, id string) (*url.URL, http.RoundTripper, error) { schemeReq, name, portReq, valid := utilnet.SplitSchemeNamePort(id) if !valid { return nil, nil, errors.NewBadRequest(fmt.Sprintf("invalid node request %q", id)) } info, err := connection.GetConnectionInfo(ctx, types.NodeName(name)) if err != nil { return nil, nil, err } // We check if we want to get a default Kubelet's transport. It happens if either: // - no port is specified in request (Kubelet's port is default) // - the requested port matches the kubelet port for this node if portReq == "" || portReq == info.Port { return &url.URL{ Scheme: info.Scheme, Host: net.JoinHostPort(info.Hostname, info.Port), }, info.Transport, nil } // Otherwise, return the requested scheme and port, and the proxy transport return &url.URL{Scheme: schemeReq, Host: net.JoinHostPort(info.Hostname, portReq)}, proxyTransport, nil }
func streamLocation( getter ResourceGetter, connInfo client.ConnectionInfoGetter, ctx api.Context, name string, opts runtime.Object, container, path string, ) (*url.URL, http.RoundTripper, error) { pod, err := getPod(getter, ctx, name) if err != nil { return nil, nil, err } // Try to figure out a container // If a container was provided, it must be valid if container == "" { switch len(pod.Spec.Containers) { case 1: container = pod.Spec.Containers[0].Name case 0: return nil, nil, errors.NewBadRequest(fmt.Sprintf("a container name must be specified for pod %s", name)) default: containerNames := getContainerNames(pod.Spec.Containers) initContainerNames := getContainerNames(pod.Spec.InitContainers) err := fmt.Sprintf("a container name must be specified for pod %s, choose one of: [%s]", name, containerNames) if len(initContainerNames) > 0 { err += fmt.Sprintf(" or one of the init containers: [%s]", initContainerNames) } return nil, nil, errors.NewBadRequest(err) } } else { if !podHasContainerWithName(pod, container) { return nil, nil, errors.NewBadRequest(fmt.Sprintf("container %s is not valid for pod %s", container, name)) } } nodeName := types.NodeName(pod.Spec.NodeName) if len(nodeName) == 0 { // If pod has not been assigned a host, return an empty location return nil, nil, errors.NewBadRequest(fmt.Sprintf("pod %s does not have a host assigned", name)) } nodeInfo, err := connInfo.GetConnectionInfo(ctx, nodeName) if err != nil { return nil, nil, err } params := url.Values{} if err := streamParams(params, opts); err != nil { return nil, nil, err } loc := &url.URL{ Scheme: nodeInfo.Scheme, Host: net.JoinHostPort(nodeInfo.Hostname, nodeInfo.Port), Path: fmt.Sprintf("/%s/%s/%s/%s", path, pod.Namespace, pod.Name, container), RawQuery: params.Encode(), } return loc, nodeInfo.Transport, nil }
func streamLocation( getter ResourceGetter, connInfo client.ConnectionInfoGetter, ctx api.Context, name string, opts runtime.Object, container, path string, ) (*url.URL, http.RoundTripper, error) { pod, err := getPod(getter, ctx, name) if err != nil { return nil, nil, err } // Try to figure out a container // If a container was provided, it must be valid if container == "" { if len(pod.Spec.Containers) == 1 { container = pod.Spec.Containers[0].Name } else { return nil, nil, errors.NewBadRequest(fmt.Sprintf("a container name must be specified for pod %s", name)) } } else { if !podHasContainerWithName(pod, container) { return nil, nil, errors.NewBadRequest(fmt.Sprintf("container %s is not valid for pod %s", container, name)) } } nodeHost := pod.Spec.NodeName if len(nodeHost) == 0 { // If pod has not been assigned a host, return an empty location return nil, nil, errors.NewBadRequest(fmt.Sprintf("pod %s does not have a host assigned", name)) } nodeScheme, nodePort, nodeTransport, err := connInfo.GetConnectionInfo(ctx, nodeHost) if err != nil { return nil, nil, err } params := url.Values{} if err := streamParams(params, opts); err != nil { return nil, nil, err } loc := &url.URL{ Scheme: nodeScheme, Host: fmt.Sprintf("%s:%d", nodeHost, nodePort), Path: fmt.Sprintf("/%s/%s/%s/%s", path, pod.Namespace, pod.Name, container), RawQuery: params.Encode(), } return loc, nodeTransport, nil }
// ResourceLocation returns an URL and transport which one can use to send traffic for the specified node. func ResourceLocation(getter ResourceGetter, connection client.ConnectionInfoGetter, proxyTransport http.RoundTripper, ctx api.Context, id string) (*url.URL, http.RoundTripper, error) { schemeReq, name, portReq, valid := utilnet.SplitSchemeNamePort(id) if !valid { return nil, nil, errors.NewBadRequest(fmt.Sprintf("invalid node request %q", id)) } nodeObj, err := getter.Get(ctx, name) if err != nil { return nil, nil, err } node := nodeObj.(*api.Node) hostIP, err := nodeutil.GetNodeHostIP(node) if err != nil { return nil, nil, err } host := hostIP.String() // We check if we want to get a default Kubelet's transport. It happens if either: // - no port is specified in request (Kubelet's port is default), // - we're using Port stored as a DaemonEndpoint and requested port is a Kubelet's port stored in the DaemonEndpoint, // - there's no information in the API about DaemonEnpoint (legacy cluster) and requested port is equal to ports.KubeletPort (cluster-wide config) kubeletPort := node.Status.DaemonEndpoints.KubeletEndpoint.Port if kubeletPort == 0 { kubeletPort = ports.KubeletPort } if portReq == "" || strconv.Itoa(int(kubeletPort)) == portReq { scheme, port, kubeletTransport, err := connection.GetConnectionInfo(ctx, node.Name) if err != nil { return nil, nil, err } return &url.URL{ Scheme: scheme, Host: net.JoinHostPort( host, strconv.FormatUint(uint64(port), 10), ), }, kubeletTransport, nil } return &url.URL{Scheme: schemeReq, Host: net.JoinHostPort(host, portReq)}, proxyTransport, nil }
// LogLocation returns the log URL for a pod container. If opts.Container is blank // and only one container is present in the pod, that container is used. func LogLocation( getter ResourceGetter, connInfo client.ConnectionInfoGetter, ctx api.Context, name string, opts *api.PodLogOptions, ) (*url.URL, http.RoundTripper, error) { pod, err := getPod(getter, ctx, name) if err != nil { return nil, nil, err } // Try to figure out a container // If a container was provided, it must be valid container := opts.Container if len(container) == 0 { switch len(pod.Spec.Containers) { case 1: container = pod.Spec.Containers[0].Name case 0: return nil, nil, errors.NewBadRequest(fmt.Sprintf("a container name must be specified for pod %s", name)) default: containerNames := getContainerNames(pod.Spec.Containers) initContainerNames := getContainerNames(pod.Spec.InitContainers) err := fmt.Sprintf("a container name must be specified for pod %s, choose one of: [%s]", name, containerNames) if len(initContainerNames) > 0 { err += fmt.Sprintf(" or one of the init containers: [%s]", initContainerNames) } return nil, nil, errors.NewBadRequest(err) } } else { if !podHasContainerWithName(pod, container) { return nil, nil, errors.NewBadRequest(fmt.Sprintf("container %s is not valid for pod %s", container, name)) } } nodeName := types.NodeName(pod.Spec.NodeName) if len(nodeName) == 0 { // If pod has not been assigned a host, return an empty location return nil, nil, nil } nodeInfo, err := connInfo.GetConnectionInfo(ctx, nodeName) if err != nil { return nil, nil, err } params := url.Values{} if opts.Follow { params.Add("follow", "true") } if opts.Previous { params.Add("previous", "true") } if opts.Timestamps { params.Add("timestamps", "true") } if opts.SinceSeconds != nil { params.Add("sinceSeconds", strconv.FormatInt(*opts.SinceSeconds, 10)) } if opts.SinceTime != nil { params.Add("sinceTime", opts.SinceTime.Format(time.RFC3339)) } if opts.TailLines != nil { params.Add("tailLines", strconv.FormatInt(*opts.TailLines, 10)) } if opts.LimitBytes != nil { params.Add("limitBytes", strconv.FormatInt(*opts.LimitBytes, 10)) } loc := &url.URL{ Scheme: nodeInfo.Scheme, Host: net.JoinHostPort(nodeInfo.Hostname, nodeInfo.Port), Path: fmt.Sprintf("/containerLogs/%s/%s/%s", pod.Namespace, pod.Name, container), RawQuery: params.Encode(), } return loc, nodeInfo.Transport, nil }