| 1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206220722082209221022112212221322142215221622172218221922202221222222232224222522262227222822292230223122322233223422352236223722382239224022412242224322442245224622472248224922502251225222532254225522562257225822592260226122622263226422652266226722682269227022712272227322742275227622772278227922802281228222832284228522862287228822892290229122922293229422952296229722982299230023012302230323042305230623072308230923102311231223132314231523162317231823192320232123222323232423252326232723282329233023312332233323342335233623372338233923402341234223432344234523462347234823492350235123522353235423552356235723582359236023612362236323642365236623672368236923702371237223732374237523762377237823792380238123822383238423852386238723882389239023912392239323942395239623972398239924002401240224032404240524062407240824092410241124122413241424152416241724182419242024212422242324242425242624272428242924302431243224332434243524362437243824392440244124422443244424452446244724482449245024512452245324542455245624572458245924602461246224632464246524662467246824692470247124722473247424752476247724782479248024812482248324842485248624872488248924902491249224932494249524962497249824992500250125022503250425052506250725082509251025112512251325142515251625172518251925202521252225232524252525262527252825292530253125322533253425352536253725382539254025412542254325442545254625472548254925502551255225532554255525562557255825592560256125622563256425652566256725682569257025712572257325742575257625772578257925802581258225832584258525862587258825892590259125922593259425952596259725982599260026012602260326042605260626072608260926102611261226132614261526162617261826192620262126222623262426252626262726282629263026312632263326342635263626372638263926402641264226432644264526462647264826492650265126522653265426552656265726582659266026612662266326642665266626672668266926702671267226732674267526762677267826792680268126822683268426852686268726882689269026912692269326942695269626972698269927002701270227032704270527062707270827092710271127122713271427152716271727182719272027212722272327242725272627272728272927302731273227332734273527362737273827392740274127422743274427452746274727482749275027512752275327542755275627572758275927602761276227632764276527662767276827692770277127722773277427752776277727782779278027812782278327842785278627872788278927902791279227932794279527962797279827992800280128022803280428052806280728082809281028112812281328142815281628172818281928202821282228232824282528262827282828292830283128322833283428352836283728382839284028412842284328442845284628472848284928502851285228532854285528562857285828592860286128622863286428652866286728682869287028712872287328742875287628772878287928802881288228832884288528862887288828892890289128922893289428952896289728982899290029012902290329042905290629072908290929102911291229132914291529162917291829192920292129222923292429252926292729282929293029312932293329342935293629372938293929402941294229432944294529462947294829492950295129522953295429552956295729582959296029612962296329642965296629672968296929702971297229732974297529762977297829792980298129822983298429852986298729882989299029912992299329942995299629972998299930003001300230033004300530063007300830093010301130123013301430153016301730183019302030213022302330243025302630273028302930303031303230333034303530363037303830393040304130423043304430453046304730483049305030513052305330543055305630573058305930603061306230633064306530663067306830693070307130723073307430753076307730783079308030813082308330843085308630873088308930903091309230933094309530963097309830993100310131023103310431053106310731083109311031113112311331143115311631173118311931203121312231233124312531263127312831293130313131323133313431353136313731383139314031413142314331443145314631473148314931503151315231533154315531563157315831593160316131623163316431653166316731683169317031713172317331743175317631773178317931803181318231833184318531863187318831893190319131923193319431953196319731983199320032013202320332043205320632073208320932103211321232133214321532163217321832193220322132223223322432253226322732283229323032313232323332343235323632373238323932403241324232433244324532463247324832493250325132523253325432553256325732583259326032613262326332643265326632673268326932703271327232733274327532763277327832793280328132823283328432853286328732883289329032913292329332943295329632973298329933003301330233033304330533063307330833093310331133123313331433153316331733183319332033213322332333243325332633273328332933303331333233333334333533363337333833393340334133423343334433453346334733483349 |
- // 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 guestman
- import (
- "context"
- "encoding/base64"
- "encoding/json"
- "fmt"
- "io"
- "io/ioutil"
- "net/url"
- "os"
- "path"
- "path/filepath"
- "strconv"
- "strings"
- "sync"
- "time"
- "github.com/opencontainers/runtime-spec/specs-go"
- runtimeapi "k8s.io/cri-api/pkg/apis/runtime/v1"
- "yunion.io/x/jsonutils"
- "yunion.io/x/log"
- "yunion.io/x/pkg/errors"
- "yunion.io/x/pkg/util/sets"
- "yunion.io/x/pkg/utils"
- "yunion.io/x/onecloud/pkg/apis"
- computeapi "yunion.io/x/onecloud/pkg/apis/compute"
- hostapi "yunion.io/x/onecloud/pkg/apis/host"
- "yunion.io/x/onecloud/pkg/hostman/container/device"
- "yunion.io/x/onecloud/pkg/hostman/container/lifecycle"
- "yunion.io/x/onecloud/pkg/hostman/container/prober"
- proberesults "yunion.io/x/onecloud/pkg/hostman/container/prober/results"
- "yunion.io/x/onecloud/pkg/hostman/container/snapshot_service"
- "yunion.io/x/onecloud/pkg/hostman/container/status"
- "yunion.io/x/onecloud/pkg/hostman/container/volume_mount"
- "yunion.io/x/onecloud/pkg/hostman/container/volume_mount/disk"
- _ "yunion.io/x/onecloud/pkg/hostman/container/volume_mount/disk"
- "yunion.io/x/onecloud/pkg/hostman/guestman/desc"
- "yunion.io/x/onecloud/pkg/hostman/guestman/pod/runtime"
- "yunion.io/x/onecloud/pkg/hostman/guestman/pod/statusman"
- deployapi "yunion.io/x/onecloud/pkg/hostman/hostdeployer/apis"
- "yunion.io/x/onecloud/pkg/hostman/hostinfo"
- "yunion.io/x/onecloud/pkg/hostman/hostutils"
- "yunion.io/x/onecloud/pkg/hostman/isolated_device"
- _ "yunion.io/x/onecloud/pkg/hostman/isolated_device/container_device/cdi"
- "yunion.io/x/onecloud/pkg/hostman/options"
- "yunion.io/x/onecloud/pkg/hostman/storageman"
- "yunion.io/x/onecloud/pkg/httperrors"
- "yunion.io/x/onecloud/pkg/mcclient"
- "yunion.io/x/onecloud/pkg/mcclient/auth"
- computemod "yunion.io/x/onecloud/pkg/mcclient/modules/compute"
- imagemod "yunion.io/x/onecloud/pkg/mcclient/modules/image"
- "yunion.io/x/onecloud/pkg/util/cgrouputils/cpuset"
- "yunion.io/x/onecloud/pkg/util/fileutils2"
- "yunion.io/x/onecloud/pkg/util/mountutils"
- podutil "yunion.io/x/onecloud/pkg/util/pod"
- containerdutil "yunion.io/x/onecloud/pkg/util/pod/containerd"
- "yunion.io/x/onecloud/pkg/util/pod/logs"
- "yunion.io/x/onecloud/pkg/util/pod/nerdctl"
- "yunion.io/x/onecloud/pkg/util/procutils"
- )
- func (m *SGuestManager) startContainerProbeManager() {
- livenessManager := proberesults.NewManager()
- startupManager := proberesults.NewManager()
- man := prober.NewManager(status.NewManager(), livenessManager, startupManager, newContainerRunner(m))
- m.containerProbeManager = man
- man.Start()
- }
- func (m *SGuestManager) GetContainerProbeManager() prober.Manager {
- return m.containerProbeManager
- }
- func newContainerRunner(man *SGuestManager) *containerRunner {
- return &containerRunner{man}
- }
- type containerRunner struct {
- manager *SGuestManager
- }
- func (cr *containerRunner) RunInContainer(podId string, containerId string, cmd []string, timeout time.Duration) ([]byte, error) {
- srv, ok := cr.manager.GetServer(podId)
- if !ok {
- return nil, errors.Wrapf(httperrors.ErrNotFound, "server %s not found", podId)
- }
- s := srv.(*sPodGuestInstance)
- ctrCriId, err := s.getContainerCRIId(containerId)
- if err != nil {
- return nil, errors.Wrap(err, "get container cri id")
- }
- resp, err := s.getCRI().ExecSync(context.Background(), ctrCriId, cmd, int64(timeout.Seconds()))
- if err != nil {
- return nil, errors.Wrapf(err, "exec sync %#v to %s", cmd, ctrCriId)
- }
- return append(resp.Stdout, resp.Stderr...), nil
- }
- type PodInstance interface {
- GuestRuntimeInstance
- GetCRIId() string
- GetContainerById(ctrId string) *hostapi.ContainerDesc
- GetContainerByCRIId(criId string) (*hostapi.ContainerDesc, error)
- CreateContainer(ctx context.Context, userCred mcclient.TokenCredential, id string, input *hostapi.ContainerCreateInput) (jsonutils.JSONObject, error)
- StartContainer(ctx context.Context, userCred mcclient.TokenCredential, ctrId string, input *hostapi.ContainerCreateInput) (jsonutils.JSONObject, error)
- StartLocalContainer(ctx context.Context, userCred mcclient.TokenCredential, ctrId string) (jsonutils.JSONObject, error)
- DeleteContainer(ctx context.Context, cred mcclient.TokenCredential, id string) (jsonutils.JSONObject, error)
- SyncStatus(reason string, ctrId string)
- SyncContainerStatus(ctx context.Context, cred mcclient.TokenCredential, ctrId string) (jsonutils.JSONObject, error)
- StopContainer(ctx context.Context, userCred mcclient.TokenCredential, ctrId string, input *hostapi.ContainerStopInput) (jsonutils.JSONObject, error)
- GetContainerStatus(ctx context.Context, ctrId string) (string, *runtime.Status, error)
- IsPrimaryContainer(ctrId string) bool
- StopAll(ctx context.Context) error
- PullImage(ctx context.Context, userCred mcclient.TokenCredential, ctrId string, input *hostapi.ContainerPullImageInput) (jsonutils.JSONObject, error)
- SaveVolumeMountToImage(ctx context.Context, userCred mcclient.TokenCredential, input *hostapi.ContainerSaveVolumeMountToImageInput, ctrId string) (jsonutils.JSONObject, error)
- ExecContainer(ctx context.Context, userCred mcclient.TokenCredential, ctrId string, input *computeapi.ContainerExecInput) (*url.URL, error)
- ContainerExecSync(ctx context.Context, userCred mcclient.TokenCredential, ctrId string, input *computeapi.ContainerExecSyncInput) (jsonutils.JSONObject, error)
- SetContainerResourceLimit(ctrId string, limit *apis.ContainerResources) (jsonutils.JSONObject, error)
- CommitContainer(ctx context.Context, userCred mcclient.TokenCredential, ctrId string, input *hostapi.ContainerCommitInput) (jsonutils.JSONObject, error)
- AddContainerVolumeMountPostOverlay(ctx context.Context, userCred mcclient.TokenCredential, ctrId string, input *computeapi.ContainerVolumeMountAddPostOverlayInput) error
- RemoveContainerVolumeMountPostOverlay(ctx context.Context, userCred mcclient.TokenCredential, ctrId string, input *computeapi.ContainerVolumeMountRemovePostOverlayInput) error
- ReadLogs(ctx context.Context, userCred mcclient.TokenCredential, ctrId string, input *computeapi.PodLogOptions, stdout, stderr io.Writer) error
- // for monitoring
- GetVolumeMountUsages() (map[ContainerVolumeKey]*volume_mount.ContainerVolumeMountUsage, error)
- IsInternalStopped(ctrCriId string) (*ContainerExpectedStatus, bool)
- IsInternalRemoved(ctrCriId string) bool
- GetPodContainerCriIds() []string
- // For container log rotation: log dir, relative log path per container, and ctrId->criId map
- GetPodLogDir() string
- GetContainerLogPath(ctrId string) string
- ListContainerCriIds() map[string]string
- }
- type sContainer struct {
- Id string `json:"id"`
- Index int `json:"index"`
- CRIId string `json:"cri_id"`
- }
- func newContainer(id string) *sContainer {
- return &sContainer{
- Id: id,
- }
- }
- type startStatHelper struct {
- podId string
- homeDir string
- }
- func newStartStatHelper(podId string, homeDir string) *startStatHelper {
- return &startStatHelper{
- podId: podId,
- homeDir: homeDir,
- }
- }
- func (h startStatHelper) getPodFile() string {
- return filepath.Join(h.homeDir, "pod-start.stat")
- }
- func (h startStatHelper) IsPodFileExists() bool {
- return fileutils2.Exists(h.getPodFile())
- }
- func (h startStatHelper) createStatFile(fp string) error {
- if fileutils2.Exists(fp) {
- return nil
- }
- if err := podutil.EnsureFile(fp, "", "755"); err != nil {
- return errors.Wrapf(err, "ensure file %s", fp)
- }
- return nil
- }
- func (h startStatHelper) removeStatFile(fp string) error {
- if !fileutils2.Exists(fp) {
- return nil
- }
- if err := os.Remove(fp); err != nil && !strings.Contains(err.Error(), "no such file or directory") {
- return errors.Wrapf(err, "remove file %s", fp)
- }
- return nil
- }
- func (h startStatHelper) CreatePodFile() error {
- return h.createStatFile(h.getPodFile())
- }
- func (h startStatHelper) RemovePodFile() error {
- return h.removeStatFile(h.getPodFile())
- }
- func (h startStatHelper) getContainerFile(ctrId string) string {
- return filepath.Join(h.homeDir, fmt.Sprintf("container-start-%s.stat", ctrId))
- }
- func (h startStatHelper) IsContainerFileExists(ctrId string) bool {
- return fileutils2.Exists(h.getContainerFile(ctrId))
- }
- func (h startStatHelper) CreateContainerFile(ctrId string) error {
- return h.createStatFile(h.getContainerFile(ctrId))
- }
- func (h startStatHelper) RemoveContainerFile(ctrId string) error {
- return h.removeStatFile(h.getContainerFile(ctrId))
- }
- type sPodGuestInstance struct {
- *sBaseGuestInstance
- containers map[string]*sContainer
- startStat *startStatHelper
- expectedStatus *PodExpectedStatus
- startPodLock sync.Mutex
- saveContainerLock sync.Mutex
- }
- func newPodGuestInstance(id string, man *SGuestManager) PodInstance {
- p := &sPodGuestInstance{
- sBaseGuestInstance: newBaseGuestInstance(id, man, computeapi.HYPERVISOR_POD),
- containers: make(map[string]*sContainer),
- startPodLock: sync.Mutex{},
- saveContainerLock: sync.Mutex{},
- }
- es, err := NewPodExpectedStatus(p.HomeDir(), computeapi.VM_UNKNOWN)
- if err != nil {
- log.Fatalf("NewPodExpectedStatus failed of %s: %s", p.HomeDir(), err)
- }
- p.expectedStatus = es
- p.startStat = newStartStatHelper(id, p.HomeDir())
- return p
- }
- func (s *sPodGuestInstance) CleanGuest(ctx context.Context, params interface{}) (jsonutils.JSONObject, error) {
- var err error
- criId := s.GetCRIId()
- if criId == "" {
- criId, err = s.getPodIdFromCRI()
- if err != nil && !IsContainerNotFoundError(err) {
- return nil, errors.Wrapf(err, "get cri pod id")
- }
- }
- if criId != "" {
- if err := s.getCRI().RemovePod(ctx, criId); err != nil {
- return nil, errors.Wrapf(err, "RemovePod with cri_id %q", criId)
- }
- }
- return nil, DeleteHomeDir(s)
- }
- func (s *sPodGuestInstance) getPodIdFromCRI() (string, error) {
- ids, err := runtime.GetSandboxIDByPodUID(s.getCRI(), s.GetInitialId(), nil)
- if err != nil {
- return "", errors.Wrapf(err, "get pod cri_id by uid %s", s.GetInitialId())
- }
- if len(ids) == 0 {
- return "", errors.Wrapf(errors.ErrNotFound, "not found cri pod by uid %s", s.GetInitialId())
- }
- return ids[0], nil
- }
- func (s *sPodGuestInstance) ExitCleanup(clear bool) {
- }
- func (s *sPodGuestInstance) CleanDirtyGuest(ctx context.Context) error {
- _, err := s.CleanGuest(ctx, false)
- return err
- }
- func (s *sPodGuestInstance) ImportServer(pendingDelete bool) {
- // TODO: 参考SKVMGuestInstance,可以做更多的事,比如同步状态
- s.manager.SaveServer(s.Id, s)
- s.manager.RemoveCandidateServer(s)
- if s.IsDaemon() || s.IsDirtyShutdown() {
- ctx := context.Background()
- cred := hostutils.GetComputeSession(ctx).GetToken()
- if err := s.StartLocalDirtyPod(ctx, cred); err != nil {
- log.Errorf("start local pod err %s", err.Error())
- }
- } else {
- s.SyncStatus("sync status after host started", "")
- s.getProbeManager().AddPod(s)
- }
- }
- func (s *sPodGuestInstance) isPodDirtyShutdown() bool {
- if !s.IsRunning() && s.startStat.IsPodFileExists() {
- return true
- }
- return false
- }
- func (s *sPodGuestInstance) isContainerDirtyShutdown(ctrId string) bool {
- isRunning, err := s.IsContainerRunning(context.Background(), ctrId)
- if err != nil {
- log.Warningf("[isContainerDrityShutdown] IsContainerRunning(%s, %s): %v", s.GetId(), ctrId, err)
- }
- if !isRunning && s.startStat.IsContainerFileExists(ctrId) {
- return true
- }
- return false
- }
- func (s *sPodGuestInstance) IsDirtyShutdown() bool {
- if !s.manager.EnableDirtyRecoveryFeature() {
- return false
- }
- if s.isPodDirtyShutdown() {
- return true
- }
- for _, ctr := range s.GetContainers() {
- if s.isContainerDirtyShutdown(ctr.Id) {
- return true
- }
- }
- return false
- }
- func (s *sPodGuestInstance) getStatus(ctx context.Context, defaultStatus string) string {
- status := defaultStatus
- if status == "" {
- status = computeapi.VM_READY
- }
- if s.IsRunning() {
- status = computeapi.VM_RUNNING
- }
- for _, c := range s.GetContainers() {
- cStatus, cs, err := s.getContainerStatus(ctx, c.Id)
- if err != nil {
- log.Errorf("get container %s status of pod %s", c.Id, s.Id)
- continue
- }
- if cs != nil {
- status = GetPodStatusByContainerStatus(status, cStatus, s.IsPrimaryContainer(c.Id))
- }
- }
- return status
- }
- func (s *sPodGuestInstance) GetUploadStatus(ctx context.Context, reason string) (*computeapi.HostUploadGuestStatusInput, error) {
- // sync pod status
- var status = computeapi.VM_READY
- if s.IsRunning() {
- status = computeapi.VM_RUNNING
- }
- errs := make([]error, 0)
- if err := s.expectedStatus.SetStatus(status); err != nil {
- log.Warningf("set expected status to %s, reason: %s, err: %s", status, reason, err.Error())
- }
- /*if status == computeapi.VM_READY {
- // remove pod
- if err := s.stopPod(ctx, 5); err != nil {
- log.Warningf("stop cri pod when sync status: %s: %v", s.Id, err)
- }
- }*/
- // sync container's status
- cStatuss := make(map[string]*computeapi.ContainerPerformStatusInput)
- for _, c := range s.GetContainers() {
- cStatus, cs, err := s.getContainerStatus(ctx, c.Id)
- if err != nil {
- log.Errorf("get container %s status of pod %s", c.Id, s.Id)
- continue
- }
- /*if err := s.expectedStatus.SetContainerStatus(c.CRIId, c.Id, cStatus); err != nil {
- log.Warningf("expectedStatus.SetContainerStatus(%s, %s) to %s, error: %s", s.GetId(), c.Id, cStatus, err.Error())
- }*/
- ctrStatusInput := &computeapi.ContainerPerformStatusInput{
- PerformStatusInput: apis.PerformStatusInput{
- Status: cStatus,
- Reason: reason,
- HostId: hostinfo.Instance().HostId,
- },
- }
- if cs != nil {
- if computeapi.ContainerNoFailedRunningStatus.Has(cStatus) {
- ctrStatusInput.RestartCount = 0
- } else {
- ctrStatusInput.RestartCount = cs.RestartCount
- }
- if !cs.StartedAt.IsZero() {
- ctrStatusInput.StartedAt = &cs.StartedAt
- }
- if !cs.FinishedAt.IsZero() {
- ctrStatusInput.LastFinishedAt = &cs.FinishedAt
- }
- if ctr := s.GetContainerById(c.Id); ctr != nil {
- ctr.RestartCount = ctrStatusInput.RestartCount
- ctr.StartedAt = cs.StartedAt
- ctr.LastFinishedAt = cs.FinishedAt
- if err := s.SaveContainerDesc(ctr); err != nil {
- errs = append(errs, errors.Wrapf(err, "save container desc for %s/%s", ctr.Id, ctr.Name))
- }
- }
- }
- cStatuss[c.Id] = ctrStatusInput
- status = GetPodStatusByContainerStatus(status, cStatus, s.IsPrimaryContainer(c.Id))
- }
- if len(errs) > 0 {
- log.Errorf("get upload status error: %v", errors.NewAggregate(errs))
- }
- statusInput := &apis.PerformStatusInput{
- Status: status,
- Reason: reason,
- PowerStates: GetPowerStates(s),
- HostId: hostinfo.Instance().HostId,
- }
- return &computeapi.HostUploadGuestStatusInput{
- PerformStatusInput: *statusInput,
- Containers: cStatuss,
- }, nil
- }
- // UploadStatus uploads the status of the pod and the specified container to the server
- // If uploadCtrId is not empty, only the status of the specified container will be uploaded
- // If uploadCtrId is empty, all containers' status will be uploaded
- func (s *sPodGuestInstance) UploadStatus(ctx context.Context, reason string, uploadCtrId string) error {
- /*resp, err := s.GetUploadStatus(ctx, reason)
- if err != nil {
- return errors.Wrapf(err, "get upload status of pod: %s", reason)
- }
- errs := make([]error, 0)
- // sync container's status
- for id, ctrStatusInput := range resp.Containers {
- if _, err := hostutils.UpdateContainerStatus(ctx, id, ctrStatusInput); err != nil {
- errs = append(errs, errors.Wrapf(err, "failed update container %s status", id))
- }
- // 同步容器状态可能会出现 probing 状态,所以需要 mark 成 dirty,等待 probe manager 重新探测容器状态
- s.markContainerProbeDirty(ctrStatusInput.Status, id, reason)
- }
- if _, err := hostutils.UpdateServerStatus(ctx, s.Id, &resp.PerformStatusInput); err != nil {
- errs = append(errs, errors.Wrapf(err, "failed update guest status"))
- }*/
- // return errors.NewAggregate(errs)
- resp, err := s.GetUploadStatus(ctx, reason)
- if err != nil {
- return errors.Wrapf(err, "get upload status of pod: %s", reason)
- }
- containerStatuses := make(map[string]*statusman.ContainerStatus)
- for ctrId, cStatus := range resp.Containers {
- if uploadCtrId != "" && ctrId != uploadCtrId {
- continue
- }
- containerStatuses[ctrId] = &statusman.ContainerStatus{
- Status: cStatus.Status,
- RestartCount: cStatus.RestartCount,
- StartedAt: cStatus.StartedAt,
- LastFinishedAt: cStatus.LastFinishedAt,
- }
- }
- if err := statusman.GetManager().UpdateStatus(&statusman.PodStatusUpdateRequest{
- Id: s.Id,
- Pod: s,
- Status: resp.Status,
- ContainerStatuses: containerStatuses,
- Reason: reason,
- }); err != nil {
- return errors.Wrapf(err, "update status of pod: %s", reason)
- }
- return nil
- }
- func (s *sPodGuestInstance) PostUploadStatus(resp *computeapi.HostUploadGuestStatusInput, reason string) {
- for ctrId, cStatus := range resp.Containers {
- s.markContainerProbeDirty(cStatus.Status, ctrId, reason)
- }
- }
- func (s *sPodGuestInstance) SyncStatus(reason string, ctrId string) {
- if err := s.UploadStatus(context.Background(), reason, ctrId); err != nil {
- log.Warningf("upload status failed, reason: %s, err: %v", reason, err)
- }
- }
- func (s *sPodGuestInstance) DeployFs(ctx context.Context, userCred mcclient.TokenCredential, deployInfo *deployapi.DeployInfo) (jsonutils.JSONObject, error) {
- // update port_mappings
- /*podInput, err := s.getPodCreateParams()
- if err != nil {
- return nil, errors.Wrap(err, "getPodCreateParams")
- }
- if len(podInput.PortMappings) != 0 {
- pms, err := s.getPortMappings(podInput.PortMappings)
- if err != nil {
- return nil, errors.Wrap(err, "get port mappings")
- }
- if err := s.setPortMappings(ctx, userCred, s.convertToPodMetadataPortMappings(pms)); err != nil {
- return nil, errors.Wrap(err, "set port mappings")
- }
- }*/
- return nil, nil
- }
- func (s *sPodGuestInstance) IsStopped() bool {
- //TODO implement me
- panic("implement me")
- }
- func (s *sPodGuestInstance) IsSuspend() bool {
- return false
- }
- func (s *sPodGuestInstance) getCRI() podutil.CRI {
- return s.manager.GetCRI()
- }
- func (s *sPodGuestInstance) getProbeManager() prober.Manager {
- return s.manager.GetContainerProbeManager()
- }
- func (s *sPodGuestInstance) getHostCPUMap() *podutil.HostContainerCPUMap {
- return s.manager.GetContainerCPUMap()
- }
- func (s *sPodGuestInstance) getPod(ctx context.Context) (*runtimeapi.PodSandbox, error) {
- pods, err := s.getCRI().ListPods(ctx, podutil.ListPodOptions{})
- if err != nil {
- return nil, errors.Wrap(err, "ListPods")
- }
- for _, p := range pods {
- if p.Metadata.Uid == s.Id {
- return p, nil
- }
- }
- return nil, errors.Wrap(httperrors.ErrNotFound, "Not found pod from containerd")
- }
- func (s *sPodGuestInstance) IsRunning() bool {
- pod, err := s.getPod(context.Background())
- if err != nil {
- return false
- }
- if pod.GetState() == runtimeapi.PodSandboxState_SANDBOX_READY {
- return true
- }
- return false
- }
- func (s *sPodGuestInstance) IsContainerRunning(ctx context.Context, ctrId string) (bool, error) {
- status, _, err := s.getContainerStatus(ctx, ctrId)
- if err != nil {
- return false, errors.Wrapf(err, "get container %s status error", ctrId)
- }
- if computeapi.ContainerRunningStatus.Has(status) {
- return true, nil
- }
- return false, nil
- }
- func (s *sPodGuestInstance) probeGuestStatus(ctx context.Context, resp *computeapi.HostUploadGuestStatusInput) {
- resp.Status = s.getStatus(ctx, resp.Status)
- }
- func (s *sPodGuestInstance) HandleGuestStatus(ctx context.Context, resp *computeapi.HostUploadGuestStatusInput, isBatch bool) *computeapi.HostUploadGuestStatusInput {
- //s.probeGuestStatus(ctx, resp)
- //hostutils.TaskComplete(ctx, jsonutils.Marshal(resp))
- ctrStatus, _ := s.GetUploadStatus(ctx, "")
- return ctrStatus
- }
- func (s *sPodGuestInstance) HandleGuestStart(ctx context.Context, userCred mcclient.TokenCredential, body jsonutils.JSONObject) (jsonutils.JSONObject, error) {
- hostutils.DelayTaskWithWorker(ctx, func(ctx context.Context, params interface{}) (jsonutils.JSONObject, error) {
- resp, err := s.startPod(ctx, userCred)
- if err != nil {
- return nil, errors.Wrap(err, "startPod")
- }
- resJ := jsonutils.Marshal(resp)
- res := resJ.(*jsonutils.JSONDict)
- if !s.manager.host.IsSchedulerNumaAllocateEnabled() {
- res.Set("cpu_numa_pin", jsonutils.Marshal(s.Desc.CpuNumaPin))
- }
- return res, nil
- }, nil, s.manager.GuestStartWorker)
- return nil, nil
- }
- func (s *sPodGuestInstance) HandleStop(ctx context.Context, timeout int64) error {
- hostutils.DelayTask(ctx, func(ctx context.Context, params interface{}) (jsonutils.JSONObject, error) {
- err := s.stopPod(ctx, timeout)
- if err != nil {
- return nil, errors.Wrap(err, "stopPod")
- }
- return nil, nil
- }, nil)
- return nil
- }
- func (s *sPodGuestInstance) getCreateParams() (jsonutils.JSONObject, error) {
- createParamsStr, ok := s.GetDesc().Metadata[computeapi.VM_METADATA_CREATE_PARAMS]
- if !ok {
- return nil, errors.Errorf("not found %s in metadata", computeapi.VM_METADATA_CREATE_PARAMS)
- }
- return jsonutils.ParseString(createParamsStr)
- }
- func (s *sPodGuestInstance) getPostStopCleanupConfig() (*computeapi.PodPostStopCleanupConfig, error) {
- data, ok := s.GetDesc().Metadata[computeapi.POD_METADATA_POST_STOP_CLEANUP_CONFIG]
- if !ok {
- return nil, nil
- }
- jsonData, err := jsonutils.ParseString(data)
- if err != nil {
- return nil, errors.Wrapf(err, "parse to json")
- }
- input := new(computeapi.PodPostStopCleanupConfig)
- if err := jsonData.Unmarshal(input); err != nil {
- return nil, errors.Wrapf(err, "unmarshal to pod post stop cleanup config")
- }
- return input, nil
- }
- func (s *sPodGuestInstance) getPodCreateParams() (*computeapi.PodCreateInput, error) {
- createParams, err := s.getCreateParams()
- if err != nil {
- return nil, errors.Wrapf(err, "getCreateParams")
- }
- input := new(computeapi.PodCreateInput)
- if err := createParams.Unmarshal(input, "pod"); err != nil {
- return nil, errors.Wrapf(err, "unmarshal to pod creation input")
- }
- return input, nil
- }
- func (s *sPodGuestInstance) getPodLogDir() string {
- return filepath.Join(s.HomeDir(), "logs")
- }
- func (s *sPodGuestInstance) GetPodLogDir() string {
- return s.getPodLogDir()
- }
- func (s *sPodGuestInstance) getContainerLogPath(ctrId string) string {
- return filepath.Join(fmt.Sprintf("%s.log", ctrId))
- }
- func (s *sPodGuestInstance) GetContainerLogPath(ctrId string) string {
- return s.getContainerLogPath(ctrId)
- }
- func (s *sPodGuestInstance) ListContainerCriIds() map[string]string {
- out := make(map[string]string, len(s.containers))
- for ctrId, c := range s.containers {
- out[ctrId] = c.CRIId
- }
- return out
- }
- func (s *sPodGuestInstance) getShmDir() string {
- return filepath.Join(s.HomeDir(), "shm")
- }
- func (s *sPodGuestInstance) getContainerShmDir(containerName string) string {
- return filepath.Join(s.getShmDir(), fmt.Sprintf("%s-shm", containerName))
- }
- func (s *sPodGuestInstance) GetDisks() []*desc.SGuestDisk {
- return s.GetDesc().Disks
- }
- func (s *sPodGuestInstance) ConvertRootFsToVolumeMount(rootFs *hostapi.ContainerRootfs) *hostapi.ContainerVolumeMount {
- return &hostapi.ContainerVolumeMount{
- Type: rootFs.Type,
- Disk: rootFs.Disk,
- }
- }
- func (s *sPodGuestInstance) mountRootFs(ctrId string, rootFs *hostapi.ContainerRootfs) error {
- drv := volume_mount.GetDriver(rootFs.Type)
- vol := s.ConvertRootFsToVolumeMount(rootFs)
- if err := drv.Mount(s, ctrId, vol); err != nil {
- return errors.Wrapf(err, "mount root fs %s, ctrId %s", jsonutils.Marshal(rootFs), ctrId)
- }
- return nil
- }
- func (s *sPodGuestInstance) clearContainerRootFs(ctrId string, rootFs *hostapi.ContainerRootfs) error {
- if rootFs == nil {
- return nil
- }
- drv := volume_mount.GetDriver(rootFs.Type)
- vol := s.ConvertRootFsToVolumeMount(rootFs)
- hostPath, err := drv.GetRuntimeMountHostPath(s, ctrId, vol)
- if err != nil {
- return errors.Wrapf(err, "get runtime mount path")
- }
- if !rootFs.Persistent {
- if err := volume_mount.RemoveDir(hostPath); err != nil {
- return errors.Wrapf(err, "remove %q", hostPath)
- }
- log.Infof("clear rootfs of container %s/%s: %q", s.GetName(), ctrId, hostPath)
- }
- return nil
- }
- func (s *sPodGuestInstance) umountRootFs(ctrId string, rootFs *hostapi.ContainerRootfs) error {
- if rootFs == nil {
- return nil
- }
- drv := volume_mount.GetDriver(rootFs.Type).(volume_mount.IConnectedVolumeMount)
- vol := s.ConvertRootFsToVolumeMount(rootFs)
- if err := s.clearContainerRootFs(ctrId, rootFs); err != nil {
- return errors.Wrapf(err, "clear rootfs of container %s", ctrId)
- }
- if err := drv.UnmountWithoutDisconnect(s, ctrId, vol); err != nil {
- return errors.Wrapf(err, "unmount root fs %s, ctrId %s", jsonutils.Marshal(rootFs), ctrId)
- }
- return nil
- }
- func (s *sPodGuestInstance) GetRootFsMountPath(ctrId string) (string, error) {
- ctr := s.GetContainerById(ctrId)
- if ctr == nil {
- return "", errors.Wrapf(httperrors.ErrNotFound, "not found container %s", ctrId)
- }
- rootFs := ctr.Spec.Rootfs
- if rootFs == nil {
- return "", errors.Wrapf(httperrors.ErrNotFound, "not found root fs %s", ctrId)
- }
- vol := s.ConvertRootFsToVolumeMount(rootFs)
- drv := volume_mount.GetDriver(vol.Type)
- hostPath, err := drv.GetRuntimeMountHostPath(s, ctrId, vol)
- if err != nil {
- return "", errors.Wrapf(err, "get runtime mount host path %s, ctrId %s", jsonutils.Marshal(vol), ctrId)
- }
- return hostPath, nil
- }
- func (s *sPodGuestInstance) mountPodVolumes() error {
- for _, ctr := range s.GetDesc().Containers {
- if ctr.Spec.Rootfs == nil {
- continue
- }
- if err := s.mountRootFs(ctr.Id, ctr.Spec.Rootfs); err != nil {
- return errors.Wrapf(err, "mount root fs %s, ctrId %s", jsonutils.Marshal(ctr.Spec.Rootfs), ctr.Id)
- }
- }
- for ctrId, vols := range s.getContainerVolumeMounts() {
- for _, vol := range vols {
- drv := volume_mount.GetDriver(vol.Type)
- if err := drv.Mount(s, ctrId, vol); err != nil {
- return errors.Wrapf(err, "mount volume %s, ctrId %s", jsonutils.Marshal(vol), ctrId)
- }
- if vol.FsUser != nil || vol.FsGroup != nil {
- // change mountpoint owner
- if err := volume_mount.ChangeDirOwner(s, drv, ctrId, vol); err != nil {
- return errors.Wrapf(err, "change dir owner")
- }
- }
- }
- }
- return nil
- }
- func (s *sPodGuestInstance) umountPodVolumes() error {
- disConnectFuncs := make([]func() error, 0)
- for ctrId, vols := range s.getContainerVolumeMounts() {
- for _, vol := range vols {
- drv := volume_mount.GetDriver(vol.Type)
- connectedDrv, ok := drv.(volume_mount.IConnectedVolumeMount)
- if !ok {
- if err := drv.Unmount(s, ctrId, vol); err != nil {
- return errors.Wrapf(err, "Unmount volume %s, ctrId %s", jsonutils.Marshal(vol), ctrId)
- }
- } else {
- if err := connectedDrv.UnmountWithoutDisconnect(s, ctrId, vol); err != nil {
- return errors.Wrapf(err, "UnmountWithoutDisconnect volume %s, ctrId %s", jsonutils.Marshal(vol), ctrId)
- }
- tmpCtrId := ctrId
- tmpVol := vol
- disConnectFuncs = append(disConnectFuncs, func() error {
- if err := connectedDrv.Disconnect(s, tmpCtrId, tmpVol); err != nil {
- return errors.Wrapf(err, "Disconnect volume %s, ctrId %s", jsonutils.Marshal(tmpVol), tmpCtrId)
- }
- return nil
- })
- }
- }
- }
- for _, ctr := range s.GetDesc().Containers {
- if ctr.Spec.Rootfs == nil {
- continue
- }
- if err := s.umountRootFs(ctr.Id, ctr.Spec.Rootfs); err != nil {
- return errors.Wrapf(err, "umount root fs %s, ctrId %s", jsonutils.Marshal(ctr.Spec.Rootfs), ctr.Id)
- }
- }
- for _, disConnectFunc := range disConnectFuncs {
- if err := disConnectFunc(); err != nil {
- return errors.Wrapf(err, "disconnect volume")
- }
- }
- return nil
- }
- func (s *sPodGuestInstance) GetContainers() []*hostapi.ContainerDesc {
- return s.GetDesc().Containers
- }
- func (s *sPodGuestInstance) GetPodContainerCriIds() []string {
- criids := make([]string, 0)
- for i := range s.containers {
- criids = append(criids, s.containers[i].CRIId)
- }
- return criids
- }
- func (s *sPodGuestInstance) HasContainerNvidiaGpu() bool {
- for i := range s.Desc.IsolatedDevices {
- if utils.IsInStringArray(s.Desc.IsolatedDevices[i].DevType, computeapi.NVIDIA_GPU_TYPES) {
- return true
- }
- }
- return false
- }
- func (s *sPodGuestInstance) GetContainerById(ctrId string) *hostapi.ContainerDesc {
- ctrs := s.GetContainers()
- for i := range ctrs {
- ctr := ctrs[i]
- if ctr.Id == ctrId {
- return ctr
- }
- }
- return nil
- }
- func (s *sPodGuestInstance) SaveContainerDesc(ctr *hostapi.ContainerDesc) error {
- ctrs := s.GetContainers()
- for i := range ctrs {
- tmp := ctrs[i]
- if tmp.Id == ctr.Id {
- ctrs[i] = ctr
- }
- }
- s.GetDesc().Containers = ctrs
- return SaveDesc(s, s.GetDesc())
- }
- func (s *sPodGuestInstance) getContainerVolumeMounts() map[string][]*hostapi.ContainerVolumeMount {
- result := make(map[string][]*hostapi.ContainerVolumeMount, 0)
- for _, ctr := range s.GetDesc().Containers {
- mnts, ok := result[ctr.Id]
- if !ok {
- mnts = make([]*hostapi.ContainerVolumeMount, 0)
- }
- for _, vol := range ctr.Spec.VolumeMounts {
- tmp := vol
- mnts = append(mnts, tmp)
- }
- result[ctr.Id] = mnts
- }
- return result
- }
- func (s *sPodGuestInstance) getContainerVolumeMountsByDiskId(ctrId, diskId string) []*hostapi.ContainerVolumeMount {
- ctrVols := s.getContainerVolumeMounts()
- vols, ok := ctrVols[ctrId]
- if !ok {
- return nil
- }
- volList := make([]*hostapi.ContainerVolumeMount, 0)
- for _, vol := range vols {
- if vol.Disk != nil {
- if vol.Disk.Id == diskId {
- tmpVol := vol
- volList = append(volList, tmpVol)
- }
- }
- }
- return volList
- }
- func (s *sPodGuestInstance) GetVolumesDir() string {
- return filepath.Join(s.HomeDir(), "volumes")
- }
- func (s *sPodGuestInstance) GetVolumesOverlayDir() string {
- return filepath.Join(s.GetVolumesDir(), "_overlay_")
- }
- func (s *sPodGuestInstance) GetDiskMountPoint(disk storageman.IDisk) string {
- return s.GetDiskMountPointById(disk.GetId())
- }
- func (s *sPodGuestInstance) GetDiskMountPointById(diskId string) string {
- return filepath.Join(s.GetVolumesDir(), diskId)
- }
- func (s *sPodGuestInstance) getPodPrivilegedMode(input *computeapi.PodCreateInput) bool {
- for _, ctr := range input.Containers {
- if ctr.Privileged {
- return true
- }
- }
- return false
- }
- func (s *sPodGuestInstance) getOtherPods() []*sPodGuestInstance {
- man := s.manager
- otherPods := make([]*sPodGuestInstance, 0)
- man.Servers.Range(func(id, value any) bool {
- if id == s.Id {
- return true
- }
- ins := value.(GuestRuntimeInstance)
- pod, ok := ins.(*sPodGuestInstance)
- if !ok {
- return true
- }
- otherPods = append(otherPods, pod)
- return true
- })
- return otherPods
- }
- func PodCgroupParent() string {
- return "/cloudpods"
- }
- type localDirtyPodStartTask struct {
- ctx context.Context
- userCred mcclient.TokenCredential
- pod *sPodGuestInstance
- }
- func newLocalDirtyPodStartTask(ctx context.Context, userCred mcclient.TokenCredential, pod *sPodGuestInstance) *localDirtyPodStartTask {
- return &localDirtyPodStartTask{
- ctx: ctx,
- userCred: userCred,
- pod: pod,
- }
- }
- func (t *localDirtyPodStartTask) Run() {
- /*if t.pod.isPodDirtyShutdown() {
- log.Infof("start dirty pod locally (%s/%s)", t.pod.Id, t.pod.GetName())
- if _, err := t.pod.startPod(t.ctx, t.userCred); err != nil {
- log.Errorf("start dirty pod(%s/%s) err: %s", t.pod.GetId(), t.pod.GetName(), err.Error())
- }
- }*/
- for _, ctr := range t.pod.GetContainers() {
- if t.pod.isContainerDirtyShutdown(ctr.Id) {
- if !t.pod.IsRunning() {
- log.Infof("start dirty pod locally (%s/%s)", t.pod.Id, t.pod.GetName())
- if _, err := t.pod.startPod(t.ctx, t.userCred); err != nil {
- log.Errorf("start dirty pod(%s/%s) err: %s", t.pod.GetId(), t.pod.GetName(), err.Error())
- }
- }
- log.Infof("start dirty container locally (%s/%s/%s/%s)", t.pod.Id, t.pod.GetName(), ctr.Id, ctr.Name)
- if _, err := t.pod.StartLocalContainer(t.ctx, t.userCred, ctr.Id); err != nil {
- log.Errorf("start dirty container %s err: %s", ctr.Id, err.Error())
- }
- }
- }
- t.pod.SyncStatus("sync status after dirty pod start locally", "")
- }
- func (t *localDirtyPodStartTask) Dump() string {
- return fmt.Sprintf("pod start task %s/%s", t.pod.GetId(), t.pod.GetName())
- }
- func (s *sPodGuestInstance) StartLocalDirtyPod(ctx context.Context, userCred mcclient.TokenCredential) error {
- s.manager.GuestStartWorker.Run(newLocalDirtyPodStartTask(ctx, userCred, s), nil, nil)
- return nil
- }
- func (s *sPodGuestInstance) ShouldRestartPodOnCrash() bool {
- if len(s.GetContainers()) <= 1 {
- return true
- }
- return false
- }
- func (s *sPodGuestInstance) IsPrimaryContainer(ctrId string) bool {
- ctr := s.GetContainerById(ctrId)
- if ctr == nil {
- return false
- }
- if len(s.containers) == 1 {
- return true
- }
- return ctr.Spec.Primary
- }
- func (s *sPodGuestInstance) startPod(ctx context.Context, userCred mcclient.TokenCredential) (*computeapi.PodStartResponse, error) {
- s.startPodLock.Lock()
- defer s.startPodLock.Unlock()
- retries := 3
- sec := 5 * time.Second
- var err error
- var resp *computeapi.PodStartResponse
- for i := 1; i <= retries; i++ {
- resp, err = s._startPod(ctx, userCred)
- if err == nil {
- return resp, nil
- }
- log.Errorf("start pod %s/%s error with %d times: %v", s.GetId(), s.GetName(), i, err)
- time.Sleep(sec * time.Duration(i))
- }
- return resp, err
- }
- func (s *sPodGuestInstance) namespacesForPod(input *computeapi.PodCreateInput) *runtimeapi.NamespaceOption {
- opt := &runtimeapi.NamespaceOption{
- Ipc: runtimeapi.NamespaceMode_POD,
- Network: runtimeapi.NamespaceMode_POD,
- Pid: runtimeapi.NamespaceMode_CONTAINER,
- }
- if input.HostIPC {
- opt.Ipc = runtimeapi.NamespaceMode_NODE
- }
- return opt
- }
- func (s *sPodGuestInstance) updateGuestDesc() error {
- s.Desc = new(desc.SGuestDesc)
- err := jsonutils.Marshal(s.SourceDesc).Unmarshal(s.Desc)
- if err != nil {
- return errors.Wrap(err, "unmarshal source desc")
- }
- return s.allocateCpuNumaPin()
- }
- func (s *sPodGuestInstance) _startPod(ctx context.Context, userCred mcclient.TokenCredential) (*computeapi.PodStartResponse, error) {
- podInput, err := s.getPodCreateParams()
- if err != nil {
- return nil, errors.Wrap(err, "getPodCreateParams")
- }
- if err := s.updateGuestDesc(); err != nil {
- return nil, errors.Wrap(err, "updateGuestDesc")
- }
- if err := s.mountPodVolumes(); err != nil {
- return nil, errors.Wrap(err, "mountPodVolumes")
- }
- if err := s.ensurePodRemoved(ctx, 0); err != nil {
- log.Warningf("ensure pod removed before starting %s: %v", s.GetId(), err)
- }
- podCfg := &runtimeapi.PodSandboxConfig{
- Metadata: &runtimeapi.PodSandboxMetadata{
- Name: s.GetDesc().Name,
- Uid: s.GetId(),
- Namespace: s.GetDesc().TenantId,
- Attempt: 1,
- },
- Hostname: s.GetDesc().Hostname,
- LogDirectory: s.getPodLogDir(),
- DnsConfig: nil,
- PortMappings: nil,
- Labels: map[string]string{
- runtime.PodUIDLabel: s.GetId(),
- },
- Annotations: nil,
- Linux: &runtimeapi.LinuxPodSandboxConfig{
- CgroupParent: PodCgroupParent(),
- SecurityContext: &runtimeapi.LinuxSandboxSecurityContext{
- NamespaceOptions: s.namespacesForPod(podInput),
- SelinuxOptions: nil,
- RunAsUser: nil,
- RunAsGroup: nil,
- ReadonlyRootfs: false,
- SupplementalGroups: nil,
- Privileged: s.getPodPrivilegedMode(podInput),
- Seccomp: &runtimeapi.SecurityProfile{
- ProfileType: runtimeapi.SecurityProfile_Unconfined,
- },
- Apparmor: &runtimeapi.SecurityProfile{
- ProfileType: runtimeapi.SecurityProfile_Unconfined,
- },
- SeccompProfilePath: "",
- },
- Sysctls: nil,
- },
- Windows: nil,
- }
- // inject pod security context
- podSec := podInput.SecurityContext
- if podSec != nil {
- /*podCfg.Linux.Sysctls = map[string]string{
- "net.ipv4.ip_unprivileged_port_start": "80",
- }*/
- if podSec.RunAsUser != nil {
- podCfg.Linux.SecurityContext.RunAsUser = &runtimeapi.Int64Value{
- Value: *podSec.RunAsUser,
- }
- }
- if podSec.RunAsGroup != nil {
- podCfg.Linux.SecurityContext.RunAsGroup = &runtimeapi.Int64Value{
- Value: *podSec.RunAsGroup,
- }
- }
- }
- if options.HostOptions.EnableContainerCniPortmap {
- metaPms, err := s.GetPortMappings()
- if err != nil {
- return nil, errors.Wrap(err, "GetPortMappings")
- }
- if len(metaPms) != 0 {
- pms := make([]*runtimeapi.PortMapping, len(metaPms))
- for idx := range metaPms {
- pm := metaPms[idx]
- proto := runtimeapi.Protocol_TCP
- switch pm.Protocol {
- case computeapi.PodPortMappingProtocolTCP:
- proto = runtimeapi.Protocol_TCP
- case computeapi.PodPortMappingProtocolUDP:
- proto = runtimeapi.Protocol_UDP
- }
- pms[idx] = &runtimeapi.PortMapping{
- Protocol: proto,
- ContainerPort: int32(pm.Port),
- HostPort: int32(*pm.HostPort),
- HostIp: pm.HostIp,
- }
- }
- podCfg.PortMappings = pms
- }
- }
- criId, err := s.getCRI().RunPod(ctx, podCfg, "")
- if err != nil {
- return nil, errors.Wrap(err, "cri.RunPod")
- }
- if err := s.setCRIInfo(ctx, userCred, criId, podCfg); err != nil {
- return nil, errors.Wrap(err, "setCRIId")
- }
- // set pod cgroup resources
- if err := s.setPodCgroupResources(criId, s.GetDesc().Mem, s.GetDesc().Cpu); err != nil {
- return nil, errors.Wrapf(err, "set pod %s cgroup memMB %d, cpu %d", criId, s.GetDesc().Mem, s.GetDesc().Cpu)
- }
- s.getProbeManager().AddPod(s)
- if err := s.startStat.CreatePodFile(); err != nil {
- return nil, errors.Wrap(err, "startStat.CreatePodFile")
- }
- return &computeapi.PodStartResponse{
- CRIId: criId,
- IsRunning: false,
- }, nil
- }
- func (s *sPodGuestInstance) setPodCgroupResources(criId string, memMB int64, cpuCnt int64) error {
- if err := s.getCGUtil().SetMemoryLimitBytes(criId, memMB*1024*1024); err != nil {
- return errors.Wrap(err, "set cgroup memory limit")
- }
- if err := s.getCGUtil().SetCPUCfs(criId, cpuCnt*s.getDefaultCPUPeriod(), s.getDefaultCPUPeriod()); err != nil {
- return errors.Wrap(err, "set cgroup cfs")
- }
- return nil
- }
- func (s *sPodGuestInstance) ensurePodRemoved(ctx context.Context, timeout int64) error {
- if timeout == 0 {
- timeout = 15
- }
- ctx, cancel := context.WithTimeout(ctx, time.Duration(timeout)*time.Second)
- defer cancel()
- /*if err := s.getCRI().StopPod(ctx, &runtimeapi.StopPodSandboxRequest{
- PodSandboxId: s.GetCRIId(),
- }); err != nil {
- return errors.Wrapf(err, "stop cri pod: %s", s.GetCRIId())
- }*/
- criId := s.GetCRIId()
- if criId != "" {
- if err := s.getCRI().RemovePod(ctx, s.GetCRIId()); err != nil {
- return errors.Wrapf(err, "remove cri pod: %s", s.GetCRIId())
- }
- }
- p, _ := s.getPod(ctx)
- if p != nil {
- if err := s.getCRI().RemovePod(ctx, p.GetId()); err != nil {
- return errors.Wrapf(err, "remove cri pod: %s", p.GetId())
- }
- }
- s.getProbeManager().RemovePod(s)
- if err := s.startStat.RemovePodFile(); err != nil {
- return errors.Wrap(err, "startStat.RemovePodFile")
- }
- return nil
- }
- func (s *sPodGuestInstance) stopPod(ctx context.Context, timeout int64) error {
- if err := s.umountPodVolumes(); err != nil {
- return errors.Wrapf(err, "umount pod volumes")
- }
- if timeout == 0 {
- timeout = 15
- }
- if err := s.ensurePodRemoved(ctx, timeout); err != nil {
- return err
- }
- ReleaseGuestCpuset(s.manager, s)
- if err := s.postStopCleanup(ctx); err != nil {
- return errors.Wrapf(err, "post stop cleanup")
- }
- return nil
- }
- func (s *sPodGuestInstance) postStopCleanup(ctx context.Context) error {
- config, err := s.getPostStopCleanupConfig()
- if err != nil {
- return errors.Wrapf(err, "get post stop cleanup config")
- }
- if config == nil {
- return nil
- }
- for _, dir := range config.Dirs {
- if err := os.RemoveAll(dir); err != nil {
- return errors.Wrapf(err, "remove dir %s", dir)
- }
- }
- return nil
- }
- func (s *sPodGuestInstance) LoadDesc() error {
- if err := LoadDesc(s); err != nil {
- return errors.Wrap(err, "LoadDesc")
- }
- if err := s.loadContainers(); err != nil {
- return errors.Wrap(err, "loadContainers")
- }
- return nil
- }
- func (s *sPodGuestInstance) loadContainers() error {
- s.containers = make(map[string]*sContainer)
- ctrFile := s.getContainersFilePath()
- if !fileutils2.Exists(ctrFile) {
- log.Warningf("pod %s containers file %s doesn't exist", s.Id, ctrFile)
- return nil
- }
- ctrStr, err := ioutil.ReadFile(ctrFile)
- if err != nil {
- return errors.Wrapf(err, "read %s", ctrFile)
- }
- obj, err := jsonutils.Parse(ctrStr)
- if err != nil {
- return errors.Wrapf(err, "jsonutils.Parse %s", ctrStr)
- }
- ctrs := make(map[string]*sContainer)
- if err := obj.Unmarshal(ctrs); err != nil {
- return errors.Wrapf(err, "unmarshal %s to container map", obj.String())
- }
- s.containers = ctrs
- return nil
- }
- func (s *sPodGuestInstance) PostLoad(m *SGuestManager) error {
- return LoadGuestCpuset(m, s)
- }
- func (s *sPodGuestInstance) SyncConfig(ctx context.Context, guestDesc *desc.SGuestDesc, fwOnly, setUefiBootOrder bool) (jsonutils.JSONObject, error) {
- if err := SaveDesc(s, guestDesc); err != nil {
- return nil, errors.Wrap(err, "SaveDesc")
- }
- // update guest live desc, don't be here update cpu and mem
- // cpu and memory should update from SGuestHotplugCpuMemTask
- s.UpdateLiveDesc(guestDesc)
- // keep origin cpu numa pin
- cpuNumaPin := s.Desc.CpuNumaPin
- s.Desc.SGuestHardwareDesc = guestDesc.SGuestHardwareDesc
- s.Desc.SGuestContainerDesc = guestDesc.SGuestContainerDesc
- s.Desc.CpuNumaPin = cpuNumaPin
- if err := SaveLiveDesc(s, s.Desc); err != nil {
- return nil, errors.Wrap(err, "SaveLiveDesc")
- }
- return nil, nil
- }
- func (s *sPodGuestInstance) getContainerMeta(id string) *sContainer {
- return s.containers[id]
- }
- func (s *sPodGuestInstance) getContainerCRIId(ctrId string) (string, error) {
- ctr := s.getContainerMeta(ctrId)
- if ctr == nil {
- return "", errors.Wrapf(errors.ErrNotFound, "Not found container %s", ctrId)
- }
- return ctr.CRIId, nil
- }
- func (s *sPodGuestInstance) GetContainerByCRIId(criId string) (*hostapi.ContainerDesc, error) {
- for _, ctr := range s.containers {
- if ctr.CRIId == criId {
- desc := s.GetContainerById(ctr.Id)
- if desc == nil {
- return nil, errors.Wrapf(errors.ErrNotFound, "Not found container desc by CRIId %s", criId)
- }
- return desc, nil
- }
- }
- return nil, errors.Wrapf(errors.ErrNotFound, "Not found container by CRIId %s", criId)
- }
- func (s *sPodGuestInstance) StartLocalContainer(ctx context.Context, userCred mcclient.TokenCredential, ctrId string) (jsonutils.JSONObject, error) {
- ctr := s.GetContainerById(ctrId)
- if ctr == nil {
- return nil, errors.Wrapf(errors.ErrNotFound, "Not found container %s", ctrId)
- }
- input := &hostapi.ContainerCreateInput{
- Name: ctr.Name,
- GuestId: s.GetId(),
- Spec: ctr.Spec,
- RestartCount: ctr.RestartCount + 1,
- }
- ret, err := s.StartContainer(ctx, userCred, ctrId, input)
- if err != nil {
- return nil, errors.Wrap(err, "start container")
- }
- return ret, nil
- }
- func (s *sPodGuestInstance) StartContainer(ctx context.Context, userCred mcclient.TokenCredential, ctrId string, input *hostapi.ContainerCreateInput) (jsonutils.JSONObject, error) {
- _, hasCtr := s.containers[ctrId]
- needRecreate := false
- if hasCtr {
- status, _, err := s.getContainerStatus(ctx, ctrId)
- if err != nil {
- if IsContainerNotFoundError(err) {
- needRecreate = true
- } else {
- return nil, errors.Wrap(err, "get container status")
- }
- } else {
- if computeapi.ContainerExitedStatus.Has(status) {
- needRecreate = true
- } else if status != computeapi.CONTAINER_STATUS_CREATED {
- return nil, errors.Errorf("can't start container when status is %s", status)
- }
- }
- }
- if err := s.clearContainerRootFs(ctrId, input.Spec.Rootfs); err != nil {
- return nil, errors.Wrapf(err, "clear container rootfs %s before starting", jsonutils.Marshal(input.Spec.Rootfs))
- }
- if !hasCtr || needRecreate {
- log.Infof("recreate container %s before starting. hasCtr: %v, needRecreate: %v", ctrId, hasCtr, needRecreate)
- // delete and recreate the container before starting
- if hasCtr {
- if _, err := s.DeleteContainer(ctx, userCred, ctrId); err != nil {
- return nil, errors.Wrap(err, "delete container before starting")
- }
- }
- if _, err := s.CreateContainer(ctx, userCred, ctrId, input); err != nil {
- return nil, errors.Wrap(err, "recreate container before starting")
- }
- }
- criId, err := s.getContainerCRIId(ctrId)
- if err != nil {
- return nil, errors.Wrap(err, "get container cri id")
- }
- if err := s.expectedStatus.SetContainerStatus(criId, ctrId, computeapi.CONTAINER_STATUS_RUNNING); err != nil {
- log.Warningf("set container %s(%s) expected status to running: %v", criId, ctrId, err)
- }
- if err := s.getCRI().StartContainer(ctx, criId); err != nil {
- return nil, errors.Wrap(err, "CRI.StartContainer")
- }
- // 如果是 cgroup v2,设备规则已经通过 containerd API 在 CreateContainer 时设置,跳过 eBPF 方式
- // 如果是 cgroup v1,继续使用原有的 eBPF 方式
- isV2, err := podutil.DetectCgroupVersion()
- if err != nil {
- log.Warningf("[StartContainer] Failed to detect cgroup version: %v, using eBPF device allow", err)
- isV2 = false
- }
- if !isV2 {
- // cgroup v1 场景,使用原有的 eBPF 方式
- if err := s.setContainerCgroupDevicesAllow(criId, input.Spec.CgroupDevicesAllow, input.Spec.Devices); err != nil {
- return nil, errors.Wrap(err, "set cgroup devices allow")
- }
- } else {
- log.Debugf("[StartContainer] cgroup v2 detected, skipping eBPF device allow (devices already set via containerd API)")
- }
- if input.Spec.CgroupPidsMax > 0 {
- if err := s.getCGUtil().SetPidsMax(criId, input.Spec.CgroupPidsMax); err != nil {
- return nil, errors.Wrap(err, "set cgroup pids.max")
- }
- }
- if err := s.doContainerStartPostLifecycle(ctx, criId, input); err != nil {
- return nil, errors.Wrap(err, "do container lifecycle")
- }
- if err := s.startStat.CreateContainerFile(ctrId); err != nil {
- return nil, errors.Wrapf(err, "create container startup stat file %s", ctrId)
- }
- if input.Spec.ResourcesLimit != nil {
- if err := s.setContainerResourcesLimit(criId, input.Spec.ResourcesLimit); err != nil {
- return nil, errors.Wrap(err, "set container resources limit")
- }
- }
- return nil, nil
- }
- func (s *sPodGuestInstance) allocateCpuNumaPin() error {
- if len(s.Desc.CpuNumaPin) != 0 || len(s.Desc.VcpuPin) != 0 {
- return nil
- }
- if scpuset, ok := s.Desc.Metadata[computeapi.VM_METADATA_CGROUP_CPUSET]; ok {
- cpusetJson, err := jsonutils.ParseString(scpuset)
- if err != nil {
- log.Errorf("failed parse server %s cpuset %s: %s", s.Id, scpuset, err)
- return errors.Errorf("failed parse server %s cpuset %s: %s", s.Id, scpuset, err)
- }
- input := new(computeapi.ServerCPUSetInput)
- err = cpusetJson.Unmarshal(input)
- if err != nil {
- log.Errorf("failed unmarshal server %s cpuset %s", s.Id, err)
- return errors.Errorf("failed unmarshal server %s cpuset %s", s.Id, err)
- }
- cpus := input.CPUS
- s.Desc.VcpuPin = []desc.SCpuPin{
- {
- Vcpus: fmt.Sprintf("0-%d", s.Desc.Cpu-1),
- Pcpus: cpuset.NewCPUSet(cpus...).String(),
- },
- }
- return nil
- }
- var cpus = make([]int, 0)
- var preferNumaNodes = make([]int8, 0)
- for i := range s.Desc.IsolatedDevices {
- if s.Desc.IsolatedDevices[i].NumaNode >= 0 {
- preferNumaNodes = append(preferNumaNodes, s.Desc.IsolatedDevices[i].NumaNode)
- break
- }
- }
- log.Infof("guest %s prefer nodes %v", s.Id, preferNumaNodes)
- nodeNumaCpus, err := s.manager.cpuSet.AllocCpuset(int(s.Desc.Cpu), s.Desc.Mem*1024, preferNumaNodes, s.GetId())
- if err != nil {
- return err
- }
- for _, numaCpus := range nodeNumaCpus {
- cpus = append(cpus, numaCpus.Cpuset...)
- }
- if !s.manager.hostagentNumaAllocate {
- s.Desc.VcpuPin = []desc.SCpuPin{
- {
- Vcpus: fmt.Sprintf("0-%d", s.Desc.Cpu-1),
- Pcpus: cpuset.NewCPUSet(cpus...).String(),
- },
- }
- } else {
- var cpuNumaPin = make([]*desc.SCpuNumaPin, 0)
- for nodeId, numaCpus := range nodeNumaCpus {
- if s.manager.hostagentNumaAllocate {
- unodeId := uint16(nodeId)
- vcpuPin := make([]desc.SVCpuPin, len(numaCpus.Cpuset))
- for i := range numaCpus.Cpuset {
- vcpuPin[i].Pcpu = numaCpus.Cpuset[i]
- if i < int(s.Desc.Cpu) {
- vcpuPin[i].Vcpu = i
- } else {
- vcpuPin[i].Vcpu = -1
- }
- }
- memPin := &desc.SCpuNumaPin{
- SizeMB: numaCpus.MemSizeKB / 1024, // MB
- NodeId: &unodeId,
- VcpuPin: vcpuPin,
- Unregular: numaCpus.Unregular,
- }
- cpuNumaPin = append(cpuNumaPin, memPin)
- }
- }
- s.Desc.CpuNumaPin = cpuNumaPin
- }
- return SaveLiveDesc(s, s.Desc)
- }
- func (s *sPodGuestInstance) doContainerStartPostLifecycle(ctx context.Context, criId string, input *hostapi.ContainerCreateInput) error {
- ls := input.Spec.Lifecyle
- if ls == nil {
- return nil
- }
- if ls.PostStart == nil {
- return nil
- }
- drv := lifecycle.GetDriver(ls.PostStart.Type)
- if err := drv.Run(ctx, ls.PostStart, s.getCRI(), criId); err != nil {
- return errors.Wrapf(err, "run %s", ls.PostStart.Type)
- }
- return nil
- }
- func (s *sPodGuestInstance) StopAll(ctx context.Context) error {
- ctrs := s.GetContainers()
- userCred := hostutils.GetComputeSession(ctx).GetToken()
- errs := []error{}
- for _, ctr := range ctrs {
- if _, err := s.StopContainer(ctx, userCred, ctr.Id, &hostapi.ContainerStopInput{}); err != nil {
- errs = append(errs, errors.Wrapf(err, "failed to stop container %s", ctr.Id))
- }
- }
- err := errors.NewAggregate(errs)
- if err != nil {
- return err
- }
- if err := s.stopPod(ctx, 5); err != nil {
- return errors.Wrapf(err, "stop pod %s", s.GetName())
- }
- return nil
- }
- func (s *sPodGuestInstance) StopContainer(ctx context.Context, userCred mcclient.TokenCredential, ctrId string, input *hostapi.ContainerStopInput) (jsonutils.JSONObject, error) {
- criId, err := s.getContainerCRIId(ctrId)
- if err != nil {
- if errors.Cause(err) == errors.ErrNotFound {
- // cri id not found, should already stopped
- return nil, nil
- }
- return nil, errors.Wrap(err, "get container cri id")
- }
- var timeout int64 = 0
- s.expectedStatus.SetContainerStatus(criId, ctrId, computeapi.CONTAINER_STATUS_EXITED)
- if input.Timeout != 0 {
- timeout = input.Timeout
- }
- shmSizeMB := input.ShmSizeMB
- if shmSizeMB > 64 {
- name := input.ContainerName
- if name == "" {
- return nil, errors.Wrapf(errors.ErrNotFound, "not found container_name from input: %s", jsonutils.Marshal(input))
- }
- if err := s.unmountDevShm(name); err != nil {
- return nil, errors.Wrapf(err, "unmount shm %s", name)
- }
- }
- if err := s.getCRI().StopContainer(ctx, criId, timeout, true, input.Force); err != nil {
- if !IsContainerNotFoundError(err) {
- return nil, errors.Wrap(err, "CRI.StopContainer")
- } else {
- log.Warningf("CRI.StopContainer %s not found", criId)
- }
- }
- if input.Force {
- // FIXME: Sleep 2s 等待 pleg.PodLifecycleEventGenerator 刷新
- // 后期可以添加主动通知刷新
- time.Sleep(2 * time.Second)
- }
- if err := s.startStat.RemoveContainerFile(ctrId); err != nil {
- return nil, errors.Wrap(err, "startStat.RemoveContainerFile")
- }
- return nil, nil
- }
- func (s *sPodGuestInstance) GetCRIId() string {
- return s.GetSourceDesc().Metadata[computeapi.POD_METADATA_CRI_ID]
- }
- func (s *sPodGuestInstance) convertToPodMetadataPortMappings(pms []*runtimeapi.PortMapping) []*computeapi.PodMetadataPortMapping {
- ret := make([]*computeapi.PodMetadataPortMapping, len(pms))
- for idx := range pms {
- pm := pms[idx]
- var proto computeapi.PodPortMappingProtocol = computeapi.PodPortMappingProtocolTCP
- if pm.Protocol == runtimeapi.Protocol_UDP {
- proto = computeapi.PodPortMappingProtocolUDP
- }
- ret[idx] = &computeapi.PodMetadataPortMapping{
- Protocol: proto,
- ContainerPort: pm.ContainerPort,
- HostPort: pm.HostPort,
- HostIp: pm.HostIp,
- }
- }
- return ret
- }
- func (s *sPodGuestInstance) setPortMappings(ctx context.Context, userCred mcclient.TokenCredential, pms []*computeapi.PodMetadataPortMapping) error {
- pmStr := jsonutils.Marshal(pms).String()
- s.Desc.Metadata[computeapi.POD_METADATA_PORT_MAPPINGS] = pmStr
- session := auth.GetSession(ctx, userCred, options.HostOptions.Region)
- if _, err := computemod.Servers.SetMetadata(session, s.GetId(), jsonutils.Marshal(map[string]string{
- computeapi.POD_METADATA_PORT_MAPPINGS: pmStr,
- })); err != nil {
- return errors.Wrapf(err, "set cri_id of pod %s", s.GetId())
- }
- return SaveDesc(s, s.Desc)
- }
- func (s *sPodGuestInstance) setCRIInfo(ctx context.Context, userCred mcclient.TokenCredential, criId string, cfg *runtimeapi.PodSandboxConfig) error {
- s.Desc.Metadata[computeapi.POD_METADATA_CRI_ID] = criId
- cfgStr := jsonutils.Marshal(cfg).String()
- s.Desc.Metadata[computeapi.POD_METADATA_CRI_CONFIG] = cfgStr
- session := auth.GetSession(ctx, userCred, options.HostOptions.Region)
- if _, err := computemod.Servers.SetMetadata(session, s.GetId(), jsonutils.Marshal(map[string]string{
- computeapi.POD_METADATA_CRI_ID: criId,
- computeapi.POD_METADATA_CRI_CONFIG: cfgStr,
- })); err != nil {
- return errors.Wrapf(err, "set cri_id of pod %s", s.GetId())
- }
- return SaveDesc(s, s.Desc)
- }
- func (s *sPodGuestInstance) setContainerCRIInfo(ctx context.Context, userCred mcclient.TokenCredential, ctrId, criId string) error {
- session := auth.GetSession(ctx, userCred, options.HostOptions.Region)
- if _, err := computemod.Containers.SetMetadata(session, ctrId, jsonutils.Marshal(map[string]string{
- computeapi.CONTAINER_METADATA_CRI_ID: criId,
- })); err != nil {
- return errors.Wrapf(err, "set cri_id of container %s", ctrId)
- }
- return nil
- }
- func (s *sPodGuestInstance) getPodSandboxConfig() (*runtimeapi.PodSandboxConfig, error) {
- cfgStr := s.GetSourceDesc().Metadata[computeapi.POD_METADATA_CRI_CONFIG]
- obj, err := jsonutils.ParseString(cfgStr)
- if err != nil {
- return nil, errors.Wrapf(err, "ParseString to json object: %s", cfgStr)
- }
- podCfg := new(runtimeapi.PodSandboxConfig)
- if err := obj.Unmarshal(podCfg); err != nil {
- return nil, errors.Wrap(err, "Unmarshal to PodSandboxConfig")
- }
- return podCfg, nil
- }
- func (s *sPodGuestInstance) GetPortMappings() (computeapi.GuestPortMappings, error) {
- srcDesc := s.GetSourceDesc()
- nics := srcDesc.Nics
- pms := make([]*computeapi.GuestPortMapping, 0)
- for _, nic := range nics {
- for _, pm := range nic.PortMappings {
- tmpPm := pm
- pms = append(pms, tmpPm)
- }
- }
- return pms, nil
- }
- func (s *sPodGuestInstance) saveContainer(id string, criId string) error {
- s.saveContainerLock.Lock()
- defer s.saveContainerLock.Unlock()
- _, ok := s.containers[id]
- if ok {
- return errors.Errorf("container %s already exists", criId)
- }
- ctr := newContainer(id)
- ctr.CRIId = criId
- s.containers[id] = ctr
- if err := s.saveContainersFile(s.containers); err != nil {
- return errors.Wrap(err, "saveContainersFile")
- }
- return nil
- }
- func (s *sPodGuestInstance) saveContainersFile(containers map[string]*sContainer) error {
- content := jsonutils.Marshal(containers).String()
- if err := fileutils2.FilePutContents(s.getContainersFilePath(), content, false); err != nil {
- return errors.Wrapf(err, "put content %s to containers file", content)
- }
- return nil
- }
- func (s *sPodGuestInstance) getContainersFilePath() string {
- return path.Join(s.HomeDir(), "containers")
- }
- func (s *sPodGuestInstance) CreateContainer(ctx context.Context, userCred mcclient.TokenCredential, id string, input *hostapi.ContainerCreateInput) (jsonutils.JSONObject, error) {
- // always pull image for checking
- imgInput := &hostapi.ContainerPullImageInput{
- Image: input.Spec.Image,
- PullPolicy: input.Spec.ImagePullPolicy,
- }
- if input.Spec.ImageCredentialToken != "" {
- tokenJson, err := base64.StdEncoding.DecodeString(input.Spec.ImageCredentialToken)
- if err != nil {
- return nil, errors.Wrapf(err, "base64 decode image credential token %s", input.Spec.ImageCredentialToken)
- }
- authObj, err := jsonutils.Parse(tokenJson)
- if err != nil {
- return nil, errors.Wrapf(err, "parse image credential token %s", input.Spec.ImageCredentialToken)
- }
- imgAuth := new(apis.ContainerPullImageAuthConfig)
- if err := authObj.Unmarshal(imgAuth); err != nil {
- return nil, errors.Wrapf(err, "unmarshal image credential token: %s", authObj)
- }
- imgInput.Auth = imgAuth
- }
- if _, err := s.PullImage(ctx, userCred, id, imgInput); err != nil {
- return nil, errors.Wrapf(err, "pull image %s", input.Spec.Image)
- }
- pod, err := s.getPod(ctx)
- if err != nil {
- return nil, errors.Wrap(err, "get pod")
- }
- ctrCriId, err := s.createContainer(ctx, userCred, pod, id, input)
- if err != nil {
- return nil, errors.Wrap(err, "CRI.CreateContainer")
- }
- // 如果是 cgroup v2,通过 containerd API 更新 container spec 中的 devices
- isV2, err := podutil.DetectCgroupVersion()
- if err != nil {
- log.Warningf("[CreateContainer] Failed to detect cgroup version: %v, skipping containerd device update", err)
- } else if isV2 {
- // 将设备规则转换为 specs.LinuxDeviceCgroup
- specDevices, err := podutil.ConvertDeviceRulesToSpecsDevices(input.Spec.CgroupDevicesAllow)
- if err != nil {
- log.Warningf("[CreateContainer] Failed to convert device rules to specs devices: %v, skipping containerd device update", err)
- } else if len(specDevices) > 0 {
- if err := s.updateContainerDevicesViaContainerd(ctx, ctrCriId, specDevices); err != nil {
- log.Warningf("[CreateContainer] Failed to update container devices via containerd API: %v (container created but devices may not be accessible)", err)
- // 不返回错误,因为容器已经创建成功
- }
- }
- }
- if err := s.setContainerCRIInfo(ctx, userCred, id, ctrCriId); err != nil {
- return nil, errors.Wrap(err, "setContainerCRIInfo")
- }
- return nil, nil
- }
- func (s *sPodGuestInstance) getLxcfsMounts() []*runtimeapi.Mount {
- // lxcfsPath := "/var/lib/lxc/lxcfs"
- lxcfsPath := options.HostOptions.LxcfsPath
- const (
- procCpuinfo = "/proc/cpuinfo"
- procDiskstats = "/proc/diskstats"
- procMeminfo = "/proc/meminfo"
- procStat = "/proc/stat"
- procSwaps = "/proc/swaps"
- procUptime = "/proc/uptime"
- )
- newLxcfsMount := func(fp string) *runtimeapi.Mount {
- return &runtimeapi.Mount{
- ContainerPath: fp,
- HostPath: fmt.Sprintf("%s%s", lxcfsPath, fp),
- }
- }
- return []*runtimeapi.Mount{
- newLxcfsMount(procUptime),
- newLxcfsMount(procMeminfo),
- newLxcfsMount(procStat),
- newLxcfsMount(procCpuinfo),
- newLxcfsMount(procSwaps),
- newLxcfsMount(procDiskstats),
- }
- }
- func (s *sPodGuestInstance) getContainerMounts(ctrId string, input *hostapi.ContainerCreateInput) ([]*runtimeapi.Mount, error) {
- inputMounts := input.Spec.VolumeMounts
- if len(inputMounts) == 0 {
- return make([]*runtimeapi.Mount, 0), nil
- }
- mounts := make([]*runtimeapi.Mount, len(inputMounts))
- for idx, im := range inputMounts {
- mnt := &runtimeapi.Mount{
- ContainerPath: im.MountPath,
- Readonly: im.ReadOnly,
- SelinuxRelabel: im.SelinuxRelabel,
- Propagation: volume_mount.GetRuntimeVolumeMountPropagation(im.Propagation),
- }
- hostPath, err := volume_mount.GetDriver(im.Type).GetRuntimeMountHostPath(s, ctrId, im)
- if err != nil {
- return nil, errors.Wrapf(err, "get runtime host mount path of %s", jsonutils.Marshal(im))
- }
- mnt.HostPath = hostPath
- mounts[idx] = mnt
- }
- return mounts, nil
- }
- func (s *sPodGuestInstance) getCGUtil() podutil.CgroupUtil {
- cgUtil, err := podutil.NewPodCgroupUtil(PodCgroupParent())
- if err != nil {
- // 如果检测失败,记录错误并使用默认的 v1 实现
- log.Errorf("failed to detect cgroup version, fallback to v1: %s", err)
- return podutil.NewPodCgroupV1Util(PodCgroupParent())
- }
- return cgUtil
- }
- // updateContainerDevicesViaContainerd 通过 containerd API 更新 container spec 中的 devices
- // 用于 cgroup v2 场景
- func (s *sPodGuestInstance) updateContainerDevicesViaContainerd(ctx context.Context, criId string, devices []*specs.LinuxDeviceCgroup) error {
- addr, namespace := GetContainerdConnectionInfo()
- // 创建 containerd client
- client, err := containerdutil.NewClient(ctx, addr, namespace)
- if err != nil {
- return errors.Wrap(err, "create containerd client")
- }
- defer client.Close()
- // 更新 container devices
- return containerdutil.UpdateContainerDevices(ctx, client, criId, devices)
- }
- func (s *sPodGuestInstance) setContainerCgroupDevicesAllow(ctrId string, allowStrs []string, devices []*hostapi.ContainerDevice) error {
- // 自动从容器设备配置中提取设备号并添加到允许列表
- allowSet := make(map[string]bool)
- for _, rule := range allowStrs {
- allowSet[rule] = true
- }
- // 遍历容器设备,提取设备路径并生成设备规则
- for _, dev := range devices {
- var devicePath string
- var permissions string = "rwm" // 默认权限
- // 获取设备路径和权限
- if dev.Host != nil && dev.Host.HostPath != "" {
- devicePath = dev.Host.HostPath
- if dev.Permissions != "" {
- permissions = dev.Permissions
- }
- } else if dev.IsolatedDevice != nil {
- // 对于 IsolatedDevice,优先使用 RenderPath,然后是 Path
- if dev.IsolatedDevice.RenderPath != "" {
- devicePath = dev.IsolatedDevice.RenderPath
- } else if dev.IsolatedDevice.Path != "" {
- devicePath = dev.IsolatedDevice.Path
- } else if dev.IsolatedDevice.CardPath != "" {
- devicePath = dev.IsolatedDevice.CardPath
- }
- if dev.Permissions != "" {
- permissions = dev.Permissions
- }
- } else {
- log.Debugf("[setContainerCgroupDevicesAllow] Skipping device %v (no Host or IsolatedDevice path)", dev)
- continue
- }
- if devicePath == "" {
- log.Debugf("[setContainerCgroupDevicesAllow] Skipping device %v (no device path found)", dev)
- continue
- }
- // 从设备路径获取设备号并生成设备规则
- rule, err := podutil.GetDeviceAllowRuleFromPath(devicePath, permissions)
- if err != nil {
- log.Warningf("[setContainerCgroupDevicesAllow] Failed to get device rule from path %s: %v (skipping)", devicePath, err)
- continue
- }
- // 添加到允许列表(去重)
- if !allowSet[rule] {
- allowStrs = append(allowStrs, rule)
- allowSet[rule] = true
- log.Infof("[setContainerCgroupDevicesAllow] Auto-added device rule: %s (from device path: %s)", rule, devicePath)
- }
- }
- return s.getCGUtil().SetDevicesAllow(ctrId, allowStrs)
- }
- func (s *sPodGuestInstance) SetContainerResourceLimit(ctrId string, limit *apis.ContainerResources) (jsonutils.JSONObject, error) {
- criId, err := s.getContainerCRIId(ctrId)
- if err != nil {
- return nil, errors.Wrap(err, "get container cri id")
- }
- return nil, s.setContainerResourcesLimit(criId, limit)
- }
- func (s *sPodGuestInstance) setContainerResourcesLimit(ctrId string, limit *apis.ContainerResources) error {
- cgUtil := s.getCGUtil()
- /*if limit.MemoryLimitMB != nil {
- if err := cgUtil.SetMemoryLimitBytes(ctrId, *limit.MemoryLimitMB*1024*1024); err != nil {
- return errors.Wrapf(err, "set memory limit to %d MB", *limit.MemoryLimitMB)
- }
- }*/
- if limit.CpuCfsQuota != nil {
- cpuCfsQuotaUs := *limit.CpuCfsQuota * float64(s.getDefaultCPUPeriod())
- if err := cgUtil.SetCPUCfs(ctrId, int64(cpuCfsQuotaUs), s.getDefaultCPUPeriod()); err != nil {
- return errors.Wrapf(err, "set cpu cfs quota to %d", int64(cpuCfsQuotaUs))
- }
- }
- if limit.PidsMax != nil {
- if err := cgUtil.SetPidsMax(ctrId, *limit.PidsMax); err != nil {
- return errors.Wrapf(err, "set pids.max to %d", *limit.PidsMax)
- }
- }
- if len(limit.DevicesAllow) != 0 {
- if err := cgUtil.SetDevicesAllow(ctrId, limit.DevicesAllow); err != nil {
- return errors.Wrapf(err, "set devices.allow %v", limit.DevicesAllow)
- }
- }
- if limit.CpusetCloneChildren {
- if err := cgUtil.SetCpusetCloneChildren(ctrId); err != nil {
- return errors.Wrapf(err, "set cpuset clone_children")
- }
- }
- if limit.MemoryHighRatio != nil {
- memHigh := int64(*limit.MemoryHighRatio * float64(s.GetDesc().Mem*1024*1024))
- if err := cgUtil.SetCgroupKeyValue(ctrId, podutil.CgroupControllerMemory, "memory.high", fmt.Sprintf("%d", memHigh)); err != nil {
- return errors.Wrapf(err, "set memory.high to %d", memHigh)
- }
- }
- return nil
- }
- func (s *sPodGuestInstance) getDefaultCPUPeriod() int64 {
- return 100000
- }
- func (s *sPodGuestInstance) createContainer(ctx context.Context, userCred mcclient.TokenCredential, sandbox *runtimeapi.PodSandbox, ctrId string, input *hostapi.ContainerCreateInput) (string, error) {
- podCfg, err := s.getPodSandboxConfig()
- if err != nil {
- return "", errors.Wrap(err, "getPodSandboxConfig")
- }
- spec := input.Spec
- mounts, err := s.getContainerMounts(ctrId, input)
- if err != nil {
- return "", errors.Wrap(err, "get container mounts")
- }
- if spec.SimulateCpu {
- systemCpuMounts, err := s.simulateContainerSystemCpu(ctx, ctrId)
- if err != nil {
- return "", errors.Wrapf(err, "simulate container system cpu")
- }
- newMounts := systemCpuMounts
- newMounts = append(newMounts, mounts...)
- mounts = newMounts
- }
- // process shm size
- if spec.ShmSizeMB > 64 {
- // mount empty dir
- shmPath, err := s.mountDevShm(input, spec.ShmSizeMB)
- if err != nil {
- return "", errors.Wrapf(err, "mount dev shm")
- }
- mounts = append(mounts, &runtimeapi.Mount{
- ContainerPath: "/dev/shm",
- HostPath: shmPath,
- })
- }
- // inject /etc/hosts to hide host storage
- if spec.Rootfs != nil {
- if etcFilesMount, err := s.getEtcFilesMount(ctrId); err != nil {
- return "", errors.Wrapf(err, "get etc hosts mount")
- } else {
- mounts = append(mounts, etcFilesMount...)
- }
- }
- var cpuSetCpus string
- var cpuSetMems string
- var extraCpuCount int
- {
- cpuSets := sets.NewString()
- cpuMemSets := sets.NewString()
- if len(s.Desc.CpuNumaPin) > 0 {
- for _, cpuNumaPin := range s.GetDesc().CpuNumaPin {
- for _, cpuPin := range cpuNumaPin.VcpuPin {
- cpuSets.Insert(fmt.Sprintf("%d", cpuPin.Pcpu))
- }
- if cpuNumaPin.NodeId != nil && cpuNumaPin.SizeMB > 0 {
- cpuMemSets.Insert(fmt.Sprintf("%d", int(*cpuNumaPin.NodeId)))
- }
- if cpuNumaPin.ExtraCpuCount > 0 {
- extraCpuCount += cpuNumaPin.ExtraCpuCount
- }
- }
- cpuSetCpus = strings.Join(cpuSets.List(), ",")
- cpuSetMems = strings.Join(cpuMemSets.List(), ",")
- } else if len(s.Desc.VcpuPin) > 0 {
- for _, vcpuPin := range s.Desc.VcpuPin {
- cpuSets.Insert(vcpuPin.Pcpus)
- }
- cpuSetCpus = strings.Join(cpuSets.List(), ",")
- }
- }
- procMountType := apis.ContainerDefaultProcMount
- if spec.SecurityContext != nil && spec.SecurityContext.ProcMount == apis.ContainerUnmaskedProcMount {
- procMountType = apis.ContainerUnmaskedProcMount
- }
- ctrCfg := &runtimeapi.ContainerConfig{
- Metadata: &runtimeapi.ContainerMetadata{
- Name: input.Name,
- Attempt: uint32(input.RestartCount),
- },
- Labels: map[string]string{
- runtime.PodNameLabel: s.GetDesc().Name,
- runtime.PodUIDLabel: s.GetId(),
- runtime.ContainerNameLabel: input.Name,
- runtime.ContainerRestartCountLabel: fmt.Sprintf("%d", input.RestartCount),
- },
- Annotations: map[string]string{
- runtime.ContainerRestartCountLabel: fmt.Sprintf("%d", input.RestartCount),
- },
- Image: &runtimeapi.ImageSpec{
- Image: spec.Image,
- },
- Linux: &runtimeapi.LinuxContainerConfig{
- Resources: &runtimeapi.LinuxContainerResources{
- // REF: https://docs.docker.com/config/containers/resource_constraints/#configure-the-default-cfs-scheduler
- CpuPeriod: s.getDefaultCPUPeriod(),
- CpuQuota: (s.GetDesc().Cpu + int64(extraCpuCount)) * s.getDefaultCPUPeriod(),
- //CpuShares: defaultCPUPeriod,
- MemoryLimitInBytes: s.GetDesc().Mem * 1024 * 1024,
- OomScoreAdj: 0,
- CpusetCpus: cpuSetCpus,
- CpusetMems: cpuSetMems,
- HugepageLimits: nil,
- Unified: nil,
- MemorySwapLimitInBytes: 0,
- },
- SecurityContext: &runtimeapi.LinuxContainerSecurityContext{
- Capabilities: &runtimeapi.Capability{},
- Privileged: spec.Privileged,
- NamespaceOptions: podCfg.Linux.SecurityContext.GetNamespaceOptions(),
- SelinuxOptions: nil,
- RunAsUser: nil,
- RunAsGroup: nil,
- RunAsUsername: "",
- ReadonlyRootfs: false,
- SupplementalGroups: nil,
- NoNewPrivs: !spec.DisableNoNewPrivs,
- MaskedPaths: podutil.GetDefaultMaskedPaths(procMountType),
- ReadonlyPaths: podutil.GetReadonlyPaths(procMountType),
- Seccomp: &runtimeapi.SecurityProfile{
- ProfileType: runtimeapi.SecurityProfile_Unconfined,
- },
- Apparmor: &runtimeapi.SecurityProfile{
- ProfileType: runtimeapi.SecurityProfile_Unconfined,
- },
- ApparmorProfile: "",
- SeccompProfilePath: "",
- },
- },
- LogPath: s.getContainerLogPath(ctrId),
- Envs: make([]*runtimeapi.KeyValue, 0),
- Devices: []*runtimeapi.Device{},
- Mounts: mounts,
- }
- // set container namespace options to target
- /*if ctrCfg.Linux.SecurityContext.NamespaceOptions.Pid == runtimeapi.NamespaceMode_CONTAINER {
- ctrCfg.Linux.SecurityContext.NamespaceOptions.Pid = runtimeapi.NamespaceMode_TARGET
- ctrCfg.Linux.SecurityContext.NamespaceOptions.TargetId = s.GetCRIId()
- }*/
- if spec.Rootfs != nil {
- ctrCfg.Labels[snapshot_service.LabelServerId] = s.GetId()
- ctrCfg.Labels[snapshot_service.LabelContainerId] = ctrId
- }
- // inherit security context
- if spec.SecurityContext != nil {
- secInput := spec.SecurityContext
- if secInput.RunAsUser != nil {
- ctrCfg.Linux.SecurityContext.RunAsUser = &runtimeapi.Int64Value{
- Value: *secInput.RunAsUser,
- }
- }
- if secInput.RunAsGroup != nil {
- ctrCfg.Linux.SecurityContext.RunAsGroup = &runtimeapi.Int64Value{
- Value: *secInput.RunAsGroup,
- }
- }
- if secInput.ApparmorProfile != "" {
- ctrCfg.Linux.SecurityContext.Apparmor = &runtimeapi.SecurityProfile{
- ProfileType: runtimeapi.SecurityProfile_Localhost,
- LocalhostRef: secInput.ApparmorProfile,
- }
- }
- }
- if spec.EnableLxcfs {
- ctrCfg.Mounts = append(ctrCfg.Mounts, s.getLxcfsMounts()...)
- }
- if spec.Capabilities != nil {
- ctrCfg.Linux.SecurityContext.Capabilities.AddCapabilities = spec.Capabilities.Add
- ctrCfg.Linux.SecurityContext.Capabilities.DropCapabilities = spec.Capabilities.Drop
- }
- envSecs := make(map[string]map[string]string, 0)
- if len(spec.SecretCredentials) > 0 {
- for credId, credData := range spec.SecretCredentials {
- obj := map[string]string{}
- credKey, err := base64.StdEncoding.DecodeString(credData)
- if err != nil {
- return "", errors.Wrapf(err, "decode secret credential %s", credId)
- }
- if err := json.Unmarshal(credKey, &obj); err != nil {
- return "", errors.Wrapf(err, "unmarshal secret credential %s", credId)
- }
- envSecs[credId] = obj
- }
- for i := range spec.Envs {
- env := spec.Envs[i]
- if env.ValueFrom == nil {
- continue
- }
- if env.ValueFrom.Credential != nil {
- credId := env.ValueFrom.Credential.Id
- if _, ok := envSecs[credId]; !ok {
- return "", errors.Wrapf(errors.ErrNotFound, "secret credential %s not found", credId)
- }
- credKey := env.ValueFrom.Credential.Key
- if _, ok := envSecs[credId][credKey]; !ok {
- return "", errors.Wrapf(errors.ErrNotFound, "secret credential %s key %s not found", credId, credKey)
- }
- env.Value = envSecs[credId][credKey]
- }
- }
- }
- for _, env := range spec.Envs {
- ctrCfg.Envs = append(ctrCfg.Envs, &runtimeapi.KeyValue{
- Key: env.Key,
- Value: env.Value,
- })
- }
- pms, err := s.GetPortMappings()
- if err != nil {
- return "", errors.Wrapf(err, "get pod port mappings")
- }
- if len(pms) != 0 {
- for _, pm := range pms {
- envKey := fmt.Sprintf("CLOUDPODS_%s_PORT_%d", strings.ToUpper(string(pm.Protocol)), pm.Port)
- envVal := fmt.Sprintf("%d", *pm.HostPort)
- ctrCfg.Envs = append(ctrCfg.Envs, &runtimeapi.KeyValue{
- Key: envKey,
- Value: envVal,
- })
- for _, pEnv := range pm.Envs {
- pEnvVal := ""
- switch pEnv.ValueFrom {
- case computeapi.GuestPortMappingEnvValueFromHostPort:
- pEnvVal = fmt.Sprintf("%d", *pm.HostPort)
- case computeapi.GuestPortMappingEnvValueFromPort:
- pEnvVal = fmt.Sprintf("%d", pm.Port)
- default:
- return "", httperrors.NewInputParameterError("invalid value from %s", pEnv.ValueFrom)
- }
- ctrCfg.Envs = append(ctrCfg.Envs, &runtimeapi.KeyValue{
- Key: pEnv.Key,
- Value: pEnvVal,
- })
- }
- }
- }
- if s.GetDesc().HostAccessIp != "" {
- ctrCfg.Envs = append(ctrCfg.Envs, &runtimeapi.KeyValue{
- Key: "CLOUDPODS_HOST_ACCESS_IP",
- Value: s.GetDesc().HostAccessIp,
- })
- }
- if s.GetDesc().HostEIP != "" {
- ctrCfg.Envs = append(ctrCfg.Envs, &runtimeapi.KeyValue{
- Key: "CLOUDPODS_HOST_EIP",
- Value: s.GetDesc().HostEIP,
- })
- }
- if len(spec.Devices) != 0 {
- devsByType := map[apis.ContainerDeviceType][]*hostapi.ContainerDevice{}
- for i := range spec.Devices {
- if devs, ok := devsByType[spec.Devices[i].Type]; ok {
- devsByType[spec.Devices[i].Type] = append(devs, spec.Devices[i])
- } else {
- devsByType[spec.Devices[i].Type] = []*hostapi.ContainerDevice{spec.Devices[i]}
- }
- }
- for cdType, devs := range devsByType {
- ctrDevs, err := device.GetDriver(cdType).GetRuntimeDevices(input, devs)
- if err != nil {
- return "", errors.Wrapf(err, "GetRuntimeDevices of %s", jsonutils.Marshal(devs))
- }
- ctrCfg.Devices = append(ctrCfg.Devices, ctrDevs...)
- }
- if err := s.getIsolatedDeviceExtraConfig(spec, ctrCfg); err != nil {
- return "", err
- }
- } else {
- if hostinfo.Instance().HasContainerNvidiaGpu() {
- ctrCfg.Envs = append(ctrCfg.Envs, &runtimeapi.KeyValue{Key: "NVIDIA_VISIBLE_DEVICES", Value: "void"})
- }
- }
- if len(spec.Command) != 0 {
- ctrCfg.Command = spec.Command
- }
- if len(spec.Args) != 0 {
- ctrCfg.Args = spec.Args
- }
- criId, err := s.getCRI().CreateContainer(ctx, sandbox.GetId(), podCfg, ctrCfg, false)
- if err != nil {
- return "", errors.Wrapf(err, "cri.CreateContainer of pod: %q", sandbox.GetId())
- }
- if err := s.saveContainer(ctrId, criId); err != nil {
- return "", errors.Wrap(err, "saveContainer")
- }
- return criId, nil
- }
- // copyEtcFile 复制主机上的 etc 文件到容器根文件系统
- func (s *sPodGuestInstance) copyEtcFile(hostPath, etcFilePath string) (*runtimeapi.Mount, error) {
- hostEtcFilePath := filepath.Join(hostPath, etcFilePath)
- // 确保目录存在
- if err := volume_mount.EnsureDir(filepath.Dir(hostEtcFilePath)); err != nil {
- return nil, errors.Wrapf(err, "ensure dir %s", filepath.Dir(hostEtcFilePath))
- }
- // 复制文件
- if err := volume_mount.CopyFile(etcFilePath, hostEtcFilePath); err != nil {
- return nil, errors.Wrapf(err, "copy file %s to %s", etcFilePath, hostEtcFilePath)
- }
- // 创建挂载点
- return &runtimeapi.Mount{
- ContainerPath: etcFilePath,
- HostPath: hostEtcFilePath,
- }, nil
- }
- // generateEtcFile 生成 etc 文件内容到容器根文件系统
- func (s *sPodGuestInstance) generateEtcFile(hostPath, etcFilePath, content string) (*runtimeapi.Mount, error) {
- hostEtcFilePath := filepath.Join(hostPath, etcFilePath)
- // 确保目录存在
- if err := volume_mount.EnsureDir(filepath.Dir(hostEtcFilePath)); err != nil {
- return nil, errors.Wrapf(err, "ensure dir %s", filepath.Dir(hostEtcFilePath))
- }
- // 生成文件内容
- if err := fileutils2.FilePutContents(hostEtcFilePath, content, false); err != nil {
- return nil, errors.Wrapf(err, "put file %s to %s", etcFilePath, hostEtcFilePath)
- }
- // 创建挂载点
- return &runtimeapi.Mount{
- ContainerPath: etcFilePath,
- HostPath: hostEtcFilePath,
- }, nil
- }
- func (s *sPodGuestInstance) getEtcFilesMount(ctrId string) ([]*runtimeapi.Mount, error) {
- hostPath, err := s.GetRootFsMountPath(ctrId)
- if err != nil {
- return nil, errors.Wrapf(err, "get container root fs path of %s", ctrId)
- }
- // 复制 /etc/hosts 文件
- etcHostsMount, err := s.copyEtcFile(hostPath, "/etc/hosts")
- if err != nil {
- return nil, errors.Wrap(err, "copy /etc/hosts")
- }
- // 生成 /etc/hostname 文件
- etcHostnameMount, err := s.generateEtcFile(hostPath, "/etc/hostname", s.GetDesc().Hostname)
- if err != nil {
- return nil, errors.Wrap(err, "generate /etc/hostname")
- }
- // 复制 /etc/resolv.conf 文件
- etcResolvConfMount, err := s.copyEtcFile(hostPath, "/etc/resolv.conf")
- if err != nil {
- return nil, errors.Wrap(err, "copy /etc/resolv.conf")
- }
- return []*runtimeapi.Mount{etcHostsMount, etcHostnameMount, etcResolvConfMount}, nil
- }
- type FilteredContainerDevices struct {
- EnvDevs []*hostapi.ContainerDevice
- CDIDevs []*hostapi.ContainerDevice
- RestDevs []*hostapi.ContainerDevice
- }
- func filterContainerIsolatedDevices(devs []*hostapi.ContainerDevice, devTypes sets.String) FilteredContainerDevices {
- envDevs := []*hostapi.ContainerDevice{}
- restDevs := []*hostapi.ContainerDevice{}
- cdiDevs := []*hostapi.ContainerDevice{}
- for i := range devs {
- dev := devs[i]
- if dev.IsolatedDevice != nil {
- devType := dev.IsolatedDevice.DeviceType
- if !devTypes.Has(devType) {
- continue
- }
- if dev.IsolatedDevice.IsCDIUsed() {
- cdiDevs = append(cdiDevs, dev)
- } else if len(dev.IsolatedDevice.OnlyEnv) > 0 {
- envDevs = append(envDevs, dev)
- } else {
- restDevs = append(restDevs, dev)
- }
- }
- }
- return FilteredContainerDevices{
- EnvDevs: envDevs,
- CDIDevs: cdiDevs,
- RestDevs: restDevs,
- }
- }
- func getEnvsFromDevices(devs []*hostapi.ContainerDevice) []*runtimeapi.KeyValue {
- retEnvs := []*runtimeapi.KeyValue{}
- for _, dev := range devs {
- if dev.IsolatedDevice == nil {
- continue
- }
- if len(dev.IsolatedDevice.OnlyEnv) == 0 {
- continue
- }
- for _, oe := range dev.IsolatedDevice.OnlyEnv {
- var tmpEnv *runtimeapi.KeyValue
- if oe.FromRenderPath {
- tmpEnv = &runtimeapi.KeyValue{
- Key: oe.Key,
- Value: dev.IsolatedDevice.RenderPath,
- }
- }
- if oe.FromIndex {
- tmpEnv = &runtimeapi.KeyValue{
- Key: oe.Key,
- Value: fmt.Sprintf("%d", dev.IsolatedDevice.Index),
- }
- }
- if oe.FromDeviceMinor {
- tmpEnv = &runtimeapi.KeyValue{
- Key: oe.Key,
- Value: fmt.Sprintf("%d", dev.IsolatedDevice.DeviceMinor),
- }
- }
- if tmpEnv != nil {
- retEnvs = append(retEnvs, tmpEnv)
- }
- }
- }
- return retEnvs
- }
- func (s *sPodGuestInstance) getIsolatedDeviceExtraConfig(spec *hostapi.ContainerSpec, ctrCfg *runtimeapi.ContainerConfig) error {
- devTypes := sets.NewString(
- string(isolated_device.ContainerDeviceTypeNvidiaGpu),
- string(isolated_device.ContainerDeviceTypeNvidiaMps),
- string(isolated_device.ContainerDeviceTypeNvidiaGpuShare),
- string(isolated_device.ContainerDeviceTypeAscendNpu),
- )
- fDevs := filterContainerIsolatedDevices(spec.Devices, devTypes)
- if len(fDevs.EnvDevs) != 0 {
- ctrCfg.Envs = append(ctrCfg.Envs, getEnvsFromDevices(fDevs.EnvDevs)...)
- }
- for i := range fDevs.RestDevs {
- dev := fDevs.RestDevs[i]
- devMan, err := isolated_device.GetContainerDeviceManager(isolated_device.ContainerDeviceType(dev.IsolatedDevice.DeviceType))
- if err != nil {
- return errors.Wrapf(err, "GetContainerDeviceManager by type %q", dev.IsolatedDevice.DeviceType)
- }
- envs, mounts := devMan.GetContainerExtraConfigures([]*hostapi.ContainerDevice{dev})
- if len(envs) > 0 {
- ctrCfg.Envs = append(ctrCfg.Envs, envs...)
- }
- if len(mounts) > 0 {
- ctrCfg.Mounts = append(ctrCfg.Mounts, mounts...)
- }
- }
- if len(fDevs.CDIDevs) > 0 {
- cdiDevs, err := isolated_device.GetContainerCDIDevices(fDevs.CDIDevs)
- if err != nil {
- return errors.Wrap(err, "GetContainerCDIDevices")
- }
- ctrCfg.CDIDevices = append(ctrCfg.CDIDevices, cdiDevs...)
- }
- return nil
- }
- func (s *sPodGuestInstance) getContainerSystemCpusDir(ctrId string) string {
- rootFsPath, _ := s.GetRootFsMountPath(ctrId)
- if rootFsPath != "" {
- return filepath.Join(rootFsPath, "cpus", ctrId)
- }
- return filepath.Join(s.HomeDir(), "cpus", ctrId)
- }
- func (s *sPodGuestInstance) ensureContainerSystemCpuDir(cpuDir string, cpuCnt int64) error {
- // create cpu dir like /var/lib/docker/cpus/$ctr_name
- if err := podutil.EnsureContainerSystemCpuDir(cpuDir, cpuCnt); err != nil {
- return errors.Wrap(err, "ensure container system cpu dir")
- }
- return nil
- }
- func (s *sPodGuestInstance) findHostCpuPath(ctrId string, cpuIndex int) (int, error) {
- return s.getHostCPUMap().Get(ctrId, cpuIndex)
- }
- func (s *sPodGuestInstance) simulateContainerSystemCpuSetScalingCurFreq(ctrId string, scalingCurFreq int64) error {
- cpuDir := s.getContainerSystemCpusDir(ctrId)
- cpuCnt := s.GetDesc().Cpu
- for i := 0; i < int(cpuCnt); i++ {
- cpufreqPolicyCurFreqFile := path.Join(cpuDir, "cpufreq", fmt.Sprintf("policy%d", i), "scaling_cur_freq")
- cpufreqPolicySetSpeedFile := path.Join(cpuDir, "cpufreq", fmt.Sprintf("policy%d", i), "scaling_setspeed")
- scalingCurFreqStr := fmt.Sprintf("%d\n", scalingCurFreq)
- if err := fileutils2.FilePutContents(cpufreqPolicyCurFreqFile, scalingCurFreqStr, false); err != nil {
- return errors.Wrapf(err, "failed write %s", cpufreqPolicyCurFreqFile)
- }
- if err := fileutils2.FilePutContents(cpufreqPolicySetSpeedFile, scalingCurFreqStr, false); err != nil {
- return errors.Wrapf(err, "failed write %s", cpufreqPolicySetSpeedFile)
- }
- }
- return nil
- }
- func (s *sPodGuestInstance) simulateContainerSystemCpu(ctx context.Context, ctrId string) ([]*runtimeapi.Mount, error) {
- cpuDir := s.getContainerSystemCpusDir(ctrId)
- cpuCnt := s.GetDesc().Cpu
- if err := s.ensureContainerSystemCpuDir(cpuDir, cpuCnt); err != nil {
- return nil, err
- }
- cpufreqConfig := s.manager.host.GetContainerCpufreqSimulateConfig()
- if cpufreqConfig != nil {
- cpufreqDir := path.Join(cpuDir, "cpufreq")
- out, err := procutils.NewRemoteCommandAsFarAsPossible("mkdir", "-p", cpufreqDir).Output()
- if err != nil {
- return nil, errors.Wrapf(err, "mkdir %s: %s", cpufreqDir, out)
- }
- }
- sysCpuPath := "/sys/devices/system/cpu"
- ret := []*runtimeapi.Mount{
- {
- ContainerPath: sysCpuPath,
- HostPath: cpuDir,
- },
- }
- for i := 0; i < int(cpuCnt); i++ {
- hostCpuIdx, err := s.findHostCpuPath(ctrId, i)
- if err != nil {
- return nil, errors.Wrapf(err, "find host cpu by container %s with index %d", ctrId, i)
- }
- hostCpuPath := filepath.Join(sysCpuPath, fmt.Sprintf("cpu%d", hostCpuIdx))
- if cpufreqConfig != nil {
- if err := s.ensureContainerSystemCpufreqHostDir(cpuDir, hostCpuPath, i, cpufreqConfig); err != nil {
- return nil, errors.Wrap(err, "ensureContainerSystemCpufreqHostDir")
- }
- } else {
- ret = append(ret, &runtimeapi.Mount{
- ContainerPath: filepath.Join(sysCpuPath, fmt.Sprintf("cpu%d", i)),
- HostPath: hostCpuPath,
- })
- }
- }
- pathMap := func(baseName string) *runtimeapi.Mount {
- p := filepath.Join(sysCpuPath, baseName)
- return &runtimeapi.Mount{
- ContainerPath: p,
- HostPath: p,
- Readonly: true,
- }
- }
- cpuConfigs := []string{"modalias", "power", "cpuidle", "hotplug", "isolated", "uevent"}
- if cpufreqConfig == nil {
- cpuConfigs = append(cpuConfigs, "cpufreq")
- }
- for _, baseName := range cpuConfigs {
- ret = append(ret, pathMap(baseName))
- }
- return ret, nil
- }
- func (s *sPodGuestInstance) ensureContainerSystemCpufreqHostDir(cpuDir, hostCpuPath string, cpuIdx int, cpufreqConfig *jsonutils.JSONDict) error {
- cpufreqPolicyDir := path.Join(cpuDir, "cpufreq", fmt.Sprintf("policy%d", cpuIdx))
- out, err := procutils.NewRemoteCommandAsFarAsPossible("mkdir", "-p", cpufreqPolicyDir).Output()
- if err != nil {
- return errors.Wrapf(err, "mkdir %s: %s", cpufreqPolicyDir, out)
- }
- cpuiDir := path.Join(cpuDir, fmt.Sprintf("cpu%d", cpuIdx))
- out, err = procutils.NewRemoteCommandAsFarAsPossible("cp", "-rf", hostCpuPath, cpuiDir).Output()
- if err != nil {
- log.Warningf("cp %s to %s: %s %s", hostCpuPath, cpuiDir, out, err)
- }
- cpufreqDir := path.Join(cpuiDir, "cpufreq")
- out, err = procutils.NewRemoteCommandAsFarAsPossible("rm", "-f", cpufreqDir).Output()
- if err != nil {
- return errors.Wrapf(err, "rm -f %s: %s", cpufreqDir, out)
- }
- for _, fname := range []string{
- "affected_cpus",
- "cpuinfo_max_freq",
- "cpuinfo_min_freq",
- "cpuinfo_transition_latency",
- "related_cpus",
- "scaling_available_governors",
- "scaling_cur_freq",
- "scaling_driver",
- "scaling_governor",
- "scaling_max_freq",
- "scaling_min_freq",
- "scaling_setspeed",
- } {
- switch fname {
- case "affected_cpus", "related_cpus":
- val := strconv.Itoa(cpuIdx)
- cpath := path.Join(cpufreqPolicyDir, fname)
- if err := fileutils2.FilePutContents(cpath, val+"\n", false); err != nil {
- return errors.Wrapf(err, "failed write %s", cpath)
- }
- default:
- val, err := cpufreqConfig.GetString(fname)
- if err != nil {
- log.Warningf("simulate cpufreq no %s", fname)
- continue
- }
- cpath := path.Join(cpufreqPolicyDir, fname)
- if err := fileutils2.FilePutContents(cpath, val+"\n", false); err != nil {
- return errors.Wrapf(err, "failed write %s", cpath)
- }
- }
- }
- out, err = procutils.NewRemoteCommandAsFarAsPossible("ln", "-s", fmt.Sprintf("../cpufreq/policy%d", cpuIdx), cpufreqDir).Output()
- if err != nil {
- return errors.Wrapf(err, "ln -s ../cpufreq/policy%d %s: %s", cpuIdx, cpufreqDir, out)
- }
- return nil
- }
- func (s *sPodGuestInstance) DeleteContainer(ctx context.Context, userCred mcclient.TokenCredential, ctrId string) (jsonutils.JSONObject, error) {
- criId, err := s.getContainerCRIId(ctrId)
- if err != nil && errors.Cause(err) != errors.ErrNotFound {
- return nil, errors.Wrap(err, "getContainerCRIId")
- }
- if criId != "" {
- s.expectedStatus.RemoveContainer(criId)
- if err := s.getCRI().RemoveContainer(ctx, criId); err != nil && !IsContainerNotFoundError(err) {
- return nil, errors.Wrap(err, "cri.RemoveContainer")
- }
- }
- // refresh local containers file
- delete(s.containers, ctrId)
- if err := s.saveContainersFile(s.containers); err != nil {
- return nil, errors.Wrap(err, "saveContainersFile")
- }
- if err := s.getHostCPUMap().Delete(ctrId); err != nil {
- log.Warningf("delete container %s cpu map: %v", ctrId, err)
- }
- return nil, nil
- }
- func (s *sPodGuestInstance) GetContainerStatus(ctx context.Context, ctrId string) (string, *runtime.Status, error) {
- return s.getContainerStatus(ctx, ctrId)
- }
- func (s *sPodGuestInstance) getContainerStatus(ctx context.Context, ctrId string) (string, *runtime.Status, error) {
- criId, err := s.getContainerCRIId(ctrId)
- if err != nil {
- if errors.Cause(err) == errors.ErrNotFound {
- // not found, already stopped
- return computeapi.CONTAINER_STATUS_EXITED, nil, nil
- }
- return "", nil, errors.Wrapf(err, "get container cri_id by %s", ctrId)
- }
- resp, err := s.getCRI().ContainerStatus(ctx, criId)
- if err != nil {
- if IsContainerNotFoundError(err) {
- return computeapi.CONTAINER_STATUS_EXITED, nil, nil
- }
- return "", nil, errors.Wrap(err, "cri.ContainerStatus")
- }
- cs := runtime.ToContainerStatus(resp.Status, "containerd")
- status := computeapi.CONTAINER_STATUS_UNKNOWN
- switch resp.Status.State {
- case runtimeapi.ContainerState_CONTAINER_CREATED:
- status = computeapi.CONTAINER_STATUS_CREATED
- case runtimeapi.ContainerState_CONTAINER_RUNNING:
- status = computeapi.CONTAINER_STATUS_RUNNING
- case runtimeapi.ContainerState_CONTAINER_EXITED:
- status = computeapi.CONTAINER_STATUS_EXITED
- case runtimeapi.ContainerState_CONTAINER_UNKNOWN:
- status = computeapi.CONTAINER_STATUS_UNKNOWN
- }
- if status == computeapi.CONTAINER_STATUS_RUNNING {
- ctr := s.GetContainerById(ctrId)
- if ctr == nil {
- return "", cs, errors.Wrapf(httperrors.ErrNotFound, "not found container by id %s", ctrId)
- }
- if ctr.Spec.NeedProbe() {
- status = computeapi.CONTAINER_STATUS_PROBING
- }
- }
- if status == computeapi.CONTAINER_STATUS_EXITED && resp.Status.ExitCode != 0 {
- if _, isInternalStopped := s.IsInternalStopped(criId); !isInternalStopped {
- status = computeapi.CONTAINER_STATUS_CRASH_LOOP_BACK_OFF
- }
- }
- return status, cs, nil
- }
- func (s *sPodGuestInstance) MarkContainerProbeDirty(ctrStatus string, ctrId string, reason string) {
- s.markContainerProbeDirty(ctrStatus, ctrId, reason)
- }
- func (s *sPodGuestInstance) markContainerProbeDirty(status, ctrId string, reason string) {
- if status == computeapi.CONTAINER_STATUS_PROBING {
- reason = fmt.Sprintf("status is probing: %s", reason)
- s.getProbeManager().SetDirtyContainer(ctrId, reason)
- s.getProbeManager().AddPod(s)
- }
- }
- func (s *sPodGuestInstance) SyncContainerStatus(ctx context.Context, userCred mcclient.TokenCredential, ctrId string) (jsonutils.JSONObject, error) {
- status, cs, err := s.getContainerStatus(ctx, ctrId)
- if err != nil {
- return nil, errors.Wrap(err, "get container status")
- }
- s.markContainerProbeDirty(status, ctrId, "after syncing status")
- resp := computeapi.ContainerSyncStatusResponse{
- Status: status,
- }
- if cs != nil {
- resp.StartedAt = cs.StartedAt
- resp.RestartCount = cs.RestartCount
- }
- return jsonutils.Marshal(resp), nil
- }
- func (s *sPodGuestInstance) PullImage(ctx context.Context, userCred mcclient.TokenCredential, ctrId string, input *hostapi.ContainerPullImageInput) (jsonutils.JSONObject, error) {
- policy := input.PullPolicy
- if policy == apis.ImagePullPolicyIfNotPresent || policy == "" {
- // check if image is presented
- img, err := s.getCRI().ImageStatus(ctx, &runtimeapi.ImageStatusRequest{
- Image: &runtimeapi.ImageSpec{
- Image: input.Image,
- },
- })
- if err != nil {
- return nil, errors.Wrapf(err, "cri.ImageStatus %s", input.Image)
- }
- if img.Image != nil {
- log.Infof("image %s already exists, skipping pulling it when policy is %s", input.Image, policy)
- return jsonutils.Marshal(&runtimeapi.PullImageResponse{
- ImageRef: img.Image.Id,
- }), nil
- }
- }
- return s.pullImageByCtrCmd(ctx, userCred, ctrId, input)
- // return s.pullImageByCRI(ctx, userCred, ctrId, input)
- }
- func (s *sPodGuestInstance) pullImageByCtrCmd(ctx context.Context, userCred mcclient.TokenCredential, ctrId string, input *hostapi.ContainerPullImageInput) (jsonutils.JSONObject, error) {
- if err := PullContainerdImage(input); err != nil {
- return nil, errors.Wrap(err, "PullContainerdImage with https and http")
- }
- return jsonutils.Marshal(&runtimeapi.PullImageResponse{
- ImageRef: input.Image,
- }), nil
- }
- func (s *sPodGuestInstance) pullImageByCRI(ctx context.Context, userCred mcclient.TokenCredential, ctrId string, input *hostapi.ContainerPullImageInput) (jsonutils.JSONObject, error) {
- /*podCfg, err := s.getPodSandboxConfig()
- if err != nil {
- return nil, errors.Wrap(err, "get pod sandbox config")
- }*/
- req := &runtimeapi.PullImageRequest{
- Image: &runtimeapi.ImageSpec{
- Image: input.Image,
- },
- // SandboxConfig: podCfg,
- }
- if input.Auth != nil {
- authCfg := &runtimeapi.AuthConfig{
- Username: input.Auth.Username,
- Password: input.Auth.Password,
- Auth: input.Auth.Auth,
- ServerAddress: input.Auth.ServerAddress,
- IdentityToken: input.Auth.IdentityToken,
- RegistryToken: input.Auth.RegistryToken,
- }
- req.Auth = authCfg
- }
- resp, err := s.getCRI().PullImage(ctx, req)
- if err != nil {
- return nil, errors.Wrapf(err, "cri.PullImage %s", input.Image)
- }
- return jsonutils.Marshal(resp), nil
- }
- func (s *sPodGuestInstance) SaveVolumeMountToImage(ctx context.Context, userCred mcclient.TokenCredential, input *hostapi.ContainerSaveVolumeMountToImageInput, ctrId string) (jsonutils.JSONObject, error) {
- vol := input.VolumeMount
- drv := volume_mount.GetDriver(vol.Type)
- if err := drv.Mount(s, ctrId, vol); err != nil {
- return nil, errors.Wrapf(err, "mount volume %s, ctrId %s", jsonutils.Marshal(vol), ctrId)
- }
- defer func() {
- if err := drv.Unmount(s, ctrId, vol); err != nil {
- log.Warningf("unmount volume %s: %v", jsonutils.Marshal(vol), err)
- }
- }()
- hostPath, err := drv.GetRuntimeMountHostPath(s, ctrId, vol)
- if err != nil {
- return nil, errors.Wrapf(err, "get runtime host mount path of %s", jsonutils.Marshal(vol))
- }
- // 1. tar hostPath to tgz
- imgPath, originalSizeBytes, err := s.tarGzDir(input, ctrId, hostPath)
- if err != nil {
- return nil, errors.Wrapf(err, "tar and zip directory %s", hostPath)
- }
- defer func() {
- out, err := procutils.NewRemoteCommandAsFarAsPossible("rm", "-f", imgPath).Output()
- if err != nil {
- log.Warningf("rm -f %s: %s", imgPath, out)
- }
- }()
- // 2. upload target tgz to glance
- if err := s.saveTarGzToGlance(ctx, input, imgPath, originalSizeBytes); err != nil {
- return nil, errors.Wrapf(err, "saveTarGzToGlance: %s", imgPath)
- }
- return nil, nil
- }
- // shellQuote wraps s in single quotes, escaping any embedded single quotes
- // so the result is safe to embed in a sh -c command string.
- func shellQuote(s string) string {
- return "'" + strings.ReplaceAll(s, "'", "'\\''") + "'"
- }
- func (s *sPodGuestInstance) tarGzDir(input *hostapi.ContainerSaveVolumeMountToImageInput, ctrId string, hostPath string) (string, int64, error) {
- fp := fmt.Sprintf("volimg-%s-ctr-%s-%d.tar.gz", input.ImageId, ctrId, input.VolumeMountIndex)
- outputFp := filepath.Join(s.GetVolumesDir(), fp)
- dirPath := "."
- if len(input.VolumeMountDirs) != 0 {
- dirPath = ""
- for _, vd := range input.VolumeMountDirs {
- dirPath = fmt.Sprintf("%s %s", dirPath, shellQuote(vd))
- }
- }
- // 计算总字节数,兼容多个目录/文件
- var totalSize int64
- if len(input.VolumeMountDirs) == 0 {
- sizeCmd := fmt.Sprintf("du -sb %s | awk '{print $1}'", shellQuote(hostPath))
- out, err := procutils.NewRemoteCommandAsFarAsPossible("sh", "-c", sizeCmd).Output()
- if err != nil {
- return "", 0, errors.Wrapf(err, "calculate total size: %s", out)
- }
- outStr := strings.TrimSpace(string(out))
- totalSize, err = strconv.ParseInt(outStr, 10, 64)
- if err != nil {
- return "", 0, errors.Wrapf(err, "parse total size: %s", outStr)
- }
- } else {
- for _, d := range input.VolumeMountDirs {
- // 兼容目录或文件名有空格
- sizeCmd := fmt.Sprintf("du -sb %s | awk '{print $1}'", shellQuote(d))
- cmd := fmt.Sprintf("cd %s && %s", shellQuote(hostPath), sizeCmd)
- out, err := procutils.NewRemoteCommandAsFarAsPossible("sh", "-c", cmd).Output()
- if err != nil {
- return "", 0, errors.Wrapf(err, "calculate total size for %s: %s", d, out)
- }
- outStr := strings.TrimSpace(string(out))
- sz, err := strconv.ParseInt(outStr, 10, 64)
- if err != nil {
- return "", 0, errors.Wrapf(err, "parse total size for %s: %s", d, outStr)
- }
- totalSize += sz
- }
- }
- // 减去 excludePaths 的大小
- for _, exclude := range input.ExcludePaths {
- // exclude 路径是相对于 hostPath 的
- sizeCmd := fmt.Sprintf("du -sb %s 2>/dev/null | awk '{print $1}'", shellQuote(exclude))
- cmd := fmt.Sprintf("cd %s && %s", shellQuote(hostPath), sizeCmd)
- out, err := procutils.NewRemoteCommandAsFarAsPossible("sh", "-c", cmd).Output()
- if err != nil {
- // exclude 路径不存在时忽略错误,继续处理下一个
- continue
- }
- outStr := strings.TrimSpace(string(out))
- if outStr == "" {
- continue
- }
- excludeSize, err := strconv.ParseInt(outStr, 10, 64)
- if err != nil {
- // 解析失败时忽略,继续处理下一个
- continue
- }
- totalSize -= excludeSize
- // 确保 totalSize 不为负数
- if totalSize < 0 {
- totalSize = 0
- }
- }
- baseCmd := "tar -czf"
- // 添加 exclude 选项
- for _, exclude := range input.ExcludePaths {
- baseCmd = fmt.Sprintf("%s --exclude=%s", baseCmd, shellQuote(exclude))
- }
- cmd := fmt.Sprintf("%s %s -C %s %s", baseCmd, shellQuote(outputFp), shellQuote(hostPath), dirPath)
- if input.VolumeMountPrefix != "" {
- cmd += fmt.Sprintf(" --transform 's,^,%s/,'", input.VolumeMountPrefix)
- }
- if out, err := procutils.NewRemoteCommandAsFarAsPossible("sh", "-c", cmd).Output(); err != nil {
- return "", 0, errors.Wrapf(err, "%s: %s", cmd, out)
- }
- return outputFp, totalSize, nil
- }
- func (s *sPodGuestInstance) saveTarGzToGlance(ctx context.Context, input *hostapi.ContainerSaveVolumeMountToImageInput, imgPath string, originalSizeBytes int64) error {
- f, err := os.Open(imgPath)
- if err != nil {
- return err
- }
- defer f.Close()
- finfo, err := f.Stat()
- if err != nil {
- return err
- }
- size := finfo.Size()
- // 转换为 MB
- originalSizeMB := originalSizeBytes / (1024 * 1024)
- var params = jsonutils.NewDict()
- params.Set("image_id", jsonutils.NewString(input.ImageId))
- params.Set("min_disk", jsonutils.NewInt(originalSizeMB))
- if _, err := imagemod.Images.Upload(hostutils.GetImageSession(ctx), params, f, size); err != nil {
- return errors.Wrap(err, "upload image")
- }
- return err
- }
- func (s *sPodGuestInstance) ExecContainer(ctx context.Context, userCred mcclient.TokenCredential, ctrId string, input *computeapi.ContainerExecInput) (*url.URL, error) {
- rCli := s.getCRI().GetRuntimeClient()
- criId, err := s.getContainerCRIId(ctrId)
- if err != nil {
- return nil, errors.Wrap(err, "get container cri id")
- }
- stderr := true
- if input.Tty {
- stderr = false
- }
- req := &runtimeapi.ExecRequest{
- ContainerId: criId,
- Cmd: input.Command,
- Tty: input.Tty,
- Stdin: true,
- Stdout: true,
- Stderr: stderr,
- }
- if input.SetIO {
- req.Stdin = input.Stdin
- req.Stdout = input.Stdout
- }
- resp, err := rCli.Exec(ctx, req)
- if err != nil {
- return nil, errors.Wrap(err, "exec")
- }
- return url.Parse(resp.Url)
- }
- func (s *sPodGuestInstance) mountDevShm(input *hostapi.ContainerCreateInput, mb int) (string, error) {
- shmPath := s.getContainerShmDir(input.Name)
- if !fileutils2.Exists(shmPath) {
- out, err := procutils.NewRemoteCommandAsFarAsPossible("mkdir", "-p", shmPath).Output()
- if err != nil {
- return "", errors.Wrapf(err, "mkdir -p %s: %s", shmPath, out)
- }
- }
- if err := procutils.NewRemoteCommandAsFarAsPossible("mountpoint", shmPath).Run(); err == nil {
- log.Warningf("mountpoint %s is already mounted", shmPath)
- return "", nil
- }
- out, err := procutils.NewRemoteCommandAsFarAsPossible("mount", "-t", "tmpfs", "-o", fmt.Sprintf("size=%dM", mb), "tmpfs", shmPath).Output()
- if err != nil {
- return "", errors.Wrapf(err, "mount tmpfs %s: %s", shmPath, out)
- }
- return shmPath, nil
- }
- func (s *sPodGuestInstance) unmountDevShm(containerName string) error {
- shmPath := s.getContainerShmDir(containerName)
- if err := procutils.NewRemoteCommandAsFarAsPossible("mountpoint", shmPath).Run(); err != nil {
- return nil
- }
- out, err := procutils.NewRemoteCommandAsFarAsPossible("umount", shmPath).Output()
- if err != nil {
- return errors.Wrapf(err, "mount tmpfs %s: %s", shmPath, out)
- }
- return nil
- }
- func (s *sPodGuestInstance) DoSnapshot(ctx context.Context, params *SDiskSnapshot) (jsonutils.JSONObject, error) {
- input := params.BackupDiskConfig.BackupAsTar
- if input.ContainerId == "" {
- return nil, httperrors.NewMissingParameterError("missing backup_disk_config.backup_as_tar.container_id")
- }
- isCtrRunning, err := s.IsContainerRunning(ctx, input.ContainerId)
- if err != nil {
- return nil, errors.Wrapf(err, "check container %s running status", input.ContainerId)
- }
- if params.BackupDiskConfig == nil {
- return nil, httperrors.NewMissingParameterError("missing backup_disk_config")
- }
- if params.BackupDiskConfig.BackupAsTar == nil {
- return nil, httperrors.NewMissingParameterError("missing backup_disk_config.backup_as_tar")
- }
- vols := s.getContainerVolumeMountsByDiskId(input.ContainerId, params.Disk.GetId())
- if len(vols) == 0 {
- return nil, httperrors.NewNotFoundError("not found container volume_mount by container_id %s and disk_id %s", input.ContainerId, params.Disk.GetId())
- }
- tmpBackRootDir, err := storageman.EnsureBackupDir()
- if err != nil {
- return nil, errors.Wrap(err, "EnsureBackupDir")
- }
- defer storageman.CleanupDirOrFile(tmpBackRootDir)
- povTmpBackRootDir := []string{}
- for _, vol := range vols {
- drv := volume_mount.GetDriver(vol.Type)
- if err := drv.Mount(s, input.ContainerId, vol); err != nil {
- return nil, errors.Wrapf(err, "mount %s to %s", input.ContainerId, jsonutils.Marshal(vol))
- }
- mntPath, err := drv.GetRuntimeMountHostPath(s, input.ContainerId, vol)
- if err != nil {
- return nil, errors.Wrapf(err, "GetRuntimeMountHostPath containerId: %s, vol: %s", input.ContainerId, jsonutils.Marshal(vol))
- }
- isMntPathFile := false
- targetBindMntPath := tmpBackRootDir
- if vol.Disk.SubDirectory != "" {
- // mkdir tmpBackRootDir/subdirectory
- targetBindMntPath = filepath.Join(tmpBackRootDir, vol.Disk.SubDirectory)
- }
- if vol.Disk.StorageSizeFile != "" {
- targetBindMntPath = filepath.Join(tmpBackRootDir, vol.Disk.StorageSizeFile)
- isMntPathFile = true
- }
- if isMntPathFile {
- if out, err := procutils.NewRemoteCommandAsFarAsPossible("touch", targetBindMntPath).Output(); err != nil {
- return nil, errors.Wrapf(err, "touch %s: %s", targetBindMntPath, out)
- }
- } else {
- if err := volume_mount.EnsureDir(targetBindMntPath); err != nil {
- return nil, errors.Wrap(err, "ensure dir")
- }
- }
- // do bind mount
- if err := mountutils.MountBind(mntPath, targetBindMntPath); err != nil {
- return nil, errors.Wrapf(err, "bind mount %s to %s", mntPath, targetBindMntPath)
- }
- // process post overlay
- diskDrv := drv.(disk.IVolumeMountDisk)
- for _, pov := range vol.Disk.PostOverlay {
- // bind mount post overlay dirs to tmpBackRootDir
- upperDir, err := diskDrv.GetPostOverlayRootUpperDir(s, vol, input.ContainerId, pov)
- if err != nil {
- return nil, errors.Wrapf(err, "get post overlay root upper dir: %s", jsonutils.Marshal(pov))
- }
- workDir, err := diskDrv.GetPostOverlayRootWorkDir(s, vol, input.ContainerId)
- if err != nil {
- return nil, errors.Wrapf(err, "get post overlay root upper dir: %s", jsonutils.Marshal(pov))
- }
- hostDiskRootPath, _ := diskDrv.GetHostDiskRootPath(s, vol)
- for _, srcDir := range []string{upperDir, workDir} {
- targetSubDir := strings.TrimPrefix(srcDir, hostDiskRootPath)
- targetPovBindMntPath := filepath.Join(tmpBackRootDir, targetSubDir)
- if err := mountutils.MountBind(srcDir, targetPovBindMntPath); err != nil {
- return nil, errors.Wrap(err, "bind mount post overlay dir")
- }
- povTmpBackRootDir = append(povTmpBackRootDir, targetPovBindMntPath)
- }
- }
- }
- deferUmount := func() error {
- for _, vol := range vols {
- // unbind mount
- for _, povPath := range povTmpBackRootDir {
- if err := mountutils.Unmount(povPath, false); err != nil {
- return errors.Wrapf(err, "umount bind point %s", povTmpBackRootDir)
- }
- }
- targetBindMntPath := filepath.Join(tmpBackRootDir, vol.Disk.SubDirectory)
- if vol.Disk.StorageSizeFile != "" {
- targetBindMntPath = filepath.Join(tmpBackRootDir, vol.Disk.StorageSizeFile)
- }
- if err := mountutils.Unmount(targetBindMntPath, false); err != nil {
- return errors.Wrapf(err, "umount bind point %s", targetBindMntPath)
- }
- }
- if !isCtrRunning && !s.IsRunning() {
- for _, vol := range vols {
- drv := volume_mount.GetDriver(vol.Type)
- if err := drv.Unmount(s, input.ContainerId, vol); err != nil {
- return errors.Wrapf(err, "unmount %s to %s", input.ContainerId, jsonutils.Marshal(vol))
- }
- }
- } else {
- log.Infof("container %s/%s is running, so skipping unmount volumes", s.GetId(), input.ContainerId)
- }
- return nil
- }
- defer func() {
- if err := deferUmount(); err != nil {
- log.Errorf("deferUmount after snapshot error: %s", err)
- } else {
- log.Infof("defer umount success")
- }
- }()
- snapshotPath, err := s.createSnapshot(params, tmpBackRootDir)
- if err != nil {
- return nil, errors.Wrap(err, "create snapshot")
- }
- res := jsonutils.NewDict()
- res.Set("location", jsonutils.NewString(snapshotPath))
- return res, nil
- }
- func (s *sPodGuestInstance) createSnapshot(params *SDiskSnapshot, hostPath string) (string, error) {
- d := params.Disk
- snapshotDir := d.GetSnapshotDir()
- log.Infof("snapshotDir of LocalDisk %s: %s", d.GetId(), snapshotDir)
- if !fileutils2.Exists(snapshotDir) {
- output, err := procutils.NewCommand("mkdir", "-p", snapshotDir).Output()
- if err != nil {
- log.Errorf("mkdir %s failed: %s", snapshotDir, output)
- return "", errors.Wrapf(err, "mkdir %s failed: %s", snapshotDir, output)
- }
- }
- snapshotPath := s.getSnapshotPath(d, params.SnapshotId)
- // tar hostPath to snapshotPath
- input := params.BackupDiskConfig.BackupAsTar
- if err := s.tarHostDir(hostPath, snapshotPath, input.IncludeFiles, input.ExcludeFiles, input.IgnoreNotExistFile, input.IncludePatterns); err != nil {
- return "", errors.Wrapf(err, "tar host dir %s to %s", hostPath, snapshotPath)
- }
- return snapshotPath, nil
- }
- func (s *sPodGuestInstance) tarHostDir(srcDir, targetPath string,
- includeFiles, excludeFiles []string,
- ignoreNotExistFile bool,
- includePatterns []string) error {
- baseCmd := "tar"
- filterNotExistFiles := func(files []string) []string {
- result := []string{}
- for i := range files {
- if fileutils2.Exists(filepath.Join(srcDir, files[i])) {
- result = append(result, files[i])
- } else {
- log.Warningf("tar path doesn't exist: %q", filepath.Join(srcDir, files[i]))
- }
- }
- return result
- }
- if ignoreNotExistFile {
- includeFiles = filterNotExistFiles(includeFiles)
- excludeFiles = filterNotExistFiles(excludeFiles)
- }
- // 如果有 includePatterns,使用 find -name 找出匹配的路径,添加到 includeFiles 中
- if len(includePatterns) > 0 {
- findPatterns := []string{}
- for _, pattern := range includePatterns {
- // 转义特殊字符,但保留 glob 通配符
- findPatterns = append(findPatterns, fmt.Sprintf("-name %s", shellQuote(pattern)))
- }
- // 构建 find 命令来查找匹配的路径
- findCmd := fmt.Sprintf("find . \\( %s \\)", strings.Join(findPatterns, " -o "))
- cmd := fmt.Sprintf("cd %s && %s", shellQuote(srcDir), findCmd)
- log.Infof("[%s] find cmd: %s", s.GetName(), cmd)
- out, err := procutils.NewRemoteCommandAsFarAsPossible("sh", "-c", cmd).Output()
- if err != nil {
- return errors.Wrapf(err, "find matching paths: %s", out)
- }
- // 解析 find 的输出,将匹配的路径添加到 includeFiles 中
- // find 输出的路径格式为 ./path,需要去掉开头的 ./
- lines := strings.Split(strings.TrimSpace(string(out)), "\n")
- for _, line := range lines {
- line = strings.TrimSpace(line)
- if line == "" {
- continue
- }
- // 去掉开头的 ./
- if strings.HasPrefix(line, "./") {
- line = line[2:]
- }
- // 添加到 includeFiles 中
- includeFiles = append(includeFiles, line)
- }
- }
- // 没有 includePatterns 时,使用原来的逻辑
- // 添加 --exclude 选项
- for _, exclude := range excludeFiles {
- baseCmd = fmt.Sprintf("%s --exclude=%s", baseCmd, shellQuote(exclude))
- }
- includeStr := "."
- if len(includeFiles) > 0 {
- for i := range includeFiles {
- includeFiles[i] = shellQuote(includeFiles[i])
- }
- includeStr = strings.Join(includeFiles, " ")
- }
- cmd := fmt.Sprintf("%s --ignore-failed-read -cf %s -C %s %s", baseCmd, shellQuote(targetPath), shellQuote(srcDir), includeStr)
- log.Infof("[%s] tar cmd: %s", s.GetName(), cmd)
- if out, err := procutils.NewRemoteCommandAsFarAsPossible("sh", "-c", cmd).Output(); err != nil {
- outErr := errors.Wrapf(err, "%s: %s", cmd, out)
- outMsg := strings.ToLower(outErr.Error())
- // ref: https://stackoverflow.com/questions/20318852/tar-file-changed-as-we-read-it
- const exitStatus1 = "exit status 1"
- const fileChangedMsg = "file changed as we read it"
- const fileRemovedMsg = "file removed before we read it"
- const socketIgnoredMsg = "socket ignored"
- if strings.Contains(outMsg, exitStatus1) {
- for _, warningMsg := range []string{fileChangedMsg, fileRemovedMsg, socketIgnoredMsg} {
- if strings.Contains(outMsg, warningMsg) {
- log.Warningf("[%s] got some warning message when tar: %s", s.GetName(), outMsg)
- return nil
- }
- }
- }
- return outErr
- }
- return nil
- }
- func (s *sPodGuestInstance) getSnapshotPath(d storageman.IDisk, snapshotId string) string {
- snapshotDir := d.GetSnapshotDir()
- snapshotPath := path.Join(snapshotDir, fmt.Sprintf("%s.tar", snapshotId))
- return snapshotPath
- }
- func (s *sPodGuestInstance) DeleteSnapshot(ctx context.Context, params *SDeleteDiskSnapshot) (jsonutils.JSONObject, error) {
- snapshotPath := s.getSnapshotPath(params.Disk, params.DeleteSnapshot)
- out, err := procutils.NewCommand("rm", "-f", snapshotPath).Output()
- if err != nil {
- return nil, errors.Wrapf(err, "rm -f %s: %s", snapshotPath, out)
- }
- res := jsonutils.NewDict()
- res.Set("deleted", jsonutils.JSONTrue)
- return res, nil
- }
- func (s *sPodGuestInstance) doOnlineResizeDisk(ctx context.Context, disk storageman.IDisk, sizeMB int64) {
- drv, err := disk.GetContainerStorageDriver()
- if err != nil {
- hostutils.TaskFailed(ctx, fmt.Sprintf("get disk storage driver %s", err))
- return
- }
- partDev, found, err := drv.CheckConnect(disk.GetPath())
- if err != nil {
- hostutils.TaskFailed(ctx, fmt.Sprintf("disk check connect %s", err))
- return
- }
- if !found {
- hostutils.TaskFailed(ctx, fmt.Sprintf("online resize but loop device not connected"))
- return
- }
- if err := disk.PreResize(ctx, sizeMB); err != nil {
- hostutils.TaskFailed(ctx, fmt.Sprintf("PreResize failed %s", err))
- return
- }
- diskInfo := jsonutils.NewDict()
- diskInfo.Set("size", jsonutils.NewInt(sizeMB))
- diskInfo.Set("loop_part_dev", jsonutils.NewString(partDev))
- resizeDiskInfo := &storageman.SDiskResizeInput{
- DiskInfo: diskInfo,
- }
- res, err := disk.Resize(ctx, resizeDiskInfo)
- if err != nil {
- hostutils.TaskFailed(ctx, fmt.Sprintf("PreResize failed %s", err))
- return
- }
- hostutils.TaskComplete(ctx, res)
- }
- func (s *sPodGuestInstance) OnlineResizeDisk(ctx context.Context, disk storageman.IDisk, sizeMB int64) {
- go s.doOnlineResizeDisk(ctx, disk, sizeMB)
- }
- func (s *sPodGuestInstance) ContainerExecSync(ctx context.Context, userCred mcclient.TokenCredential, ctrId string, input *computeapi.ContainerExecSyncInput) (jsonutils.JSONObject, error) {
- ctrCriId, err := s.getContainerCRIId(ctrId)
- if err != nil {
- return nil, errors.Wrap(err, "get container cri id")
- }
- cli := s.getCRI().GetRuntimeClient()
- resp, err := cli.ExecSync(ctx, &runtimeapi.ExecSyncRequest{
- ContainerId: ctrCriId,
- Cmd: input.Command,
- Timeout: input.Timeout,
- })
- if err != nil {
- return nil, errors.Wrapf(err, "exec sync %#v to %s", input.Command, ctrCriId)
- }
- return jsonutils.Marshal(&computeapi.ContainerExecSyncResponse{
- Stdout: string(resp.Stdout),
- Stderr: string(resp.Stderr),
- ExitCode: resp.ExitCode,
- }), nil
- }
- func (s *sPodGuestInstance) ReadLogs(ctx context.Context, userCred mcclient.TokenCredential, ctrId string, input *computeapi.PodLogOptions, stdout, stderr io.Writer) error {
- // Do a zero-byte write to stdout before handing off to the container runtime.
- // This ensures at least one Write call is made to the writer when copying starts,
- // even if we then block waiting for log output from the container.
- if _, err := stdout.Write([]byte{}); err != nil {
- return err
- }
- ctrCriId, err := s.getContainerCRIId(ctrId)
- if err != nil {
- return errors.Wrapf(err, "get container cri id %s", ctrId)
- }
- resp, err := s.getCRI().ContainerStatus(ctx, ctrCriId)
- if err != nil {
- return errors.Wrapf(err, "get container status %s", ctrCriId)
- }
- logPath := resp.GetStatus().GetLogPath()
- opts := logs.NewLogOptions(input, time.Now())
- return logs.ReadLogs(ctx, logPath, ctrCriId, opts, s.getCRI().GetRuntimeClient(), stdout, stderr)
- }
- func (s *sPodGuestInstance) CommitContainer(ctx context.Context, userCred mcclient.TokenCredential, ctrId string, input *hostapi.ContainerCommitInput) (jsonutils.JSONObject, error) {
- criId, err := s.getContainerCRIId(ctrId)
- if err != nil {
- return nil, errors.Wrap(err, "get container cri id")
- }
- // 1. commit
- tool := NewContainerdNerdctl()
- imgRepo, err := tool.Commit(criId, &nerdctl.CommitOptions{Repository: input.Repository})
- if err != nil {
- return nil, errors.Wrapf(err, "commit container %s image", ctrId)
- }
- log.Infof("container %s was commited to %s", ctrId, imgRepo)
- // 2. push to repository
- if err := PushContainerdImage(&hostapi.ContainerPushImageInput{
- Image: imgRepo,
- Auth: input.Auth,
- }); err != nil {
- return nil, errors.Wrapf(err, "push container %s image", ctrId)
- }
- log.Infof("container %s was pushed to %s", ctrId, imgRepo)
- return jsonutils.Marshal(map[string]interface{}{
- "image_repository": imgRepo,
- }), nil
- }
- func (s *sPodGuestInstance) AddContainerVolumeMountPostOverlay(ctx context.Context, userCred mcclient.TokenCredential, ctrId string, input *computeapi.ContainerVolumeMountAddPostOverlayInput) error {
- isRunning, err := s.IsContainerRunning(ctx, ctrId)
- if err != nil {
- return errors.Wrap(err, "check container is running")
- }
- if !isRunning {
- return nil
- }
- ctrSpec := s.GetContainerById(ctrId)
- vol := ctrSpec.Spec.VolumeMounts[input.Index]
- drv := volume_mount.GetDriver(vol.Type)
- diskDrv, ok := drv.(disk.IVolumeMountDisk)
- if !ok {
- return errors.Errorf("invalid disk volume driver of %s", vol.Type)
- }
- return diskDrv.MountPostOverlays(s, ctrId, vol, input.PostOverlay)
- }
- func (s *sPodGuestInstance) RemoveContainerVolumeMountPostOverlay(ctx context.Context, userCred mcclient.TokenCredential, ctrId string, input *computeapi.ContainerVolumeMountRemovePostOverlayInput) error {
- ctrSpec := s.GetContainerById(ctrId)
- vol := ctrSpec.Spec.VolumeMounts[input.Index]
- drv := volume_mount.GetDriver(vol.Type)
- diskDrv, ok := drv.(disk.IVolumeMountDisk)
- if !ok {
- return errors.Errorf("invalid disk volume driver of %s", vol.Type)
- }
- // drv.Mount 不会重复挂载,支持重复调用
- if err := drv.Mount(s, ctrId, vol); err != nil {
- return errors.Wrapf(err, "mount volume %s, ctrId %s", jsonutils.Marshal(vol), ctrId)
- }
- return diskDrv.UnmountPostOverlays(s, ctrId, vol, input.PostOverlay, input.UseLazy, input.ClearLayers)
- }
- func (s *sPodGuestInstance) SetNicDown(mac string) error {
- // null operation for pod, QIUJIAN, 20260203
- return nil
- }
- func (s *sPodGuestInstance) SetNicUp(nic *desc.SGuestNetwork) error {
- // null operation for pod, QIUJIAN, 20260203
- return nil
- }
|