kubelet: wire checkpoint container support through
This adds the last pieces to wire through the container checkpoint support in the kubelet. Signed-off-by: Adrian Reber <areber@redhat.com>
This commit is contained in:
@@ -62,6 +62,7 @@ import (
|
||||
"k8s.io/component-base/logs"
|
||||
compbasemetrics "k8s.io/component-base/metrics"
|
||||
"k8s.io/component-base/metrics/legacyregistry"
|
||||
runtimeapi "k8s.io/cri-api/pkg/apis/runtime/v1"
|
||||
podresourcesapi "k8s.io/kubelet/pkg/apis/podresources/v1"
|
||||
podresourcesapiv1alpha1 "k8s.io/kubelet/pkg/apis/podresources/v1alpha1"
|
||||
"k8s.io/kubernetes/pkg/api/legacyscheme"
|
||||
@@ -224,6 +225,7 @@ type HostInterface interface {
|
||||
GetCachedMachineInfo() (*cadvisorapi.MachineInfo, error)
|
||||
GetRunningPods() ([]*v1.Pod, error)
|
||||
RunInContainer(name string, uid types.UID, container string, cmd []string) ([]byte, error)
|
||||
CheckpointContainer(podUID types.UID, podFullName, containerName string, options *runtimeapi.CheckpointContainerRequest) error
|
||||
GetKubeletContainerLogs(ctx context.Context, podFullName, containerName string, logOptions *v1.PodLogOptions, stdout, stderr io.Writer) error
|
||||
ServeLogs(w http.ResponseWriter, req *http.Request)
|
||||
ResyncInterval() time.Duration
|
||||
@@ -403,6 +405,17 @@ func (s *Server) InstallDefaultHandlers() {
|
||||
s.restfulCont.Handle(proberMetricsPath,
|
||||
compbasemetrics.HandlerFor(p, compbasemetrics.HandlerOpts{ErrorHandling: compbasemetrics.ContinueOnError}),
|
||||
)
|
||||
|
||||
// Only enable checkpoint API if the feature is enabled
|
||||
if utilfeature.DefaultFeatureGate.Enabled(features.ContainerCheckpoint) {
|
||||
s.addMetricsBucketMatcher("checkpoint")
|
||||
ws = &restful.WebService{}
|
||||
ws.Path("/checkpoint").Produces(restful.MIME_JSON)
|
||||
ws.Route(ws.POST("/{podNamespace}/{podID}/{containerName}").
|
||||
To(s.checkpoint).
|
||||
Operation("checkpoint"))
|
||||
s.restfulCont.Add(ws)
|
||||
}
|
||||
}
|
||||
|
||||
// InstallDebuggingHandlers registers the HTTP request patterns that serve logs or run commands/containers
|
||||
@@ -878,6 +891,83 @@ func (s *Server) getPortForward(request *restful.Request, response *restful.Resp
|
||||
proxyStream(response.ResponseWriter, request.Request, url)
|
||||
}
|
||||
|
||||
// checkpoint handles the checkpoint API request. It checks if the requested
|
||||
// podNamespace, pod and container actually exist and only then calls out
|
||||
// to the runtime to actually checkpoint the container.
|
||||
func (s *Server) checkpoint(request *restful.Request, response *restful.Response) {
|
||||
pod, ok := s.host.GetPodByName(request.PathParameter("podNamespace"), request.PathParameter("podID"))
|
||||
if !ok {
|
||||
response.WriteError(http.StatusNotFound, fmt.Errorf("pod does not exist"))
|
||||
return
|
||||
}
|
||||
|
||||
containerName := request.PathParameter("containerName")
|
||||
|
||||
found := false
|
||||
for _, container := range pod.Spec.Containers {
|
||||
if container.Name == containerName {
|
||||
found = true
|
||||
}
|
||||
}
|
||||
if !found {
|
||||
for _, container := range pod.Spec.InitContainers {
|
||||
if container.Name == containerName {
|
||||
found = true
|
||||
}
|
||||
}
|
||||
}
|
||||
if !found && utilfeature.DefaultFeatureGate.Enabled(features.EphemeralContainers) {
|
||||
for _, container := range pod.Spec.EphemeralContainers {
|
||||
if container.Name == containerName {
|
||||
found = true
|
||||
}
|
||||
}
|
||||
}
|
||||
if !found {
|
||||
response.WriteError(
|
||||
http.StatusNotFound,
|
||||
fmt.Errorf("container %v does not exist", containerName),
|
||||
)
|
||||
return
|
||||
}
|
||||
|
||||
options := &runtimeapi.CheckpointContainerRequest{}
|
||||
// Query parameter to select an optional timeout. Without the timeout parameter
|
||||
// the checkpoint command will use the default CRI timeout.
|
||||
timeouts := request.Request.URL.Query()["timeout"]
|
||||
if len(timeouts) > 0 {
|
||||
// If the user specified one or multiple values for timeouts we
|
||||
// are using the last available value.
|
||||
timeout, err := strconv.ParseInt(timeouts[len(timeouts)-1], 10, 64)
|
||||
if err != nil {
|
||||
response.WriteError(
|
||||
http.StatusNotFound,
|
||||
fmt.Errorf("cannot parse value of timeout parameter"),
|
||||
)
|
||||
return
|
||||
}
|
||||
options.Timeout = timeout
|
||||
}
|
||||
|
||||
if err := s.host.CheckpointContainer(pod.UID, kubecontainer.GetPodFullName(pod), containerName, options); err != nil {
|
||||
response.WriteError(
|
||||
http.StatusInternalServerError,
|
||||
fmt.Errorf(
|
||||
"checkpointing of %v/%v/%v failed (%v)",
|
||||
request.PathParameter("podNamespace"),
|
||||
request.PathParameter("podID"),
|
||||
containerName,
|
||||
err,
|
||||
),
|
||||
)
|
||||
return
|
||||
}
|
||||
writeJSONResponse(
|
||||
response,
|
||||
[]byte(fmt.Sprintf("{\"items\":[\"%s\"]}", options.Location)),
|
||||
)
|
||||
}
|
||||
|
||||
// getURLRootPath trims a URL path.
|
||||
// For paths in the format of "/metrics/xxx", "metrics/xxx" is returned;
|
||||
// For all other paths, the first part of the path is returned.
|
||||
|
Reference in New Issue
Block a user