| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707 |
- // 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 guestdrivers
- import (
- "context"
- "fmt"
- "net/http"
- "net/url"
- "k8s.io/apimachinery/pkg/util/proxy"
- "yunion.io/x/cloudmux/pkg/cloudprovider"
- "yunion.io/x/jsonutils"
- "yunion.io/x/log"
- "yunion.io/x/pkg/errors"
- "yunion.io/x/pkg/util/httputils"
- "yunion.io/x/pkg/util/rbacscope"
- "yunion.io/x/pkg/util/sets"
- "yunion.io/x/onecloud/pkg/apis"
- api "yunion.io/x/onecloud/pkg/apis/compute"
- hostapi "yunion.io/x/onecloud/pkg/apis/host"
- "yunion.io/x/onecloud/pkg/apis/image"
- "yunion.io/x/onecloud/pkg/appsrv"
- "yunion.io/x/onecloud/pkg/cloudcommon/db"
- "yunion.io/x/onecloud/pkg/cloudcommon/db/quotas"
- "yunion.io/x/onecloud/pkg/cloudcommon/db/taskman"
- "yunion.io/x/onecloud/pkg/compute/models"
- "yunion.io/x/onecloud/pkg/compute/options"
- "yunion.io/x/onecloud/pkg/compute/utils"
- "yunion.io/x/onecloud/pkg/httperrors"
- "yunion.io/x/onecloud/pkg/mcclient"
- "yunion.io/x/onecloud/pkg/util/pod/remotecommand/spdy"
- )
- var _ models.IPodDriver = new(SPodDriver)
- type SPodDriver struct {
- SKVMGuestDriver
- }
- func init() {
- driver := SPodDriver{}
- models.RegisterGuestDriver(&driver)
- }
- func (p *SPodDriver) newUnsupportOperationError(option string) error {
- return httperrors.NewUnsupportOperationError("Container not support %s", option)
- }
- func (p *SPodDriver) GetHypervisor() string {
- return api.HYPERVISOR_POD
- }
- func (p *SPodDriver) GetProvider() string {
- return api.CLOUD_PROVIDER_ONECLOUD
- }
- func (p *SPodDriver) ValidateCreateData(ctx context.Context, userCred mcclient.TokenCredential, input *api.ServerCreateInput) (*api.ServerCreateInput, error) {
- for i, d := range input.Disks {
- if d.Format != "" {
- if d.Format != image.IMAGE_DISK_FORMAT_RAW {
- return nil, httperrors.NewInputParameterError("not support format %s for disk %d", d.Format, i)
- }
- }
- }
- if input.Pod == nil {
- return nil, httperrors.NewNotEmptyError("pod data is empty")
- }
- if len(input.Pod.Containers) == 0 {
- return nil, httperrors.NewNotEmptyError("containers data is empty")
- }
- // validate port mappings
- /*if err := p.validatePortMappings(input.Pod); err != nil {
- return nil, errors.Wrap(err, "validate port mappings")
- }*/
- ctrNames := sets.NewString()
- volUniqNames := sets.NewString()
- for idx, ctr := range input.Pod.Containers {
- if err := p.validateContainerData(ctx, userCred, idx, input.Name, ctr, input); err != nil {
- return nil, errors.Wrapf(err, "data of %d container", idx)
- }
- if ctrNames.Has(ctr.Name) {
- return nil, httperrors.NewDuplicateNameError("same name %s of containers", ctr.Name)
- }
- ctrNames.Insert(ctr.Name)
- for volIdx := range ctr.VolumeMounts {
- vol := ctr.VolumeMounts[volIdx]
- if vol.UniqueName != "" {
- if volUniqNames.Has(vol.UniqueName) {
- return nil, httperrors.NewDuplicateNameError("same volume unique name %s", fmt.Sprintf("container %s volume_mount %d %s", ctr.Name, volIdx, vol.UniqueName))
- } else {
- volUniqNames.Insert(vol.UniqueName)
- }
- }
- }
- }
- err := utils.TopologicalSortContainers(
- input.Pod.Containers,
- func(ctr *api.PodContainerCreateInput) string { return ctr.Name },
- func(ctr *api.PodContainerCreateInput) []string { return ctr.DependsOn },
- )
- if err != nil {
- return nil, errors.Wrap(err, "invalid container dependency")
- }
- return input, nil
- }
- /*func (p *SPodDriver) validatePortMappings(input *api.PodCreateInput) error {
- usedPorts := make(map[api.PodPortMappingProtocol]sets.Int)
- for idx, pm := range input.PortMappings {
- ports, ok := usedPorts[pm.Protocol]
- if !ok {
- ports = sets.NewInt()
- }
- if pm.HostPort != nil {
- if ports.Has(*pm.HostPort) {
- return httperrors.NewInputParameterError("%s host_port %d is already specified", pm.Protocol, *pm.HostPort)
- }
- ports.Insert(*pm.HostPort)
- }
- usedPorts[pm.Protocol] = ports
- if err := p.validatePortMapping(pm); err != nil {
- return errors.Wrapf(err, "validate portmapping %d", idx)
- }
- }
- return nil
- }*/
- func (p *SPodDriver) validateHostPortMapping(hostId string, pm *api.PodPortMapping) error {
- // TODO:
- return nil
- }
- func (p *SPodDriver) validateContainerData(ctx context.Context, userCred mcclient.TokenCredential, idx int, defaultNamePrefix string, ctr *api.PodContainerCreateInput, input *api.ServerCreateInput) error {
- if ctr.Name == "" {
- ctr.Name = fmt.Sprintf("%s-%d", defaultNamePrefix, idx)
- }
- if err := models.GetContainerManager().ValidateSpec(ctx, userCred, &ctr.ContainerSpec, nil, nil); err != nil {
- return errors.Wrap(err, "validate container spec")
- }
- if err := p.validateContainerVolumeMounts(ctx, userCred, ctr, input); err != nil {
- return errors.Wrap(err, "validate container volumes")
- }
- return nil
- }
- func (p *SPodDriver) validateContainerVolumeMounts(ctx context.Context, userCred mcclient.TokenCredential, ctr *api.PodContainerCreateInput, input *api.ServerCreateInput) error {
- for idx, vm := range ctr.VolumeMounts {
- if err := p.validateContainerVolumeMount(ctx, userCred, vm, input); err != nil {
- return errors.Wrapf(err, "validate volume mount %d", idx)
- }
- }
- return nil
- }
- func (p *SPodDriver) validateContainerVolumeMount(ctx context.Context, userCred mcclient.TokenCredential, vm *apis.ContainerVolumeMount, input *api.ServerCreateInput) error {
- if vm.Type == "" {
- return httperrors.NewNotEmptyError("type is required")
- }
- if vm.MountPath == "" {
- return httperrors.NewNotEmptyError("mount_path is required")
- }
- drv, err := models.GetContainerVolumeMountDriverWithError(vm.Type)
- if err != nil {
- return errors.Wrapf(err, "get container volume mount driver %s", vm.Type)
- }
- if err := drv.ValidatePodCreateData(ctx, userCred, vm, input); err != nil {
- return errors.Wrapf(err, "validate %s create data", vm.Type)
- }
- return nil
- }
- func (p *SPodDriver) validatePortRange(portRange *api.PodPortMappingPortRange) error {
- if portRange != nil {
- if portRange.Start > portRange.End {
- return httperrors.NewInputParameterError("port range start %d is large than %d", portRange.Start, portRange.End)
- }
- if portRange.Start <= api.POD_PORT_MAPPING_RANGE_START {
- return httperrors.NewInputParameterError("port range start %d <= %d", api.POD_PORT_MAPPING_RANGE_START, portRange.Start)
- }
- if portRange.End > api.POD_PORT_MAPPING_RANGE_END {
- return httperrors.NewInputParameterError("port range end %d > %d", api.POD_PORT_MAPPING_RANGE_END, portRange.End)
- }
- }
- return nil
- }
- func (p *SPodDriver) validatePort(port int, start int, end int) error {
- if port < start || port > end {
- return httperrors.NewInputParameterError("port number %d isn't within %d to %d", port, start, end)
- }
- return nil
- }
- func (p *SPodDriver) validatePortMapping(pm *api.PodPortMapping) error {
- if err := p.validatePortRange(pm.HostPortRange); err != nil {
- return err
- }
- if pm.HostPort != nil {
- if err := p.validatePort(*pm.HostPort, api.POD_PORT_MAPPING_RANGE_START, api.POD_PORT_MAPPING_RANGE_END); err != nil {
- return errors.Wrap(err, "validate host_port")
- }
- }
- if err := p.validatePort(pm.ContainerPort, 1, 65535); err != nil {
- return errors.Wrap(err, "validate container_port")
- }
- if pm.Protocol == "" {
- pm.Protocol = api.PodPortMappingProtocolTCP
- }
- if !sets.NewString(api.PodPortMappingProtocolUDP, api.PodPortMappingProtocolTCP).Has(string(pm.Protocol)) {
- return httperrors.NewInputParameterError("unsupported protocol %s", pm.Protocol)
- }
- return nil
- }
- func (p *SPodDriver) GetInstanceCapability() cloudprovider.SInstanceCapability {
- return cloudprovider.SInstanceCapability{
- Hypervisor: p.GetHypervisor(),
- Provider: p.GetProvider(),
- }
- }
- // for backward compatibility, deprecated driver
- func (p *SPodDriver) GetComputeQuotaKeys(scope rbacscope.TRbacScope, ownerId mcclient.IIdentityProvider, brand string) models.SComputeResourceKeys {
- keys := models.SComputeResourceKeys{}
- keys.SBaseProjectQuotaKeys = quotas.OwnerIdProjectQuotaKeys(scope, ownerId)
- keys.CloudEnv = api.CLOUD_ENV_ON_PREMISE
- keys.Provider = api.CLOUD_PROVIDER_ONECLOUD
- keys.Brand = api.ONECLOUD_BRAND_ONECLOUD
- keys.Hypervisor = api.HYPERVISOR_POD
- return keys
- }
- func (p *SPodDriver) GetDefaultSysDiskBackend() string {
- return api.STORAGE_LOCAL
- }
- func (p *SPodDriver) GetMinimalSysDiskSizeGb() int {
- return options.Options.DefaultDiskSizeMB / 1024
- }
- func (p *SPodDriver) StartGuestCreateTask(guest *models.SGuest, ctx context.Context, userCred mcclient.TokenCredential, data *jsonutils.JSONDict, pendingUsage quotas.IQuota, parentTaskId string) error {
- task, err := taskman.TaskManager.NewTask(ctx, "PodCreateTask", guest, userCred, data, parentTaskId, "", pendingUsage)
- if err != nil {
- return errors.Wrap(err, "New PodCreateTask")
- }
- return task.ScheduleRun(nil)
- }
- func (p *SPodDriver) RequestGuestHotAddIso(ctx context.Context, guest *models.SGuest, path string, boot bool, task taskman.ITask) error {
- // do nothing, call next stage
- return task.ScheduleRun(nil)
- }
- func (p *SPodDriver) PerformStart(ctx context.Context, userCred mcclient.TokenCredential, guest *models.SGuest, data *jsonutils.JSONDict, parentTaskId string) error {
- guest.SetStatus(ctx, userCred, api.VM_START_START, "")
- task, err := taskman.TaskManager.NewTask(ctx, "PodStartTask", guest, userCred, nil, parentTaskId, "", nil)
- if err != nil {
- return errors.Wrap(err, "New PodStartTask")
- }
- return task.ScheduleRun(nil)
- }
- func (p *SPodDriver) RequestStartOnHost(ctx context.Context, guest *models.SGuest, host *models.SHost, userCred mcclient.TokenCredential, task taskman.ITask) error {
- header := p.getTaskRequestHeader(task)
- config := jsonutils.NewDict()
- drv, err := guest.GetDriver()
- if err != nil {
- return err
- }
- desc, err := drv.GetJsonDescAtHost(ctx, task.GetUserCred(), guest, host, nil)
- if err != nil {
- return errors.Wrapf(err, "GetJsonDescAtHost")
- }
- config.Add(desc, "desc")
- params := task.GetParams()
- if params.Length() > 0 {
- config.Add(params, "params")
- }
- url := fmt.Sprintf("%s/servers/%s/start", host.ManagerUri, guest.Id)
- _, body, err := httputils.JSONRequest(httputils.GetDefaultClient(), ctx, "POST", url, header, config, false)
- if err != nil {
- return err
- }
- resp := new(api.PodStartResponse)
- body.Unmarshal(resp)
- if resp.IsRunning {
- taskman.LocalTaskRun(task, func() (jsonutils.JSONObject, error) {
- return body, nil
- })
- }
- return nil
- }
- func (p *SPodDriver) RqeuestSuspendOnHost(ctx context.Context, guest *models.SGuest, task taskman.ITask) error {
- return p.newUnsupportOperationError("suspend")
- }
- func (p *SPodDriver) RequestSoftReset(ctx context.Context, guest *models.SGuest, task taskman.ITask) error {
- return p.newUnsupportOperationError("soft reset")
- }
- func (p *SPodDriver) GetGuestVncInfo(ctx context.Context, userCred mcclient.TokenCredential, guest *models.SGuest, host *models.SHost, input *cloudprovider.ServerVncInput) (*cloudprovider.ServerVncOutput, error) {
- return nil, p.newUnsupportOperationError("VNC")
- }
- func (p *SPodDriver) OnGuestDeployTaskDataReceived(ctx context.Context, guest *models.SGuest, task taskman.ITask, data jsonutils.JSONObject) error {
- //guest.SaveDeployInfo(ctx, task.GetUserCred(), data)
- // do nothing here
- return nil
- }
- func (p *SPodDriver) CanStop(guest *models.SGuest) error {
- if guest.PowerStates == api.VM_POWER_STATES_ON {
- return nil
- }
- return p.SKVMGuestDriver.CanStop(guest)
- }
- func (p *SPodDriver) StartGuestStopTask(guest *models.SGuest, ctx context.Context, userCred mcclient.TokenCredential, params *jsonutils.JSONDict, parentTaskId string) error {
- task, err := taskman.TaskManager.NewTask(ctx, "PodStopTask", guest, userCred, params, parentTaskId, "", nil)
- if err != nil {
- return errors.Wrap(err, "New PodStopTask")
- }
- return task.ScheduleRun(nil)
- }
- func (p *SPodDriver) StartGuestRestartTask(guest *models.SGuest, ctx context.Context, userCred mcclient.TokenCredential, isForce bool, parentTaskId string) error {
- data := jsonutils.NewDict()
- data.Set("is_force", jsonutils.NewBool(isForce))
- if err := guest.SetStatus(ctx, userCred, api.VM_STOPPING, ""); err != nil {
- return err
- }
- task, err := taskman.TaskManager.NewTask(ctx, "PodRestartTask", guest, userCred, nil, parentTaskId, "", nil)
- if err != nil {
- return err
- }
- task.ScheduleRun(nil)
- return nil
- }
- func (p *SPodDriver) StartDeleteGuestTask(ctx context.Context, userCred mcclient.TokenCredential, guest *models.SGuest, params *jsonutils.JSONDict, parentTaskId string) error {
- task, err := taskman.TaskManager.NewTask(ctx, "PodDeleteTask", guest, userCred, params, parentTaskId, "", nil)
- if err != nil {
- return errors.Wrap(err, "New PodDeleteTask")
- }
- return task.ScheduleRun(nil)
- }
- func (p *SPodDriver) StartGuestSyncstatusTask(guest *models.SGuest, ctx context.Context, userCred mcclient.TokenCredential, parentTaskId string) error {
- task, err := taskman.TaskManager.NewTask(ctx, "PodSyncstatusTask", guest, userCred, nil, parentTaskId, "", nil)
- if err != nil {
- return errors.Wrap(err, "New PodSyncstatusTask")
- }
- return task.ScheduleRun(nil)
- }
- func (p *SPodDriver) RequestUndeployGuestOnHost(ctx context.Context, guest *models.SGuest, host *models.SHost, task taskman.ITask) error {
- url := fmt.Sprintf("%s/servers/%s", host.ManagerUri, guest.Id)
- header := p.getTaskRequestHeader(task)
- _, _, err := httputils.JSONRequest(httputils.GetDefaultClient(), ctx, "DELETE", url, header, nil, false)
- return err
- }
- func (p *SPodDriver) GetJsonDescAtHost(ctx context.Context, userCred mcclient.TokenCredential, guest *models.SGuest, host *models.SHost, params *jsonutils.JSONDict) (jsonutils.JSONObject, error) {
- desc := guest.GetJsonDescAtHypervisor(ctx, host)
- ctrs, err := models.GetContainerManager().GetContainersByPod(guest.GetId())
- if err != nil {
- return nil, errors.Wrap(err, "GetContainersByPod")
- }
- ctrDescs := make([]*hostapi.ContainerDesc, len(ctrs))
- for idx, ctr := range ctrs {
- desc, err := ctr.GetJsonDescAtHost(ctx, userCred)
- if err != nil {
- return nil, errors.Wrapf(err, "GetJsonDescAtHost of container %s", ctr.GetId())
- }
- ctrDescs[idx] = desc
- }
- desc.Containers = ctrDescs
- return jsonutils.Marshal(desc), nil
- }
- func (p *SPodDriver) createContainersOnPod(ctx context.Context, userCred mcclient.TokenCredential, guest *models.SGuest) error {
- input, err := guest.GetCreateParams(ctx, userCred)
- if err != nil {
- return errors.Wrap(err, "GetCreateParams")
- }
- ctrs := make([]*models.SContainer, len(input.Pod.Containers))
- for idx, ctr := range input.Pod.Containers {
- if obj, err := models.GetContainerManager().CreateOnPod(ctx, userCred, guest.GetOwnerId(), guest, ctr); err != nil {
- return errors.Wrapf(err, "create container on pod: %s", guest.GetName())
- } else {
- ctrs[idx] = obj
- }
- }
- return nil
- }
- func (p *SPodDriver) RequestDeployGuestOnHost(ctx context.Context, guest *models.SGuest, host *models.SHost, task taskman.ITask) error {
- deployAction, err := task.GetParams().GetString("deploy_action")
- if err != nil {
- return errors.Wrapf(err, "get deploy_action from task params: %s", task.GetParams())
- }
- if deployAction == "create" {
- if err := p.createContainersOnPod(ctx, task.GetUserCred(), guest); err != nil {
- return errors.Wrap(err, "create containers on pod")
- }
- }
- config, err := guest.GetDeployConfigOnHost(ctx, task.GetUserCred(), host, task.GetParams())
- if err != nil {
- log.Errorf("GetDeployConfigOnHost error: %v", err)
- return err
- }
- action, err := config.GetString("action")
- if err != nil {
- return err
- }
- url := fmt.Sprintf("%s/servers/%s/%s", host.ManagerUri, guest.Id, action)
- header := p.getTaskRequestHeader(task)
- _, _, err = httputils.JSONRequest(httputils.GetDefaultClient(), ctx, "POST", url, header, config, false)
- return err
- }
- func (p *SPodDriver) performContainerAction(ctx context.Context, userCred mcclient.TokenCredential, task models.IContainerTask, action string, data jsonutils.JSONObject) error {
- pod := task.GetPod()
- ctr := task.GetContainer()
- host, _ := pod.GetHost()
- url := fmt.Sprintf("%s/pods/%s/containers/%s/%s", host.ManagerUri, pod.GetId(), ctr.GetId(), action)
- header := p.getTaskRequestHeader(task)
- _, _, err := httputils.JSONRequest(httputils.GetDefaultClient(), ctx, "POST", url, header, data, false)
- return err
- }
- func (p *SPodDriver) getContainerCreateInput(ctx context.Context, userCred mcclient.TokenCredential, ctr *models.SContainer) (*hostapi.ContainerCreateInput, error) {
- spec, err := ctr.ToHostContainerSpec(ctx, userCred)
- if err != nil {
- return nil, errors.Wrap(err, "ToHostContainerSpec")
- }
- input := &hostapi.ContainerCreateInput{
- Name: ctr.GetName(),
- GuestId: ctr.GuestId,
- Spec: spec,
- RestartCount: ctr.RestartCount,
- }
- return input, nil
- }
- func (p *SPodDriver) RequestCreateContainer(ctx context.Context, userCred mcclient.TokenCredential, task models.IContainerTask) error {
- ctr := task.GetContainer()
- input, err := p.getContainerCreateInput(ctx, userCred, ctr)
- if err != nil {
- return errors.Wrap(err, "getContainerCreateInput")
- }
- return p.performContainerAction(ctx, userCred, task, "create", jsonutils.Marshal(input))
- }
- func (p *SPodDriver) RequestStartContainer(ctx context.Context, userCred mcclient.TokenCredential, task models.IContainerTask) error {
- ctr := task.GetContainer()
- input, err := p.getContainerCreateInput(ctx, userCred, ctr)
- if err != nil {
- return errors.Wrap(err, "getContainerCreateInput")
- }
- return p.performContainerAction(ctx, userCred, task, "start", jsonutils.Marshal(input))
- }
- func (p *SPodDriver) RequestStopContainer(ctx context.Context, userCred mcclient.TokenCredential, task models.IContainerTask) error {
- ctr := task.GetContainer()
- params := task.GetParams()
- params.Add(jsonutils.NewString(ctr.GetName()), "container_name")
- params.Add(jsonutils.NewInt(int64(ctr.Spec.ShmSizeMB)), "shm_size_mb")
- return p.performContainerAction(ctx, userCred, task, "stop", task.GetParams())
- }
- func (p *SPodDriver) RequestDeleteContainer(ctx context.Context, userCred mcclient.TokenCredential, task models.IContainerTask) error {
- return p.performContainerAction(ctx, userCred, task, "delete", nil)
- }
- func (p *SPodDriver) RequestSyncContainerStatus(ctx context.Context, userCred mcclient.TokenCredential, task models.IContainerTask) error {
- return p.performContainerAction(ctx, userCred, task, "sync-status", nil)
- }
- func (p *SPodDriver) RequestPullContainerImage(ctx context.Context, userCred mcclient.TokenCredential, task models.IContainerTask) error {
- return p.performContainerAction(ctx, userCred, task, "pull-image", task.GetParams())
- }
- func (p *SPodDriver) RequestAddVolumeMountPostOverlay(ctx context.Context, userCred mcclient.TokenCredential, task models.IContainerTask) error {
- return p.performContainerAction(ctx, userCred, task, "add-volume-mount-post-overlay", task.GetParams())
- }
- func (p *SPodDriver) RequestRemoveVolumeMountPostOverlay(ctx context.Context, userCred mcclient.TokenCredential, task models.IContainerTask) error {
- return p.performContainerAction(ctx, userCred, task, "remove-volume-mount-post-overlay", task.GetParams())
- }
- type responder struct {
- errorMessage string
- }
- func (r *responder) Error(w http.ResponseWriter, req *http.Request, err error) {
- http.Error(w, err.Error(), http.StatusInternalServerError)
- }
- func (p *SPodDriver) RequestExecContainer(ctx context.Context, userCred mcclient.TokenCredential, ctr *models.SContainer, input *api.ContainerExecInput) error {
- pod := ctr.GetPod()
- host, _ := pod.GetHost()
- urlPath := fmt.Sprintf("%s/pods/%s/containers/%s/%s?%s", host.ManagerUri, pod.GetId(), ctr.GetId(), "exec", jsonutils.Marshal(input).QueryString())
- loc, _ := url.Parse(urlPath)
- tokenHeader := mcclient.GetTokenHeaders(userCred)
- trans, _, _ := spdy.RoundTripperFor()
- handler := proxy.NewUpgradeAwareHandler(loc, trans, false, true, new(responder))
- appParams := appsrv.AppContextGetParams(ctx)
- newHeader := appParams.Request.Header
- for key, vals := range tokenHeader {
- for _, val := range vals {
- newHeader.Add(key, val)
- }
- }
- appParams.Request.Header = newHeader
- appParams.Request.Method = "POST"
- handler.ServeHTTP(appParams.Response, appParams.Request)
- return nil
- }
- func (p *SPodDriver) requestContainerSyncAction(ctx context.Context, userCred mcclient.TokenCredential, container *models.SContainer, action string, input jsonutils.JSONObject) (jsonutils.JSONObject, error) {
- pod := container.GetPod()
- host, _ := pod.GetHost()
- url := fmt.Sprintf("%s/pods/%s/containers/%s/%s", host.ManagerUri, pod.GetId(), container.GetId(), action)
- header := mcclient.GetTokenHeaders(userCred)
- _, ret, err := httputils.JSONRequest(httputils.GetDefaultClient(), ctx, "POST", url, header, input, false)
- return ret, err
- }
- func (p *SPodDriver) RequestExecSyncContainer(ctx context.Context, userCred mcclient.TokenCredential, container *models.SContainer, input *api.ContainerExecSyncInput) (jsonutils.JSONObject, error) {
- return p.requestContainerSyncAction(ctx, userCred, container, "exec-sync", jsonutils.Marshal(input))
- }
- func (p *SPodDriver) RequestSetContainerResourcesLimit(ctx context.Context, userCred mcclient.TokenCredential, container *models.SContainer, limit *apis.ContainerResources) (jsonutils.JSONObject, error) {
- return p.requestContainerSyncAction(ctx, userCred, container, "set-resources-limit", jsonutils.Marshal(limit))
- }
- func (p *SPodDriver) OnDeleteGuestFinalCleanup(ctx context.Context, guest *models.SGuest, userCred mcclient.TokenCredential) error {
- // clean disk records in DB
- return guest.DeleteAllDisksInDB(ctx, userCred)
- }
- func (p *SPodDriver) RequestRebuildRootDisk(ctx context.Context, guest *models.SGuest, task taskman.ITask) error {
- // do nothing, call next stage
- return p.newUnsupportOperationError("rebuild root")
- }
- func (p *SPodDriver) GetRandomNetworkTypes() []api.TNetworkType {
- return []api.TNetworkType{api.NETWORK_TYPE_CONTAINER, api.NETWORK_TYPE_GUEST, api.NETWORK_TYPE_HOSTLOCAL}
- }
- func (p *SPodDriver) IsSupportGuestClone() bool {
- return false
- }
- func (p *SPodDriver) IsSupportCdrom(guest *models.SGuest) (bool, error) {
- return false, nil
- }
- func (p *SPodDriver) IsSupportFloppy(guest *models.SGuest) (bool, error) {
- return false, nil
- }
- func (p *SPodDriver) GetChangeInstanceTypeStatus() ([]string, error) {
- return []string{api.VM_READY}, nil
- }
- func (p *SPodDriver) RequestSaveVolumeMountImage(ctx context.Context, userCred mcclient.TokenCredential, task models.IContainerTask) error {
- return p.performContainerAction(ctx, userCred, task, "save-volume-mount-to-image", task.GetParams())
- }
- func (p *SPodDriver) RequestCommitContainer(ctx context.Context, userCred mcclient.TokenCredential, task models.IContainerTask) error {
- return p.performContainerAction(ctx, userCred, task, "commit", task.GetParams())
- }
- func (p *SPodDriver) RequestDiskSnapshot(ctx context.Context, guest *models.SGuest, task taskman.ITask, snapshotId, diskId string) error {
- /*if guest.GetStatus() != api.VM_READY {
- return httperrors.NewNotAcceptableError("pod status %s is not ready", guest.GetStatus())
- }*/
- return p.SKVMGuestDriver.RequestDiskSnapshot(ctx, guest, task, snapshotId, diskId)
- }
- func (p *SPodDriver) RequestDeleteSnapshot(ctx context.Context, guest *models.SGuest, task taskman.ITask, params *jsonutils.JSONDict) error {
- /*if guest.GetStatus() != api.VM_READY {
- return httperrors.NewNotAcceptableError("pod status %s is not ready", guest.GetStatus())
- }*/
- return p.SKVMGuestDriver.RequestDeleteSnapshot(ctx, guest, task, params)
- }
- func (p *SPodDriver) BeforeDetachIsolatedDevice(ctx context.Context, userCred mcclient.TokenCredential, guest *models.SGuest, dev *models.SIsolatedDevice) error {
- ctrs, err := models.GetContainerManager().GetContainersByPod(guest.GetId())
- if err != nil {
- return errors.Wrapf(err, "get containers by pod %s", guest.GetId())
- }
- for _, ctr := range ctrs {
- ctrPtr := &ctr
- spec := ctrPtr.Spec
- devs := spec.Devices
- newDevs := make([]*api.ContainerDevice, 0)
- releasedDevs := make(map[string]models.ContainerReleasedDevice)
- for _, curDev := range devs {
- if curDev.IsolatedDevice == nil || curDev.IsolatedDevice.Id != dev.GetId() {
- tmpDev := curDev
- newDevs = append(newDevs, tmpDev)
- } else {
- releasedDevs[curDev.IsolatedDevice.Id] = *models.NewContainerReleasedDevice(curDev, dev.DevType, dev.Model)
- }
- }
- if err := ctrPtr.SaveReleasedDevices(ctx, userCred, releasedDevs); err != nil {
- return errors.Wrapf(err, "save release devices for container %s", ctr.GetId())
- }
- if _, err := db.Update(ctrPtr, func() error {
- ctrPtr.Spec.Devices = newDevs
- return nil
- }); err != nil {
- return errors.Wrapf(err, "update container %s devs", ctrPtr.GetId())
- }
- }
- return nil
- }
- func (p *SPodDriver) BeforeAttachIsolatedDevice(ctx context.Context, userCred mcclient.TokenCredential, guest *models.SGuest, dev *models.SIsolatedDevice) error {
- ctrs, err := models.GetContainerManager().GetContainersByPod(guest.GetId())
- if err != nil {
- return errors.Wrapf(err, "get containers by pod %s", guest.GetId())
- }
- for _, ctr := range ctrs {
- ctrPtr := &ctr
- if err := p.attachIsolatedDeviceToContainer(ctx, userCred, ctrPtr, dev); err != nil {
- return errors.Wrapf(err, "attach isolated device to container %s", ctr.GetId())
- }
- }
- return nil
- }
- func (p *SPodDriver) attachIsolatedDeviceToContainer(ctx context.Context, userCred mcclient.TokenCredential, ctrPtr *models.SContainer, dev *models.SIsolatedDevice) error {
- rlsDevs, err := ctrPtr.GetReleasedDevices(ctx, userCred)
- if err != nil {
- return errors.Wrapf(err, "get release devices for container %s", ctrPtr.GetId())
- }
- spec := new(api.ContainerSpec)
- if err := jsonutils.Marshal(ctrPtr.Spec).Unmarshal(spec); err != nil {
- return errors.Wrap(err, "deep copy spec")
- }
- // attach it
- if spec.Devices == nil {
- spec.Devices = make([]*api.ContainerDevice, 0)
- }
- shouldUpdate := true
- for _, curDev := range spec.Devices {
- if curDev.IsolatedDevice == nil {
- continue
- }
- if curDev.IsolatedDevice.Id == dev.GetId() {
- shouldUpdate = false
- break
- }
- }
- if shouldUpdate {
- spec.Devices = append(spec.Devices, &api.ContainerDevice{
- Type: apis.CONTAINER_DEVICE_TYPE_ISOLATED_DEVICE,
- IsolatedDevice: &api.ContainerIsolatedDevice{
- Id: dev.GetId(),
- },
- })
- if _, err := db.Update(ctrPtr, func() error {
- ctrPtr.Spec = spec
- return nil
- }); err != nil {
- return errors.Wrapf(err, "update container %s devs", ctrPtr.GetId())
- }
- }
- for id, rlsDev := range rlsDevs {
- if rlsDev.IsolatedDevice == nil {
- continue
- }
- if rlsDev.DeviceModel == dev.Model && rlsDev.DeviceType == dev.DevType {
- delete(rlsDevs, id)
- if err := ctrPtr.SaveReleasedDevices(ctx, userCred, rlsDevs); err != nil {
- return errors.Wrapf(err, "save release devices for container %s", ctrPtr.GetId())
- }
- return nil
- }
- }
- return nil
- }
|