| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298 |
- // 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 fsdriver
- import (
- "fmt"
- "path"
- "path/filepath"
- "strings"
- "syscall"
- "yunion.io/x/jsonutils"
- "yunion.io/x/log"
- "yunion.io/x/pkg/errors"
- "yunion.io/x/pkg/object"
- "yunion.io/x/onecloud/pkg/cloudcommon/types"
- deployapi "yunion.io/x/onecloud/pkg/hostman/hostdeployer/apis"
- "yunion.io/x/onecloud/pkg/httperrors"
- "yunion.io/x/onecloud/pkg/mcclient"
- modules "yunion.io/x/onecloud/pkg/mcclient/modules/compute"
- "yunion.io/x/onecloud/pkg/util/procutils"
- )
- type sGuestRootFsDriver struct {
- object.SObject
- rootFs IDiskPartition
- }
- func newGuestRootFsDriver(rootFs IDiskPartition) *sGuestRootFsDriver {
- return &sGuestRootFsDriver{
- rootFs: rootFs,
- }
- }
- func (d *sGuestRootFsDriver) GetIRootFsDriver() IRootFsDriver {
- return d.GetVirtualObject().(IRootFsDriver)
- }
- func (d *sGuestRootFsDriver) DeployFiles(deploys []*deployapi.DeployContent) error {
- caseInsensitive := d.IsFsCaseInsensitive()
- for _, deploy := range deploys {
- var modAppend = false
- if deploy.Action == "append" {
- modAppend = true
- }
- if len(deploy.Path) == 0 {
- return fmt.Errorf("Deploy file missing param path")
- }
- dirname := filepath.Dir(deploy.Path)
- if !d.GetPartition().Exists(dirname, caseInsensitive) {
- modeRWXOwner := syscall.S_IRWXU | syscall.S_IRGRP | syscall.S_IXGRP | syscall.S_IROTH | syscall.S_IXOTH
- err := d.GetPartition().Mkdir(dirname, modeRWXOwner, caseInsensitive)
- if err != nil {
- log.Errorf("Mkdir %s fail %s", dirname, err)
- return errors.Wrap(err, "Mkdir")
- }
- err = d.GetPartition().Chmod(dirname, uint32(modeRWXOwner), caseInsensitive)
- if err != nil {
- log.Errorf("Chmod %s fail %s", dirname, err)
- return errors.Wrap(err, "Chmod")
- }
- }
- if len(deploy.Content) > 0 {
- err := d.GetPartition().FilePutContents(deploy.Path, deploy.Content, modAppend, caseInsensitive)
- if err != nil {
- log.Errorln(err)
- return err
- }
- }
- }
- return nil
- }
- func (d *sGuestRootFsDriver) DeployTelegraf(string) (bool, error) {
- return false, nil
- }
- func (d *sGuestRootFsDriver) GetPartition() IDiskPartition {
- return d.rootFs
- }
- func (d *sGuestRootFsDriver) RootExcludeSignatures() []string {
- return []string{}
- }
- func (d *sGuestRootFsDriver) IsFsCaseInsensitive() bool {
- return false
- }
- func (d *sGuestRootFsDriver) DeployYunionroot(rootfs IDiskPartition, pubkeys *deployapi.SSHKeys, isInit, enableCloudInit bool) error {
- return nil
- }
- func (d *sGuestRootFsDriver) DeployUdevSubsystemScripts(rootfs IDiskPartition) error {
- return nil
- }
- func (d *sGuestRootFsDriver) DeployStandbyNetworkingScripts(part IDiskPartition, nics, nicsStandby []*types.SServerNic) error {
- return nil
- }
- func (d *sGuestRootFsDriver) DeployFstabScripts(_ IDiskPartition, _ []*deployapi.Disk) error {
- return nil
- }
- func (d *sGuestRootFsDriver) EnableSerialConsole(rootfs IDiskPartition, sysInfo *jsonutils.JSONDict) error {
- return nil
- }
- func (d *sGuestRootFsDriver) DisableSerialConsole(rootfs IDiskPartition) error {
- return nil
- }
- func (d *sGuestRootFsDriver) CommitChanges(rootfs IDiskPartition) error {
- return nil
- }
- func (d *sGuestRootFsDriver) DetectIsUEFISupport(IDiskPartition) bool {
- return false
- }
- func (l *sGuestRootFsDriver) IsCloudinitInstall() bool {
- return false
- }
- func (l *sGuestRootFsDriver) IsResizeFsPartitionSupport() bool {
- return true
- }
- func (r *sGuestRootFsDriver) CleanNetworkScripts(rootFs IDiskPartition) error {
- return nil
- }
- func (r *sGuestRootFsDriver) AllowAdminLogin() bool {
- return true
- }
- func (m *sGuestRootFsDriver) DeployQgaBlackList(part IDiskPartition) error {
- return nil
- }
- func (r *sGuestRootFsDriver) DeployQgaService(part IDiskPartition) error {
- return nil
- }
- const (
- modeAuthorizedKeysRWX = syscall.S_IRUSR | syscall.S_IWUSR | syscall.S_IXUSR
- modeAuthorizedKeysRW = syscall.S_IRUSR | syscall.S_IWUSR
- )
- func deployAuthorizedKeys(rootFs IDiskPartition, authFile string, uid, gid int, pubkeys *deployapi.SSHKeys, replace bool, admin bool) error {
- var oldKeys = ""
- if !replace {
- bOldKeys, _ := rootFs.FileGetContents(authFile, false)
- oldKeys = string(bOldKeys)
- }
- newKeys := MergeAuthorizedKeys(oldKeys, pubkeys, admin)
- if err := rootFs.FilePutContents(authFile, newKeys, false, false); err != nil {
- return fmt.Errorf("Put keys to %s: %v", authFile, err)
- }
- if err := rootFs.Chown(authFile, uid, gid, false); err != nil {
- return fmt.Errorf("Chown %s to uid: %d, gid: %d: %v", authFile, uid, gid, err)
- }
- if err := rootFs.Chmod(authFile, uint32(modeAuthorizedKeysRW), false); err != nil {
- return fmt.Errorf("Chmod %s to %d error: %v", authFile, uint32(modeAuthorizedKeysRW), err)
- }
- return nil
- }
- func DeployAuthorizedKeys(rootFs IDiskPartition, usrDir string, pubkeys *deployapi.SSHKeys, replace bool, admin bool) error {
- usrStat := rootFs.Stat(usrDir, false)
- if usrStat != nil {
- sshDir := path.Join(usrDir, ".ssh")
- authFile := path.Join(sshDir, "authorized_keys")
- fStat, _ := usrStat.Sys().(*syscall.Stat_t)
- uid := int(fStat.Uid)
- gid := int(fStat.Gid)
- if !rootFs.Exists(sshDir, false) {
- err := rootFs.Mkdir(sshDir, modeAuthorizedKeysRWX, false)
- if err != nil {
- log.Errorln(err)
- return err
- }
- err = rootFs.Chown(sshDir, uid, gid, false)
- if err != nil {
- log.Errorln(err)
- return err
- }
- }
- return deployAuthorizedKeys(rootFs, authFile, uid, gid, pubkeys, replace, admin)
- }
- return nil
- }
- const sshKeySignature = "@yunioncloudpods"
- func MergeAuthorizedKeys(oldKeys string, pubkeys *deployapi.SSHKeys, isAdmin bool) string {
- var allkeys = make(map[string]string)
- if len(oldKeys) > 0 {
- for _, line := range strings.Split(oldKeys, "\n") {
- line = strings.TrimSpace(line)
- dat := strings.Split(line, " ")
- if len(dat) > 1 {
- if len(dat) > 2 && dat[2] == sshKeySignature {
- // skip ssh keys with signature
- continue
- }
- if _, ok := allkeys[dat[1]]; !ok {
- allkeys[dat[1]] = line
- }
- }
- }
- }
- if len(pubkeys.DeletePublicKey) > 0 {
- dat := strings.Split(pubkeys.DeletePublicKey, " ")
- if len(dat) > 1 {
- if _, ok := allkeys[dat[1]]; ok {
- delete(allkeys, dat[1])
- }
- }
- }
- var candiateKeys []string
- if isAdmin {
- candiateKeys = []string{pubkeys.AdminPublicKey, pubkeys.ProjectPublicKey}
- } else {
- candiateKeys = []string{pubkeys.PublicKey}
- }
- for _, k := range candiateKeys {
- if len(k) > 0 {
- k = strings.TrimSpace(k)
- dat := strings.Split(k, " ")
- if len(dat) > 1 {
- if _, ok := allkeys[dat[1]]; !ok {
- allkeys[dat[1]] = strings.Join([]string{dat[0], dat[1], sshKeySignature}, " ")
- }
- }
- }
- }
- var keys = make([]string, 0)
- for _, val := range allkeys {
- keys = append(keys, val)
- }
- return strings.Join(keys, "\n") + "\n"
- }
- func DeployAdminAuthorizedKeys(s *mcclient.ClientSession) error {
- sshDir := path.Join("/root", ".ssh")
- output, err := procutils.NewRemoteCommandAsFarAsPossible("mkdir", "-p", sshDir).Output()
- if err != nil {
- return errors.Wrapf(err, "mkdir .ssh %s", output)
- }
- query := jsonutils.NewDict()
- query.Set("admin", jsonutils.JSONTrue)
- ret, err := modules.Sshkeypairs.List(s, query)
- if err != nil {
- return errors.Wrap(err, "modules.Sshkeypairs.List")
- }
- if len(ret.Data) == 0 {
- return errors.Wrap(httperrors.ErrNotFound, "Not found admin sshkey")
- }
- keys := ret.Data[0]
- adminPublicKey, _ := keys.GetString("public_key")
- pubKeys := &deployapi.SSHKeys{AdminPublicKey: adminPublicKey}
- var oldKeys string
- authFile := path.Join(sshDir, "authorized_keys")
- if procutils.NewRemoteCommandAsFarAsPossible("test", "-f", authFile).Run() == nil {
- output, err := procutils.NewRemoteCommandAsFarAsPossible("cat", authFile).Output()
- if err != nil {
- return errors.Wrapf(err, "cat: %s", output)
- }
- oldKeys = string(output)
- }
- newKeys := MergeAuthorizedKeys(oldKeys, pubKeys, true)
- if output, err := procutils.NewRemoteCommandAsFarAsPossible(
- "sh", "-c", fmt.Sprintf("echo '%s' > %s", newKeys, authFile)).Output(); err != nil {
- return errors.Wrapf(err, "write public keys: %s", output)
- }
- if output, err := procutils.NewRemoteCommandAsFarAsPossible(
- "chmod", "0644", authFile).Output(); err != nil {
- return errors.Wrapf(err, "chmod failed %s", output)
- }
- return nil
- }
|