| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190 |
- // 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 hostimage
- import (
- "context"
- "fmt"
- "net/http"
- "os"
- "path"
- execlient "yunion.io/x/executor/client"
- "yunion.io/x/jsonutils"
- "yunion.io/x/log"
- "yunion.io/x/onecloud/pkg/appsrv"
- app_common "yunion.io/x/onecloud/pkg/cloudcommon/app"
- "yunion.io/x/onecloud/pkg/cloudcommon/consts"
- common_options "yunion.io/x/onecloud/pkg/cloudcommon/options"
- "yunion.io/x/onecloud/pkg/httperrors"
- "yunion.io/x/onecloud/pkg/mcclient/auth"
- "yunion.io/x/onecloud/pkg/util/procutils"
- "yunion.io/x/onecloud/pkg/util/qemuimg"
- "yunion.io/x/onecloud/pkg/util/seclib2"
- )
- type SHostImageOptions struct {
- common_options.HostCommonOptions
- LocalImagePath []string `help:"Local Image Paths"`
- LVMVolumeGroups []string `help:"LVM Volume Groups(vgs)"`
- SnapshotDirSuffix string `help:"Snapshot dir name equal diskId concat snapshot dir suffix" default:"_snap"`
- HostImageNbdPidDir string `help:"Host-image nbd pid files dir " default:"/var/run/onecloud/host-image"`
- CommonConfigFile string `help:"common config file for container"`
- }
- var (
- HostImageOptions SHostImageOptions
- nbdExportManager *SNbdExportManager
- )
- func StartService() {
- consts.SetServiceType("host-image")
- common_options.ParseOptions(&HostImageOptions, os.Args, "host.conf", "host-image")
- if len(HostImageOptions.CommonConfigFile) > 0 {
- baseOpt := HostImageOptions.BaseOptions.BaseOptions
- commonCfg := new(common_options.CommonOptions)
- commonCfg.Config = HostImageOptions.CommonConfigFile
- common_options.ParseOptions(commonCfg, []string{"host"}, "common.conf", "host")
- HostImageOptions.CommonOptions = *commonCfg
- HostImageOptions.BaseOptions.BaseOptions = baseOpt
- }
- log.Infof("exec socket path: %s", HostImageOptions.ExecutorSocketPath)
- if HostImageOptions.EnableRemoteExecutor {
- execlient.Init(HostImageOptions.ExecutorSocketPath)
- execlient.SetTimeoutSeconds(HostImageOptions.ExecutorConnectTimeoutSeconds)
- procutils.SetRemoteExecutor()
- }
- nbdExportManager = NewNbdExportManager()
- output, err := procutils.NewCommand("mkdir", "-p", HostImageOptions.HostImageNbdPidDir).Output()
- if err != nil {
- log.Fatalf("failed to create path %s: %s %s", HostImageOptions.HostImageNbdPidDir, output, err)
- }
- HostImageOptions.EnableSsl = false
- HostImageOptions.Port += 40000
- app_common.InitAuth(&HostImageOptions.CommonOptions, func() {
- log.Infof("Auth complete!!")
- })
- app := app_common.InitApp(&HostImageOptions.BaseOptions, false)
- initHandlers(app, "")
- app_common.ServeForever(app, &HostImageOptions.BaseOptions)
- }
- func initHandlers(app *appsrv.Application, prefix string) {
- app.AddHandler("POST", fmt.Sprintf("%s/disks/<sid>/nbd-export", prefix), auth.Authenticate(imageNbdExport))
- app.AddHandler("POST", fmt.Sprintf("%s/snapshots/<diskId>/<sid>/nbd-export", prefix), auth.Authenticate(imageNbdExport))
- app.AddHandler("POST", fmt.Sprintf("%s/disks/<sid>/nbd-close", prefix), auth.Authenticate(imageNbdClose))
- app.AddHandler("POST", fmt.Sprintf("%s/snapshots/<diskId>/<sid>/nbd-close", prefix), auth.Authenticate(imageNbdClose))
- }
- func getDiskPath(diskId string) string {
- for _, imagePath := range HostImageOptions.LocalImagePath {
- diskPath := path.Join(imagePath, diskId)
- if _, err := procutils.RemoteStat(diskPath); err == nil {
- return diskPath
- }
- }
- for _, vg := range HostImageOptions.LVMVolumeGroups {
- diskPath := path.Join("/dev", vg, diskId)
- if _, err := procutils.RemoteStat(diskPath); err == nil {
- return diskPath
- }
- }
- return ""
- }
- func getSnapshotPath(diskId, snapshotId string) string {
- for _, imagePath := range HostImageOptions.LocalImagePath {
- diskPath := path.Join(imagePath, "snapshots",
- diskId+HostImageOptions.SnapshotDirSuffix, snapshotId)
- if _, err := procutils.RemoteStat(diskPath); err == nil {
- return diskPath
- }
- }
- for _, vg := range HostImageOptions.LVMVolumeGroups {
- diskPath := path.Join("/dev", vg, "snap_"+snapshotId)
- if _, err := procutils.RemoteStat(diskPath); err == nil {
- return diskPath
- }
- }
- return ""
- }
- func inputCheck(ctx context.Context, w http.ResponseWriter, r *http.Request) (string, string, error) {
- params, _, body := appsrv.FetchEnv(ctx, w, r)
- var sid = params["<sid>"]
- var imagePath string
- var remoteDiskId string
- remoteDiskId, _ = body.GetString("disk_id")
- if remoteDiskId == "" {
- return "", "", httperrors.NewMissingParameterError("disk_id")
- }
- if diskId, ok := params["<diskId>"]; ok {
- imagePath = getSnapshotPath(diskId, sid)
- } else {
- imagePath = getDiskPath(sid)
- }
- if len(imagePath) == 0 {
- return "", "", httperrors.NewNotFoundError("Disk not found")
- }
- return imagePath, remoteDiskId, nil
- }
- func imageNbdExport(ctx context.Context, w http.ResponseWriter, r *http.Request) {
- imagePath, targetDiskId, err := inputCheck(ctx, w, r)
- if err != nil {
- httperrors.GeneralServerError(ctx, w, err)
- return
- }
- imageInfo := qemuimg.SImageInfo{
- Path: imagePath,
- }
- encryptKey := r.Header.Get("X-Encrypt-Key")
- if len(encryptKey) > 0 {
- imageInfo.Password = encryptKey
- imageInfo.EncryptAlg = seclib2.TSymEncAlg(r.Header.Get("X-Encrypt-Alg"))
- }
- nbdPort, err := nbdExportManager.QemuNbdStartExport(imageInfo, targetDiskId)
- if err != nil {
- httperrors.GeneralServerError(ctx, w, err)
- return
- }
- log.Infof("Image %s request nbd export with port %d", targetDiskId, nbdPort)
- ret := jsonutils.NewDict()
- ret.Set("nbd_port", jsonutils.NewInt(int64(nbdPort)))
- appsrv.SendJSON(w, ret)
- }
- func imageNbdClose(ctx context.Context, w http.ResponseWriter, r *http.Request) {
- _, targetDiskId, err := inputCheck(ctx, w, r)
- if err != nil {
- httperrors.GeneralServerError(ctx, w, err)
- return
- }
- err = nbdExportManager.QemuNbdCloseExport(targetDiskId)
- if err != nil {
- httperrors.GeneralServerError(ctx, w, err)
- return
- }
- log.Infof("Image %s request nbd close export with port", targetDiskId)
- appsrv.SendStruct(w, map[string]string{"result": "ok"})
- }
|