// Copyright (c) Huawei Technologies Co., Ltd. 2018-2019. All rights reserved. // isulad-tools is licensed under the Mulan PSL v1. // You can use this software according to the terms and conditions of the Mulan PSL v1. // You may obtain a copy of Mulan PSL v1 at: // http://license.coscl.org.cn/MulanPSL // THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR // IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR // PURPOSE. // See the Mulan PSL v1 for more details. // Description: poststop hook // Author: zhangwei // Create: 2018-01-18 // go base main package package main import ( "fmt" "os" "path/filepath" "github.com/opencontainers/runc/libcontainer/configs" hconfig "isula.org/isulad-tools/config" "isula.org/isulad-tools/libdevice" "isula.org/isulad-tools/libnetwork" "isula.org/isulad-tools/pkg/udevd" "isula.org/isulad-tools/types" "isula.org/isulad-tools/utils" "github.com/opencontainers/runtime-spec/specs-go" "github.com/sirupsen/logrus" _ "github.com/vishvananda/netlink" "golang.org/x/sys/unix" ) // RemoveUdevRule will remove device udev rule for the stopped container func RemoveUdevRule(state *configs.HookState, hookConfig *hconfig.ContainerHookConfig, spec *specs.Spec) error { udevdCtrl := udevd.NewUdevdController() if err := udevdCtrl.Lock(); err != nil { return err } defer udevdCtrl.Unlock() if err := udevdCtrl.LoadRules(); err != nil { return err } defer udevdCtrl.ToDisk() for _, dev := range hookConfig.Devices { // re-calc the dest path of device. resolvDev := calcPathForDevice(state.Root, dev) device, err := libdevice.ParseDevice(resolvDev) if err != nil { logrus.Errorf("[device-hook] Add device (%s), parse device failed: %v", resolvDev, err) continue } if device.Type == "c" { continue } devType, err := types.GetDeviceType(device.PathOnHost) if err != nil { return err } if devType == "disk" { udevdCtrl.RemoveRule(&udevd.Rule{ Name: dev.PathOnHost, CtrDevName: dev.PathInContainer, Container: state.ID, }) } } return nil } // RemoveNetworkDevices will remove network device after container stop. func RemoveNetworkDevices(state *configs.HookState, hookConfig *hconfig.ContainerHookConfig, spec *specs.Spec) error { file, err := os.Open(filepath.Join(hconfig.IsuladToolsDirNetns, state.ID)) if err != nil { logrus.Errorf("[device-hook] Failed to Open netns file %v", err) return fmt.Errorf("[device-hook] Failed to Open netns file %v", err) } defer func() { if err := os.Remove(file.Name()); err != nil { logrus.Errorf("Failed to remove fileName err: %v", err) } file.Close() }() for _, nic := range hookConfig.NetworkInterfaces { err := libnetwork.DelNicFromContainer(filepath.Join(hconfig.IsuladToolsDirNetns, state.ID), nic) if err != nil { logrus.Errorf("[device-hook] Failed to del network interface (%s) from container %s: %v", nic.String(), state.ID, err) continue } logrus.Debugf("Removed %s interface: (%s,%s)", nic.Type, nic.HostNicName, nic.CtrNicName) } if err = unix.Unmount(file.Name(), unix.MNT_DETACH); err != nil { err = fmt.Errorf("[device-hook] Failed to Unmount netns file %v", err) logrus.Errorf("%v", err) } return err } func stringToBind(containerRoot, bindstr string, spec *specs.Spec, isCreate bool) (*types.Bind, error) { // we have done the chroot resolvBind, err := calcPathForBind(containerRoot, bindstr) if err != nil { return nil, fmt.Errorf("Re-Calculate bind(%s) failed: %v", bindstr, err) } bind, err := libdevice.ParseBind(resolvBind, spec, isCreate) if err != nil { return nil, fmt.Errorf("Parse bind(%s) failed: %v", bindstr, err) } return bind, nil } // RemoveSharedPath will remove shared path after container stop. func RemoveSharedPath(state *configs.HookState, hookConfig *hconfig.ContainerHookConfig, spec *specs.Spec) error { for _, bindstr := range hookConfig.Binds { // we have do the chroot bind, err := stringToBind("/", bindstr, spec, false) if err != nil { logrus.Errorf("RemoveSharedPath failed: %s", err) continue } if err := utils.RemoveTransferPath(state.ID, bind); err != nil { logrus.Errorf("RemoveSharedPath failed: Path: %v failed: %s", bind, err) } } utils.RemoveContainerSpecPath(state.ID) return nil } // prestartHook is the main logic of device hook func postStopHook(data *hookData, withRelabel bool) { var actions []HookAction actions = []HookAction{RemoveUdevRule, RemoveNetworkDevices, RemoveSharedPath} if withRelabel { actions = append(actions, PostStopRelabel) } for _, ac := range actions { if err := ac(data.state, data.hookConfig, data.spec); err != nil { logrus.Errorf("Failed with err: %v", err) } } }