// 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" "strings" "yunion.io/x/pkg/utils" "yunion.io/x/onecloud/pkg/apis" "yunion.io/x/onecloud/pkg/cloudcommon/types" deployapi "yunion.io/x/onecloud/pkg/hostman/hostdeployer/apis" "yunion.io/x/onecloud/pkg/util/macutils" "yunion.io/x/onecloud/pkg/util/seclib2" "yunion.io/x/onecloud/pkg/util/stringutils2" ) type SMacOSRootFs struct { *sGuestRootFsDriver scripts []string } func NewMacOSRootFs(part IDiskPartition) IRootFsDriver { return &SMacOSRootFs{sGuestRootFsDriver: newGuestRootFsDriver(part)} } func (m *SMacOSRootFs) IsFsCaseInsensitive() bool { return false } func (m *SMacOSRootFs) GetName() string { return "macOS" } func (m *SMacOSRootFs) String() string { return "MacOSRootFs" } func (m *SMacOSRootFs) GetLoginAccount(rootFs IDiskPartition, user string, defaultRootUser bool, windowsDefaultAdminUser bool) (string, error) { selUsr := "" usrs := m.rootFs.ListDir("/Users", false) if len(usrs) > 0 { for _, usr := range usrs { if usr != "Shared" && usr[0] != '.' { if len(selUsr) < len(usr) { selUsr = usr } } } } return selUsr, nil } func (m *SMacOSRootFs) RootSignatures() []string { return []string{ "/Applications", "/Library", "/Network", "/System", "/System/Library", "/Volumes", "/Users", "/usr", "/private/etc", "/private/var", "/bin", "/sbin", "/dev", } } func (m *SMacOSRootFs) DeployPublicKey(rootfs IDiskPartition, uname string, pubkeys *deployapi.SSHKeys) error { usrDir := fmt.Sprintf("/Users/%s", uname) return DeployAuthorizedKeys(m.rootFs, usrDir, pubkeys, false, false) } func (m *SMacOSRootFs) addScripts(lines []string) { if m.scripts == nil { m.scripts = []string{} } m.scripts = append(m.scripts, lines...) m.scripts = append(m.scripts, "") } func (m *SMacOSRootFs) ChangeUserPasswd(part IDiskPartition, account, gid, publicKey, password string, isRandomPassword bool) (string, error) { lines := []string{ fmt.Sprintf("dscl . -passwd /Users/%s %s", account, password), fmt.Sprintf("rm -fr /Users/%s/Library/Keychains/*", account), } m.addScripts(lines) if len(publicKey) > 0 { return seclib2.EncryptBase64(publicKey, password) } else { return utils.EncryptAESBase64(gid, password) } } func (m *SMacOSRootFs) DeployHostname(part IDiskPartition, hostname, domain string) error { lines := []string{ fmt.Sprintf("scutil --set HostName '%s'", stringutils2.EscapeString(hostname, nil)), fmt.Sprintf("scutil --set ComputerName '%s'", stringutils2.EscapeString(hostname, nil)), fmt.Sprintf("scutil --set LocalHostName '%s'", stringutils2.EscapeString(hostname, nil)), } m.addScripts(lines) return nil } func (m *SMacOSRootFs) DeployHosts(part IDiskPartition, hn, domain string, ips []string) error { return nil } func (m *SMacOSRootFs) GetReleaseInfo(IDiskPartition) *deployapi.ReleaseInfo { spath := "/System/Library/CoreServices/SystemVersion.plist" sInfo, _ := m.rootFs.FileGetContents(spath, false) info := macutils.ParsePlist(sInfo) distro, _ := info["ProductName"] version, _ := info["ProductUserVisibleVersion"] return &deployapi.ReleaseInfo{ Distro: distro, Version: version, Arch: apis.OS_ARCH_X86_64, } } func (m *SMacOSRootFs) GetOs() string { return "macOs" } func (m *SMacOSRootFs) DeployNetworkingScripts(rootfs IDiskPartition, nics []*types.SServerNic) error { return nil } func (m *SMacOSRootFs) PrepareFsForTemplate(IDiskPartition) error { sshDir := "/private/etc/ssh" if m.rootFs.Exists(sshDir, false) { for _, f := range m.rootFs.ListDir(sshDir, false) { if strings.HasSuffix(f, "_key") || strings.HasSuffix(f, "_key.pub") { m.rootFs.Remove(path.Join(sshDir, f), false) } } } tmpDirs := []string{"/private/tmp", "/private/var/tmp", "/private/var/vm", "/System/Library/Caches", "/Library/Caches"} logDirs := []string{"/var/log", "/Library/Logs"} users := m.rootFs.ListDir("/Users", false) if len(users) > 0 { for _, usr := range users { if usr != "Shared" && usr[0] != '.' { tmpDirs = append(tmpDirs, fmt.Sprintf("/Users/%s/Library", usr)) } } } for _, dir := range tmpDirs { if m.rootFs.Exists(dir, false) { if err := m.rootFs.Cleandir(dir, false, false); err != nil { return err } } } for _, dir := range logDirs { if m.rootFs.Exists(dir, false) { if err := m.rootFs.Zerofiles(dir, false); err != nil { return err } } } for _, dir := range []string{"/private/var/spool", "/private/var/run"} { if m.rootFs.Exists(dir, false) { if err := m.rootFs.Cleandir(dir, true, false); err != nil { return err } } } return nil } func (m *SMacOSRootFs) CommitChanges(part IDiskPartition) error { var ( label = "com.meituan.cloud_init" spath = "/private/var/cloud_init.sh" ) cont := macutils.LaunchdRun(label, spath) if err := m.rootFs.FilePutContents(fmt.Sprintf("/Library/LaunchDaemons/%s.plist", label), cont, false, false); err != nil { return err } lines := []string{"systemsetup -setcomputersleep Never", "systemsetup -setdisplaysleep Never", "systemsetup -setharddisksleep Never", "systemsetup -settimezone Asia/Shanghai", "networksetup -detectnewhardware", // # "diskutil disableJournal /", } m.addScripts(lines) m.addScripts([]string{fmt.Sprintf("echo > %s", spath)}) cont = strings.Join(m.scripts, "\n") + "\n" return m.rootFs.FilePutContents(spath, cont, false, false) } func (d *SMacOSRootFs) ConfigSshd(loginAccount, loginPassword string, sshPort int) error { return nil }