linux.go 74 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331233223332334233523362337233823392340234123422343234423452346234723482349235023512352235323542355235623572358235923602361236223632364236523662367236823692370237123722373237423752376237723782379238023812382238323842385238623872388238923902391239223932394239523962397239823992400240124022403240424052406240724082409241024112412241324142415241624172418241924202421242224232424242524262427242824292430243124322433243424352436243724382439244024412442244324442445244624472448244924502451245224532454245524562457245824592460246124622463246424652466246724682469247024712472247324742475247624772478247924802481248224832484248524862487248824892490249124922493249424952496
  1. // Copyright 2019 Yunion
  2. //
  3. // Licensed under the Apache License, Version 2.0 (the "License");
  4. // you may not use this file except in compliance with the License.
  5. // You may obtain a copy of the License at
  6. //
  7. // http://www.apache.org/licenses/LICENSE-2.0
  8. //
  9. // Unless required by applicable law or agreed to in writing, software
  10. // distributed under the License is distributed on an "AS IS" BASIS,
  11. // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  12. // See the License for the specific language governing permissions and
  13. // limitations under the License.
  14. package fsdriver
  15. import (
  16. "debug/elf"
  17. "fmt"
  18. "os"
  19. "path"
  20. "path/filepath"
  21. "regexp"
  22. "strconv"
  23. "strings"
  24. "syscall"
  25. "gopkg.in/yaml.v2"
  26. "yunion.io/x/jsonutils"
  27. "yunion.io/x/log"
  28. "yunion.io/x/pkg/errors"
  29. "yunion.io/x/pkg/utils"
  30. "yunion.io/x/onecloud/pkg/apis"
  31. api "yunion.io/x/onecloud/pkg/apis/compute"
  32. "yunion.io/x/onecloud/pkg/cloudcommon/consts"
  33. "yunion.io/x/onecloud/pkg/cloudcommon/types"
  34. deployapi "yunion.io/x/onecloud/pkg/hostman/hostdeployer/apis"
  35. "yunion.io/x/onecloud/pkg/util/coreosutils"
  36. "yunion.io/x/onecloud/pkg/util/fileutils2"
  37. "yunion.io/x/onecloud/pkg/util/fstabutils"
  38. "yunion.io/x/onecloud/pkg/util/netutils2"
  39. "yunion.io/x/onecloud/pkg/util/procutils"
  40. "yunion.io/x/onecloud/pkg/util/pwquality"
  41. "yunion.io/x/onecloud/pkg/util/seclib2"
  42. "yunion.io/x/onecloud/pkg/util/sysutils"
  43. )
  44. const (
  45. ROOT_USER = "root"
  46. YUNIONROOT_USER = "cloudroot"
  47. TELEGRAF_BINARY_PATH = "/opt/yunion/bin/telegraf"
  48. SUPERVISE_BINARY_PATH = "/opt/yunion/bin/supervise"
  49. QGA_BINARY_PATH = "/opt/yunion/bin/qemu-ga"
  50. QGA_WIN_MSI_INSTALLER_PATH = "/opt/yunion/bin/qemu-ga-x86_64.msi"
  51. )
  52. var (
  53. NetDevPrefix = "eth"
  54. NetDevPrefixEN = "en"
  55. IBNetDevPrefix = "ib"
  56. )
  57. func GetNetDevPrefix(nics []*types.SServerNic) string {
  58. if NicsHasDifferentDriver(nics) {
  59. return NetDevPrefixEN
  60. } else {
  61. return NetDevPrefix
  62. }
  63. }
  64. func GetIBNetDevPrefix() string {
  65. return IBNetDevPrefix
  66. }
  67. func NicsHasDifferentDriver(nics []*types.SServerNic) bool {
  68. m := make(map[string]int)
  69. for i := 0; i < len(nics); i++ {
  70. if _, ok := m[nics[i].Driver]; !ok {
  71. m[nics[i].Driver] = 1
  72. }
  73. }
  74. if len(m) > 1 {
  75. return true
  76. }
  77. return false
  78. }
  79. type sLinuxRootFs struct {
  80. *sGuestRootFsDriver
  81. }
  82. func newLinuxRootFs(part IDiskPartition) *sLinuxRootFs {
  83. return &sLinuxRootFs{
  84. sGuestRootFsDriver: newGuestRootFsDriver(part),
  85. }
  86. }
  87. func (l *sLinuxRootFs) RootSignatures() []string {
  88. return []string{"/bin", "/etc", "/boot", "/lib", "/usr"}
  89. }
  90. func getHostname(hostname, domain string) string {
  91. if len(domain) > 0 {
  92. return fmt.Sprintf("%s.%s", hostname, domain)
  93. } else {
  94. return hostname
  95. }
  96. }
  97. func (l *sLinuxRootFs) DeployQgaService(rootFs IDiskPartition) error {
  98. qemuGuestAgentPath := "/usr/bin/qemu-ga"
  99. if rootFs.Exists(qemuGuestAgentPath, false) {
  100. // qemu-ga has been installed
  101. return nil
  102. }
  103. output, err := procutils.NewCommand("cp", "-f",
  104. QGA_BINARY_PATH, path.Join(rootFs.GetMountPath(), qemuGuestAgentPath)).Output()
  105. if err != nil {
  106. return errors.Wrapf(err, "cp qga binary failed %s", output)
  107. }
  108. if l.isSupportSystemd() {
  109. udevPath := "/etc/udev/rules.d/"
  110. if rootFs.Exists(udevPath, false) {
  111. rules := rootFs.ListDir(udevPath, false)
  112. for _, rule := range rules {
  113. if strings.Index(rule, "qemu-guest-agent.rules") > 0 {
  114. rootFs.Remove(path.Join(udevPath, rule), false)
  115. }
  116. }
  117. qgaRules := `SUBSYSTEM=="virtio-ports", ATTR{name}=="org.qemu.guest_agent.0", \
  118. TAG+="systemd" ENV{SYSTEMD_WANTS}="qemu-guest-agent.service"` + "\n"
  119. if err := rootFs.FilePutContents(path.Join(udevPath, "99-qemu-guest-agent.rules"), qgaRules, false, false); err != nil {
  120. return err
  121. }
  122. }
  123. if err := l.InstallQemuGuestAgentSystemd(); err != nil {
  124. return errors.Wrap(err, "qga InstallQemuGuestAgentSystemd")
  125. }
  126. } else {
  127. initCmd := qemuGuestAgentPath
  128. if err := l.installCrond(initCmd); err != nil {
  129. return errors.Wrap(err, "qga installCrond")
  130. }
  131. }
  132. return nil
  133. }
  134. func (l *sLinuxRootFs) DeployQgaBlackList(rootFs IDiskPartition) error {
  135. var modeRwxOwner = syscall.S_IRUSR | syscall.S_IWUSR | syscall.S_IXUSR
  136. var qgaConfDir = "/etc/sysconfig"
  137. var etcSysconfigQemuga = path.Join(qgaConfDir, "qemu-ga")
  138. if err := rootFs.Mkdir(qgaConfDir, modeRwxOwner, false); err != nil {
  139. return errors.Wrap(err, "mkdir qga conf dir")
  140. }
  141. blackListContent := `# This is a systemd environment file, not a shell script.
  142. # It provides settings for \"/lib/systemd/system/qemu-guest-agent.service\".
  143. # Comma-separated blacklist of RPCs to disable, or empty list to enable all.
  144. #
  145. # You can get the list of RPC commands using \"qemu-ga --blacklist='?'\".
  146. # There should be no spaces between commas and commands in the blacklist.
  147. # BLACKLIST_RPC=guest-file-open,guest-file-close,guest-file-read,guest-file-write,guest-file-seek,guest-file-flush,guest-exec,guest-exec-status
  148. # Fsfreeze hook script specification.
  149. #
  150. # FSFREEZE_HOOK_PATHNAME=/dev/null : disables the feature.
  151. #
  152. # FSFREEZE_HOOK_PATHNAME=/path/to/executable : enables the feature with the
  153. # specified binary or shell script.
  154. #
  155. # FSFREEZE_HOOK_PATHNAME= : enables the feature with the
  156. # default value (invoke \"qemu-ga --help\" to interrogate).
  157. FSFREEZE_HOOK_PATHNAME=/etc/qemu-ga/fsfreeze-hook"
  158. `
  159. if err := rootFs.FilePutContents(etcSysconfigQemuga, blackListContent, false, false); err != nil {
  160. return errors.Wrap(err, "etcSysconfigQemuga error")
  161. }
  162. return nil
  163. }
  164. func (l *sLinuxRootFs) DeployHosts(rootFs IDiskPartition, hostname, domain string, ips []string) error {
  165. var etcHosts = "/etc/hosts"
  166. var oldHostFile string
  167. if rootFs.Exists(etcHosts, false) {
  168. oldhf, err := rootFs.FileGetContents(etcHosts, false)
  169. if err != nil {
  170. return err
  171. }
  172. oldHostFile = string(oldhf)
  173. }
  174. return rootFs.FilePutContents(etcHosts, fileutils2.FormatHostsFile(oldHostFile, ips, hostname, getHostname(hostname, domain)), false, false)
  175. }
  176. func (l *sLinuxRootFs) GetLoginAccount(rootFs IDiskPartition, sUser string, defaultRootUser bool, windowsDefaultAdminUser bool) (string, error) {
  177. if len(sUser) > 0 {
  178. if _, err := rootFs.CheckOrAddUser(sUser, "", false); err != nil && !strings.Contains(err.Error(), "already exists") {
  179. return "", fmt.Errorf("UserAdd %s: %v", sUser, err)
  180. }
  181. if err := l.EnableUserSudo(rootFs, sUser); err != nil {
  182. return "", fmt.Errorf("EnableUserSudo: %s", err)
  183. }
  184. return sUser, nil
  185. }
  186. var selUsr string
  187. if defaultRootUser && rootFs.Exists("/root", false) && l.GetIRootFsDriver().AllowAdminLogin() {
  188. selUsr = ROOT_USER
  189. } else {
  190. usrs := rootFs.ListDir("/home", false)
  191. for _, usr := range usrs {
  192. if usr == YUNIONROOT_USER {
  193. continue
  194. }
  195. if len(selUsr) == 0 || len(selUsr) > len(usr) {
  196. selUsr = usr
  197. }
  198. }
  199. if len(selUsr) == 0 && rootFs.Exists("/root", false) {
  200. selUsr = ROOT_USER
  201. }
  202. }
  203. return selUsr, nil
  204. }
  205. func (l *sLinuxRootFs) checkInputPasswd(rootFs IDiskPartition, config *pwquality.Config, account, gid, publicKey, password string) string {
  206. if config == nil {
  207. return password
  208. }
  209. err := config.Validate(password, account)
  210. if err != nil && errors.Cause(err) == pwquality.ErrPasswordTooWeak {
  211. log.Infof("password %s too weak, try regenerate password", password)
  212. npassword := config.GeneratePassword(seclib2.RandomPassword2)
  213. if len(npassword) > 0 {
  214. log.Infof("regenerate password %s", npassword)
  215. password = npassword
  216. }
  217. }
  218. return password
  219. }
  220. func (l *sLinuxRootFs) ChangeUserPasswd(rootFs IDiskPartition, account, gid, publicKey, password string, isRandomPassword bool) (string, error) {
  221. var secret string
  222. var err error
  223. err = rootFs.Passwd(account, password, false)
  224. if err == nil {
  225. if len(publicKey) > 0 {
  226. secret, err = seclib2.EncryptBase64(publicKey, password)
  227. } else {
  228. secret, err = utils.EncryptAESBase64(gid, password)
  229. }
  230. if err != nil {
  231. return "", errors.Wrap(err, "Encryption")
  232. }
  233. // put /.autorelabel if selinux enabled
  234. err = rootFs.FilePutContents("/.autorelabel", "", false, false)
  235. if err != nil {
  236. return "", errors.Wrap(err, "fail to put .autorelabel")
  237. }
  238. } else {
  239. return "", fmt.Errorf("ChangeUserPasswd error: %v", err)
  240. }
  241. return secret, err
  242. }
  243. func (l *sLinuxRootFs) DeployPublicKey(rootFs IDiskPartition, selUsr string, pubkeys *deployapi.SSHKeys) error {
  244. var usrDir string
  245. if selUsr == "root" {
  246. usrDir = "/root"
  247. } else {
  248. usrDir = path.Join("/home", selUsr)
  249. }
  250. return DeployAuthorizedKeys(rootFs, usrDir, pubkeys, false, false)
  251. }
  252. func (l *sLinuxRootFs) DeployYunionroot(rootFs IDiskPartition, pubkeys *deployapi.SSHKeys, isInit, enableCloudInit bool) error {
  253. if !consts.AllowVmSELinux() {
  254. l.DisableSelinux(rootFs)
  255. }
  256. if !enableCloudInit && isInit {
  257. l.DisableCloudinit(rootFs)
  258. }
  259. var yunionroot = YUNIONROOT_USER
  260. var rootdir string // := path.Join(cloudrootDirectory, yunionroot)
  261. var err error
  262. if rootdir, err = rootFs.CheckOrAddUser(yunionroot, cloudrootDirectory, true); err != nil {
  263. return errors.Wrap(err, "unable to CheckOrAddUser")
  264. }
  265. log.Infof("DeployYunionroot %s home %s", yunionroot, rootdir)
  266. err = DeployAuthorizedKeys(rootFs, rootdir, pubkeys, true, true)
  267. if err != nil {
  268. log.Infof("DeployAuthorizedKeys error: %s", err.Error())
  269. return fmt.Errorf("DeployAuthorizedKeys: %v", err)
  270. }
  271. if err := l.EnableUserSudo(rootFs, yunionroot); err != nil {
  272. return fmt.Errorf("EnableUserSudo: %v", err)
  273. }
  274. return nil
  275. }
  276. func (l *sLinuxRootFs) EnableUserSudo(rootFs IDiskPartition, user string) error {
  277. var sudoDir = "/etc/sudoers.d"
  278. var content = fmt.Sprintf("%s ALL=(ALL) NOPASSWD:ALL\n", user)
  279. if rootFs.Exists(sudoDir, false) {
  280. filepath := path.Join(sudoDir, fmt.Sprintf("90-%s-users", user))
  281. err := rootFs.FilePutContents(filepath, content, false, false)
  282. if err != nil {
  283. return fmt.Errorf("Write contents to %s: %v", filepath, err)
  284. }
  285. return rootFs.Chmod(filepath, syscall.S_IRUSR|syscall.S_IRGRP, false)
  286. }
  287. return nil
  288. }
  289. func (l *sLinuxRootFs) DisableSelinux(rootFs IDiskPartition) {
  290. selinuxConfig := "/etc/selinux/config"
  291. content := `# This file controls the state of SELinux on the system.
  292. # SELINUX= can take one of these three values:
  293. # enforcing - SELinux security policy is enforced.
  294. # permissive - SELinux prints warnings instead of enforcing.
  295. # disabled - No SELinux policy is loaded.
  296. SELINUX=disabled
  297. # SELINUXTYPE= can take one of three two values:
  298. # targeted - Targeted processes are protected,
  299. # minimum - Modification of targeted policy. Only selected processes are protected.
  300. # mls - Multi Level Security protection.
  301. SELINUXTYPE=targeted
  302. `
  303. if rootFs.Exists(selinuxConfig, false) {
  304. if err := rootFs.FilePutContents(selinuxConfig, content, false, false); err != nil {
  305. log.Errorf("DisableSelinux error: %v", err)
  306. }
  307. }
  308. }
  309. func (l *sLinuxRootFs) DisableCloudinit(rootFs IDiskPartition) {
  310. cloudDir := "/etc/cloud"
  311. cloudDisableFile := "/etc/cloud/cloud-init.disabled"
  312. if rootFs.Exists(cloudDir, false) {
  313. if err := rootFs.FilePutContents(cloudDisableFile, "", false, false); err != nil {
  314. log.Errorf("DisableCloudinit error: %v", err)
  315. }
  316. }
  317. }
  318. func (l *sLinuxRootFs) DeployFstabScripts(rootFs IDiskPartition, disks []*deployapi.Disk) error {
  319. fstabcont, err := rootFs.FileGetContents("/etc/fstab", false)
  320. if err != nil {
  321. return err
  322. }
  323. var dataDiskIdx = 0
  324. var rec string
  325. var modeRwxOwner = syscall.S_IRUSR | syscall.S_IWUSR | syscall.S_IXUSR
  326. var fstab = fstabutils.FSTabFile(string(fstabcont))
  327. if fstab != nil {
  328. fstab = fstab.RemoveDevices(len(disks))
  329. } else {
  330. _fstab := make(fstabutils.FsTab, 0)
  331. fstab = &_fstab
  332. }
  333. for i := 1; i < len(disks); i++ {
  334. diskId := disks[i].DiskId
  335. if len(diskId) == 0 {
  336. diskId = "None"
  337. }
  338. dev := fmt.Sprintf("UUID=%s", diskId)
  339. if !fstab.IsExists(dev) {
  340. fs := disks[i].Fs
  341. if len(fs) > 0 {
  342. if fs == "swap" {
  343. rec = fmt.Sprintf("%s none %s sw 0 0", dev, fs)
  344. } else {
  345. mtPath := disks[i].Mountpoint
  346. if len(mtPath) == 0 {
  347. mtPath = "/data"
  348. if dataDiskIdx > 0 {
  349. mtPath += fmt.Sprintf("%d", dataDiskIdx)
  350. }
  351. dataDiskIdx += 1
  352. }
  353. rec = fmt.Sprintf("%s %s %s defaults 2 2", dev, mtPath, fs)
  354. if !l.rootFs.Exists(mtPath, false) {
  355. if err := l.rootFs.Mkdir(mtPath, modeRwxOwner, false); err != nil {
  356. return err
  357. }
  358. }
  359. }
  360. fstab.AddFsrec(rec)
  361. }
  362. }
  363. }
  364. cf := fstab.ToConf()
  365. return rootFs.FilePutContents("/etc/fstab", cf, false, false)
  366. }
  367. func (l *sLinuxRootFs) DeployNetworkingScripts(rootFs IDiskPartition, nics []*types.SServerNic) error {
  368. netDevPrefix := GetNetDevPrefix(nics)
  369. log.Infof("netdev prefix: %s", netDevPrefix)
  370. udevPath := "/etc/udev/rules.d/"
  371. if rootFs.Exists(udevPath, false) {
  372. rules := rootFs.ListDir(udevPath, false)
  373. for _, rule := range rules {
  374. if strings.Index(rule, "persistent-net.rules") > 0 {
  375. rootFs.Remove(path.Join(udevPath, rule), false)
  376. } else if strings.Index(rule, "persistent-cd.rules") > 0 {
  377. if err := rootFs.FilePutContents(path.Join(udevPath, rule), "", false, false); err != nil {
  378. return err
  379. }
  380. }
  381. }
  382. var nicRules string
  383. for _, nic := range nics {
  384. nicRules += `KERNEL=="*", SUBSYSTEM=="net", ACTION=="add", `
  385. nicRules += `DRIVERS=="?*", `
  386. if nic.NicType == api.NIC_TYPE_INFINIBAND {
  387. nicRules += fmt.Sprintf(`ATTR{address}=="?*%s", ATTR{type}=="32", `, strings.ToLower(nic.Mac))
  388. nicRules += fmt.Sprintf("NAME=\"%s%d\"\n", GetIBNetDevPrefix(), nic.Index)
  389. } else {
  390. nicRules += fmt.Sprintf(`ATTR{address}=="%s", ATTR{type}=="1", `, strings.ToLower(nic.Mac))
  391. nicRules += fmt.Sprintf("NAME=\"%s%d\"\n", netDevPrefix, nic.Index)
  392. }
  393. }
  394. if err := rootFs.FilePutContents(path.Join(udevPath, "70-persistent-net.rules"), nicRules, false, false); err != nil {
  395. return err
  396. }
  397. var usbRules string
  398. usbRules = `SUBSYSTEM=="usb", ATTRS{idVendor}=="1d6b", ATTRS{idProduct}=="0001", `
  399. usbRules += "RUN+=" + `"/bin/sh -c \'echo enabled > /sys$env{DEVPATH}/../power/wakeup\'"` + "\n"
  400. if err := rootFs.FilePutContents(path.Join(udevPath,
  401. "90-usb-tablet-remote-wakeup.rules"), usbRules, false, false); err != nil {
  402. return err
  403. }
  404. }
  405. // deploy docker mtu
  406. {
  407. minMtu := int16(-1)
  408. for _, nic := range nics {
  409. if nic.Mtu > 0 && (minMtu > nic.Mtu || minMtu < 0) {
  410. minMtu = nic.Mtu
  411. }
  412. }
  413. const dockerDaemonConfPath = "/etc/docker/daemon.json"
  414. var daemonConfJson jsonutils.JSONObject
  415. if rootFs.Exists(dockerDaemonConfPath, false) {
  416. content, _ := rootFs.FileGetContents(dockerDaemonConfPath, false)
  417. if len(content) > 0 {
  418. daemonConfJson, _ = jsonutils.Parse(content)
  419. }
  420. } else {
  421. const modeRwxOwner = syscall.S_IRUSR | syscall.S_IWUSR | syscall.S_IXUSR
  422. if err := rootFs.Mkdir("/etc/docker", modeRwxOwner, false); err != nil {
  423. return errors.Wrap(err, "mkdir /etc/docker fail")
  424. }
  425. }
  426. if daemonConfJson == nil {
  427. daemonConfJson = jsonutils.NewDict()
  428. }
  429. daemonConfJson.(*jsonutils.JSONDict).Set("mtu", jsonutils.NewInt(int64(minMtu)))
  430. if err := rootFs.FilePutContents(dockerDaemonConfPath, daemonConfJson.PrettyString(), false, false); err != nil {
  431. return errors.Wrapf(err, "write %s fail", dockerDaemonConfPath)
  432. }
  433. }
  434. // deploy ssh host key
  435. {
  436. err := rootFs.GenerateSshHostKeys()
  437. if err != nil {
  438. // ignore error
  439. log.Errorf("rootFs.GenerateSshHostKeys fail %s", err)
  440. }
  441. }
  442. {
  443. // deploy /etc/gai.conf if both IPv4 and IPv6 are enabled
  444. v4Enabled := false
  445. v6Enabled := false
  446. for _, nic := range nics {
  447. if nic.Ip != "" {
  448. v4Enabled = true
  449. }
  450. if nic.Ip6 != "" {
  451. v6Enabled = true
  452. }
  453. if v4Enabled && v6Enabled {
  454. // prefer IPv4 over IPv6 by default of /etc/gai.conf not present
  455. if !rootFs.Exists("/etc/gai.conf", false) {
  456. rootFs.FilePutContents("/etc/gai.conf", "precedence ::ffff:0:0/96 100\n", false, false)
  457. }
  458. break
  459. }
  460. }
  461. }
  462. return nil
  463. }
  464. func (l *sLinuxRootFs) DeployStandbyNetworkingScripts(rootFs IDiskPartition, nics, nicsStandby []*types.SServerNic) error {
  465. var netDevPrefix = GetNetDevPrefix(nicsStandby)
  466. var udevPath = "/etc/udev/rules.d/"
  467. var nicRules string
  468. for _, nic := range nicsStandby {
  469. if len(nic.NicType) == 0 || nic.NicType != api.NIC_TYPE_IPMI {
  470. nicRules += `KERNEL=="*", SUBSYSTEM=="net", ACTION=="add", `
  471. nicRules += `DRIVERS=="?*", `
  472. mac := nic.Mac
  473. nicRules += fmt.Sprintf(`ATTR{address}=="%s", ATTR{type}=="1", `, strings.ToLower(mac))
  474. idx := nic.Index
  475. nicRules += fmt.Sprintf(`NAME="%s%d"\n`, netDevPrefix, idx)
  476. }
  477. }
  478. if err := rootFs.FilePutContents(path.Join(udevPath, "70-persistent-net.rules"), nicRules, true, false); err != nil {
  479. return err
  480. }
  481. return nil
  482. }
  483. func (l *sLinuxRootFs) DeployUdevSubsystemScripts(rootFs IDiskPartition) error {
  484. udevPath := "/etc/udev/rules.d/"
  485. if rootFs.Exists(udevPath, false) {
  486. cpuMemHotplugRules := `SUBSYSTEM=="cpu", ACTION=="add", TEST=="online", ATTR{online}=="0", ATTR{online}="1"
  487. SUBSYSTEM=="memory", ACTION=="add", TEST=="state", ATTR{state}=="offline", ATTR{state}="online"` + "\n"
  488. if err := rootFs.FilePutContents(path.Join(udevPath, "80-hotplug-cpu-mem.rules"), cpuMemHotplugRules, false, false); err != nil {
  489. return err
  490. }
  491. }
  492. return nil
  493. }
  494. func (l *sLinuxRootFs) GetOs() string {
  495. return "Linux"
  496. }
  497. func (l *sLinuxRootFs) GetArch(rootFs IDiskPartition) string {
  498. // search lib64 first
  499. for _, dir := range []string{"/usr/lib64", "/lib64", "/usr/lib", "/lib"} {
  500. if !rootFs.Exists(dir, false) {
  501. continue
  502. }
  503. files := rootFs.ListDir(dir, false)
  504. for i := 0; i < len(files); i++ {
  505. if strings.HasPrefix(files[i], "ld-") {
  506. p := rootFs.GetLocalPath(path.Join(dir, files[i]), false)
  507. fileInfo, err := os.Stat(p)
  508. if err != nil {
  509. log.Errorf("stat file %s: %s", p, err)
  510. continue
  511. }
  512. if fileInfo.IsDir() {
  513. continue
  514. }
  515. if fileInfo.Mode()&os.ModeSymlink != 0 {
  516. continue
  517. }
  518. rp, err := filepath.EvalSymlinks(p)
  519. if err != nil {
  520. log.Errorf("readlink of %s: %s", p, err)
  521. continue
  522. }
  523. elfHeader, err := elf.Open(rp)
  524. if err != nil {
  525. log.Errorf("failed read file elf %s: %s", rp, err)
  526. continue
  527. }
  528. defer elfHeader.Close()
  529. // https://en.wikipedia.org/wiki/Executable_and_Linkable_Format#File_header
  530. switch elfHeader.Machine {
  531. case elf.EM_X86_64:
  532. return apis.OS_ARCH_X86_64
  533. case elf.EM_386:
  534. return apis.OS_ARCH_X86_32
  535. case elf.EM_AARCH64:
  536. return apis.OS_ARCH_AARCH64
  537. case elf.EM_ARM:
  538. return apis.OS_ARCH_AARCH32
  539. case elf.EM_RISCV:
  540. if elfHeader.Class == elf.ELFCLASS32 {
  541. return apis.OS_ARCH_RISCV32
  542. }
  543. return apis.OS_ARCH_RISCV64
  544. }
  545. }
  546. }
  547. }
  548. return apis.OS_ARCH_X86_64
  549. }
  550. func (l *sLinuxRootFs) PrepareFsForTemplate(rootFs IDiskPartition) error {
  551. // clean /etc/fstab
  552. if rootFs.Exists("/etc/fstab", false) {
  553. fstabcont, _ := rootFs.FileGetContents("/etc/fstab", false)
  554. fstab := fstabutils.FSTabFile(string(fstabcont))
  555. var cf string
  556. if fstab != nil {
  557. fstab = fstab.RemoveDevices(1)
  558. cf = fstab.ToConf()
  559. }
  560. if err := rootFs.FilePutContents("/etc/fstab", cf, false, false); err != nil {
  561. return err
  562. }
  563. }
  564. // rm /etc/ssh/*_key.*
  565. if rootFs.Exists("/etc/ssh", false) {
  566. for _, f := range l.rootFs.ListDir("/etc/ssh", false) {
  567. if strings.HasSuffix(f, "_key") || strings.HasSuffix(f, "_key.pub") {
  568. rootFs.Remove("/etc/ssh/"+f, false)
  569. }
  570. }
  571. }
  572. // clean cloud-init
  573. if rootFs.Exists("/var/lib/cloud", false) {
  574. if err := rootFs.Cleandir("/var/lib/cloud", false, false); err != nil {
  575. return err
  576. }
  577. }
  578. cloudDisableFile := "/etc/cloud/cloud-init.disabled"
  579. if rootFs.Exists(cloudDisableFile, false) {
  580. rootFs.Remove(cloudDisableFile, false)
  581. }
  582. // clean /tmp /var/log /var/cache /var/spool /var/run
  583. for _, dir := range []string{"/tmp", "/var/tmp"} {
  584. if rootFs.Exists(dir, false) {
  585. if err := rootFs.Cleandir(dir, false, false); err != nil {
  586. return err
  587. }
  588. }
  589. }
  590. for _, dir := range []string{
  591. "/var/log",
  592. "/var/cache",
  593. "/usr/local/var/log",
  594. "/usr/local/var/cache",
  595. } {
  596. if rootFs.Exists(dir, false) {
  597. if err := l.rootFs.Zerofiles(dir, false); err != nil {
  598. return err
  599. }
  600. }
  601. }
  602. for _, dir := range []string{
  603. // "/var/spool",
  604. "/var/run",
  605. "/run",
  606. // "/usr/local/var/spool",
  607. "/usr/local/var/run",
  608. "/etc/openvswitch",
  609. } {
  610. if rootFs.Exists(dir, false) {
  611. if err := rootFs.Cleandir(dir, true, true); err != nil {
  612. return err
  613. }
  614. }
  615. }
  616. return nil
  617. }
  618. func (l *sLinuxRootFs) getSerialPorts(rootFs IDiskPartition) []string {
  619. if !rootFs.SupportSerialPorts() {
  620. return nil
  621. }
  622. // XXX HACK, only sshpart.SSHPartition support this
  623. var confpath = "/proc/tty/driver/serial"
  624. content, err := rootFs.FileGetContentsByPath(confpath)
  625. if err != nil {
  626. log.Errorf("Get %s error: %v", confpath, err)
  627. return nil
  628. }
  629. ttys := sysutils.GetSerialPorts(strings.Split(string(content), "\n"))
  630. log.Infof("Get serial ports content:\n%s, find serial ttys: %#v", string(content), ttys)
  631. return ttys
  632. }
  633. func (l *sLinuxRootFs) enableSerialConsoleInitCentos(rootFs IDiskPartition) error {
  634. // http://www.jonno.org/drupal/node/10
  635. var err error
  636. for _, tty := range l.getSerialPorts(rootFs) {
  637. content := fmt.Sprintf(
  638. `stop on runlevel [016]
  639. start on runlevel [345]
  640. instance %s
  641. respawn
  642. pre-start exec /sbin/securetty %s
  643. exec /sbin/agetty /dev/%s 115200 vt100`, tty, tty, tty)
  644. err = rootFs.FilePutContents(fmt.Sprintf("/etc/init/%s.conf", tty), content, false, false)
  645. }
  646. return err
  647. }
  648. func (l *sLinuxRootFs) enableSerialConsoleRootLogin(rootFs IDiskPartition, tty string) error {
  649. secureTTYFile := "/etc/securetty"
  650. content, err := rootFs.FileGetContents(secureTTYFile, false)
  651. if err != nil {
  652. return errors.Wrapf(err, "get contents of %s", secureTTYFile)
  653. }
  654. secureTTYs := sysutils.GetSecureTTYs(strings.Split(string(content), "\n"))
  655. if utils.IsInStringArray(tty, secureTTYs) {
  656. return nil
  657. }
  658. return rootFs.FilePutContents(secureTTYFile, fmt.Sprintf("\n%s", tty), true, false)
  659. }
  660. func (l *sLinuxRootFs) enableSerialConsoleInit(rootFs IDiskPartition) error {
  661. // https://help.ubuntu.com/community/SerialConsoleHowto
  662. var err error
  663. for _, tty := range l.getSerialPorts(rootFs) {
  664. if err := l.enableSerialConsoleRootLogin(rootFs, tty); err != nil {
  665. log.Errorf("Enable %s root login: %v", tty, err)
  666. }
  667. content := fmt.Sprintf(
  668. `start on stopped rc or RUNLEVEL=[12345]
  669. stop on runlevel [!12345]
  670. respawn
  671. exec /sbin/getty -L 115200 %s vt102`, tty)
  672. err = rootFs.FilePutContents(fmt.Sprintf("/etc/init/%s.conf", tty), content, false, false)
  673. }
  674. return err
  675. }
  676. func (l *sLinuxRootFs) disableSerialConsoleInit(rootFs IDiskPartition) {
  677. for _, tty := range l.getSerialPorts(rootFs) {
  678. path := fmt.Sprintf("/etc/init/%s.conf", tty)
  679. if rootFs.Exists(path, false) {
  680. rootFs.Remove(path, false)
  681. }
  682. }
  683. }
  684. func (l *sLinuxRootFs) enableSerialConsoleSystemd(rootFs IDiskPartition) error {
  685. for _, tty := range l.getSerialPorts(rootFs) {
  686. if err := l.enableSerialConsoleRootLogin(rootFs, tty); err != nil {
  687. log.Errorf("Enable %s root login: %v", tty, err)
  688. }
  689. sPath := fmt.Sprintf("/etc/systemd/system/getty.target.wants/getty@%s.service", tty)
  690. if err := rootFs.Symlink("/usr/lib/systemd/system/getty@.service", sPath, false); err != nil {
  691. return errors.Wrapf(err, "Symbol link tty %s", tty)
  692. }
  693. }
  694. return nil
  695. }
  696. func (l *sLinuxRootFs) disableSerialConsoleSystemd(rootFs IDiskPartition) {
  697. for _, tty := range l.getSerialPorts(rootFs) {
  698. sPath := fmt.Sprintf("/etc/systemd/system/getty.target.wants/getty@%s.service", tty)
  699. if rootFs.Exists(sPath, false) {
  700. rootFs.Remove(sPath, false)
  701. }
  702. }
  703. }
  704. func (l *sLinuxRootFs) dirWalk(part IDiskPartition, sPath string, wF func(path string, isDir bool) bool) bool {
  705. stat := part.Stat(sPath, false)
  706. if !stat.IsDir() {
  707. if wF(sPath, false) {
  708. return true
  709. }
  710. return false
  711. }
  712. if wF(sPath, true) {
  713. return true
  714. }
  715. for _, subPath := range part.ListDir(sPath, false) {
  716. if l.dirWalk(part, path.Join(sPath, subPath), wF) {
  717. return true
  718. }
  719. }
  720. return false
  721. }
  722. func (l *sLinuxRootFs) DetectIsUEFISupport(part IDiskPartition) bool {
  723. // ref: https://wiki.archlinux.org/title/EFI_system_partition#Check_for_an_existing_partition
  724. // To confirm this is the ESP, mount it and check whether it contains a directory named EFI,
  725. // if it does this is definitely the ESP.
  726. hasEFIFirmware := false
  727. for _, efiDir := range []string{"/EFI", "/efi"} {
  728. if !part.Exists(efiDir, false) {
  729. continue
  730. }
  731. l.dirWalk(part, efiDir, func(path string, isDir bool) bool {
  732. if isDir {
  733. return false
  734. }
  735. // check file is UEFI firmware
  736. if strings.HasSuffix(path, ".efi") {
  737. log.Infof("EFI firmware %s found", path)
  738. hasEFIFirmware = true
  739. return true
  740. }
  741. // continue walk
  742. return false
  743. })
  744. }
  745. return hasEFIFirmware
  746. }
  747. func (l *sLinuxRootFs) IsCloudinitInstall() bool {
  748. return l.GetPartition().Exists("/usr/bin/cloud-init", false)
  749. }
  750. func (d *sLinuxRootFs) DeployTelegraf(config string) (bool, error) {
  751. var (
  752. part = d.GetPartition()
  753. modeRwxOwner = syscall.S_IRUSR | syscall.S_IWUSR | syscall.S_IXUSR
  754. cloudMonitorPath = "/opt/.cloud-monitor"
  755. telegrafPath = path.Join(cloudMonitorPath, "run")
  756. )
  757. err := part.Mkdir(cloudMonitorPath, modeRwxOwner, false)
  758. if err != nil {
  759. return false, errors.Wrap(err, "mkdir cloud-monitor")
  760. }
  761. err = part.Mkdir(telegrafPath, modeRwxOwner, false)
  762. if err != nil {
  763. return false, errors.Wrap(err, "mkdir telegraf")
  764. }
  765. // telegraf files
  766. err = part.FilePutContents(path.Join(cloudMonitorPath, "telegraf.conf"), config, false, false)
  767. if err != nil {
  768. return false, errors.Wrap(err, "write telegraf config")
  769. }
  770. output, err := procutils.NewCommand("cp", "-f", TELEGRAF_BINARY_PATH, path.Join(part.GetMountPath(), cloudMonitorPath)).Output()
  771. if err != nil {
  772. return false, errors.Wrapf(err, "cp telegraf failed %s", output)
  773. }
  774. // supervise
  775. output, err = procutils.NewCommand("cp", "-f", SUPERVISE_BINARY_PATH, path.Join(part.GetMountPath(), cloudMonitorPath)).Output()
  776. if err != nil {
  777. return false, errors.Wrapf(err, "cp supervise failed %s", output)
  778. }
  779. err = part.FilePutContents(
  780. path.Join(telegrafPath, "run"),
  781. fmt.Sprintf("#!/bin/sh\n%s/telegraf -config %s/telegraf.conf", cloudMonitorPath, cloudMonitorPath),
  782. false, false,
  783. )
  784. if err != nil {
  785. return false, errors.Wrap(err, "write supervise run script")
  786. }
  787. err = part.Chmod(path.Join(telegrafPath, "run"), 0755, false)
  788. if err != nil {
  789. return false, errors.Wrap(err, "chmod supervise run script")
  790. }
  791. initCmd := fmt.Sprintf("%s/supervise %s", cloudMonitorPath, telegrafPath)
  792. if d.isSupportSystemd() {
  793. initCmd = path.Join(telegrafPath, "run")
  794. }
  795. err = d.installInitScript("telegraf", initCmd, false)
  796. if err != nil {
  797. return false, errors.Wrap(err, "installInitScript")
  798. }
  799. /* // add crontab: start telegraf on guest boot
  800. cronJob := fmt.Sprintf("@reboot %s/supervise %s", cloudMonitorPath, telegrafPath)
  801. if procutils.NewCommand("chroot", part.GetMountPath(), "crontab", "-l", "|", "grep", cronJob).Run() == nil {
  802. // if cronjob exist, return success
  803. return true, nil
  804. }
  805. output, err = procutils.NewCommand("chroot", part.GetMountPath(), "sh", "-c",
  806. fmt.Sprintf("(crontab -l 2>/dev/null; echo '%s') |crontab -", cronJob),
  807. ).Output()
  808. if err != nil {
  809. return false, errors.Wrapf(err, "add crontab %s", output)
  810. }*/
  811. return true, nil
  812. }
  813. func (d *sLinuxRootFs) ConfigSshd(loginAccount, loginPassword string, sshPort int) error {
  814. if d.rootFs.Exists("/etc/ssh/sshd_config.d", false) {
  815. content := "### sshd config for cloud config\n"
  816. if loginAccount == "root" {
  817. content += "PermitRootLogin yes\n"
  818. }
  819. if len(loginPassword) > 0 {
  820. content += "PasswordAuthentication yes\n"
  821. }
  822. if sshPort > 0 && sshPort != 22 {
  823. content += fmt.Sprintf("Port %d\n", sshPort)
  824. }
  825. return d.rootFs.FilePutContents("/etc/ssh/sshd_config.d/00-cloud-config.conf", content, false, false)
  826. } else {
  827. content, err := d.rootFs.FileGetContents("/etc/ssh/sshd_config", false)
  828. if err != nil {
  829. return errors.Wrap(err, "read sshd config")
  830. }
  831. lines := genSshdConfig(strings.Split(string(content), "\n"), loginAccount, loginPassword, sshPort)
  832. return d.rootFs.FilePutContents("/etc/ssh/sshd_config", strings.Join(lines, "\n"), false, false)
  833. }
  834. }
  835. type sDebianLikeRootFs struct {
  836. *sLinuxRootFs
  837. }
  838. func newDebianLikeRootFs(part IDiskPartition) *sDebianLikeRootFs {
  839. return &sDebianLikeRootFs{
  840. sLinuxRootFs: newLinuxRootFs(part),
  841. }
  842. }
  843. func (d *sDebianLikeRootFs) PrepareFsForTemplate(rootFs IDiskPartition) error {
  844. if err := d.sLinuxRootFs.PrepareFsForTemplate(rootFs); err != nil {
  845. return err
  846. }
  847. // clean /etc/network/interface
  848. if rootFs.Exists("/etc/network/interface", false) {
  849. fn := "/etc/network/interfaces"
  850. var cmds strings.Builder
  851. cmds.WriteString("auto lo\n")
  852. cmds.WriteString("iface lo inet loopback\n\n")
  853. if err := rootFs.FilePutContents(fn, cmds.String(), false, false); err != nil {
  854. return errors.Wrap(err, "file put content /etc/network/interface")
  855. }
  856. }
  857. // clean /etc/netplan/*
  858. netplanDir := "/etc/netplan/"
  859. if rootFs.Exists(netplanDir, false) {
  860. for _, f := range rootFs.ListDir(netplanDir, false) {
  861. rootFs.Remove(filepath.Join(netplanDir, f), false)
  862. }
  863. }
  864. return nil
  865. }
  866. func (d *sDebianLikeRootFs) GetReleaseInfo(rootFs IDiskPartition, driver IDebianRootFsDriver) *deployapi.ReleaseInfo {
  867. version, err := rootFs.FileGetContents(driver.VersionFilePath(), false)
  868. if err != nil {
  869. log.Errorf("Get %s error: %v", driver.VersionFilePath(), err)
  870. return nil
  871. }
  872. versionStr := strings.TrimSpace(string(version))
  873. return &deployapi.ReleaseInfo{
  874. Distro: driver.DistroName(),
  875. Version: versionStr,
  876. Arch: d.GetArch(rootFs),
  877. }
  878. }
  879. func (d *sDebianLikeRootFs) RootSignatures() []string {
  880. sig := d.sLinuxRootFs.RootSignatures()
  881. return append([]string{"/etc/issue"}, sig...)
  882. }
  883. func (d *sDebianLikeRootFs) DeployHostname(rootFs IDiskPartition, hn, domain string) error {
  884. return rootFs.FilePutContents("/etc/hostname", hn, false, false)
  885. }
  886. func getNicTeamingConfigCmds(slaves []*types.SServerNic) string {
  887. var cmds strings.Builder
  888. cmds.WriteString(" bond-mode 4\n")
  889. cmds.WriteString(" bond-miimon 100\n")
  890. cmds.WriteString(" bond-lacp-rate 1\n")
  891. cmds.WriteString(" bond-xmit_hash_policy 1\n")
  892. cmds.WriteString(" bond-slaves")
  893. for i := range slaves {
  894. cmds.WriteString(" ")
  895. cmds.WriteString(slaves[i].Name)
  896. }
  897. cmds.WriteString("\n")
  898. return cmds.String()
  899. }
  900. func (d *sDebianLikeRootFs) DeployNetworkingScripts(rootFs IDiskPartition, nics []*types.SServerNic) error {
  901. if err := d.sLinuxRootFs.DeployNetworkingScripts(rootFs, nics); err != nil {
  902. return err
  903. }
  904. if !rootFs.Exists("/etc/network", false) {
  905. if err := rootFs.Mkdir("/etc/network",
  906. syscall.S_IRUSR|syscall.S_IWUSR|syscall.S_IXUSR, false); err != nil {
  907. return errors.Wrap(err, "mkdir /etc/network")
  908. }
  909. }
  910. fn := "/etc/network/interfaces"
  911. var cmds strings.Builder
  912. cmds.WriteString("auto lo\n")
  913. cmds.WriteString("iface lo inet loopback\n\n")
  914. // ToServerNics(nics)
  915. allNics, bondNics := convertNicConfigs(nics)
  916. nicCnt := len(allNics) - len(bondNics)
  917. mainNic := getMainNic(allNics)
  918. var mainIp string
  919. if mainNic != nil {
  920. mainIp = mainNic.Ip
  921. }
  922. mainNic6 := getMainNic6(allNics)
  923. var mainIp6 string
  924. if mainNic6 != nil {
  925. mainIp6 = mainNic6.Ip6
  926. }
  927. netplanDir := "/etc/netplan"
  928. if rootFs.Exists(netplanDir, false) {
  929. for _, f := range rootFs.ListDir(netplanDir, false) {
  930. rootFs.Remove(filepath.Join(netplanDir, f), false)
  931. }
  932. netplanConfig := NewNetplanConfig(allNics, bondNics, mainIp, mainIp6)
  933. log.Debugf("netplanConfig:\n %s", netplanConfig.YAMLString())
  934. if err := rootFs.FilePutContents(path.Join(netplanDir, "config.yaml"), netplanConfig.YAMLString(), false, false); err != nil {
  935. return errors.Wrap(err, "Put netplan config")
  936. }
  937. }
  938. var systemdResolveConfig strings.Builder
  939. dnss := []string{}
  940. domains := []string{}
  941. for i := range allNics {
  942. nicDesc := allNics[i]
  943. cmds.WriteString(fmt.Sprintf("auto %s\n", nicDesc.Name))
  944. if nicDesc.TeamingMaster != nil {
  945. cmds.WriteString(fmt.Sprintf("iface %s inet manual\n", nicDesc.Name))
  946. cmds.WriteString(fmt.Sprintf(" bond-master %s\n", nicDesc.TeamingMaster.Name))
  947. cmds.WriteString("\n")
  948. } else if nicDesc.Virtual {
  949. cmds.WriteString(fmt.Sprintf("iface %s inet static\n", nicDesc.Name))
  950. cmds.WriteString(fmt.Sprintf(" address %s\n", netutils2.PSEUDO_VIP))
  951. cmds.WriteString(" netmask 255.255.255.255\n")
  952. cmds.WriteString("\n")
  953. } else if nicDesc.Manual {
  954. ifname := nicDesc.Name
  955. if len(nicDesc.Ip) > 0 {
  956. cmds.WriteString(fmt.Sprintf("iface %s inet static\n", nicDesc.Name))
  957. if nicDesc.VlanInterface {
  958. cmds.WriteString("\n")
  959. ifname = fmt.Sprintf("%s.%d", nicDesc.Name, nicDesc.Vlan)
  960. cmds.WriteString(fmt.Sprintf("auto %s\n", ifname))
  961. cmds.WriteString(fmt.Sprintf("iface %s inet static\n", ifname))
  962. }
  963. netmask := netutils2.Netlen2Mask(int(nicDesc.Masklen))
  964. cmds.WriteString(fmt.Sprintf(" address %s\n", nicDesc.Ip))
  965. cmds.WriteString(fmt.Sprintf(" netmask %s\n", netmask))
  966. cmds.WriteString(fmt.Sprintf(" hwaddress ether %s\n", nicDesc.Mac))
  967. if len(nicDesc.Gateway) > 0 && nicDesc.Ip == mainIp {
  968. cmds.WriteString(fmt.Sprintf(" gateway %s\n", nicDesc.Gateway))
  969. }
  970. if nicDesc.Mtu > 0 {
  971. cmds.WriteString(fmt.Sprintf(" mtu %d\n", nicDesc.Mtu))
  972. }
  973. }
  974. routes4 := make([]netutils2.SRouteInfo, 0)
  975. routes6 := make([]netutils2.SRouteInfo, 0)
  976. routes4, routes6 = netutils2.AddNicRoutes(routes4, routes6, nicDesc, mainIp, mainIp6, nicCnt)
  977. for _, r := range routes4 {
  978. cmds.WriteString(fmt.Sprintf(" up ip route add %s/%d via %s || true\n", r.Prefix, r.PrefixLen, r.Gateway))
  979. cmds.WriteString(fmt.Sprintf(" down ip route del %s/%d via %s || true\n", r.Prefix, r.PrefixLen, r.Gateway))
  980. }
  981. for _, r := range routes6 {
  982. cmds.WriteString(fmt.Sprintf(" up ip -6 route add %s/%d via %s || true\n", r.Prefix, r.PrefixLen, r.Gateway))
  983. cmds.WriteString(fmt.Sprintf(" down ip -6 route del %s/%d via %s || true\n", r.Prefix, r.PrefixLen, r.Gateway))
  984. }
  985. dnslist, _ := netutils2.GetNicDns(nicDesc)
  986. if len(dnslist) > 0 {
  987. cmds.WriteString(fmt.Sprintf(" dns-nameservers %s\n", strings.Join(dnslist, " ")))
  988. dnss = append(dnss, dnslist...)
  989. if len(nicDesc.Domain) > 0 {
  990. cmds.WriteString(fmt.Sprintf(" dns-search %s\n", nicDesc.Domain))
  991. domains = append(domains, nicDesc.Domain)
  992. }
  993. if nicDesc.Mtu > 0 {
  994. cmds.WriteString(fmt.Sprintf(" mtu %d\n", nicDesc.Mtu))
  995. }
  996. if len(nicDesc.TeamingSlaves) > 0 {
  997. cmds.WriteString(getNicTeamingConfigCmds(nicDesc.TeamingSlaves))
  998. }
  999. cmds.WriteString("\n")
  1000. }
  1001. if len(nicDesc.Ip6) > 0 {
  1002. cmds.WriteString(fmt.Sprintf("iface %s inet6 static\n", ifname))
  1003. cmds.WriteString(fmt.Sprintf(" address %s\n", nicDesc.Ip6))
  1004. cmds.WriteString(fmt.Sprintf(" netmask %d\n", nicDesc.Masklen6))
  1005. if len(nicDesc.Gateway6) > 0 && nicDesc.Ip == mainIp {
  1006. cmds.WriteString(fmt.Sprintf(" gateway %s\n", nicDesc.Gateway6))
  1007. }
  1008. _, dnslist := netutils2.GetNicDns(nicDesc)
  1009. if len(dnslist) > 0 {
  1010. cmds.WriteString(fmt.Sprintf(" dns-nameservers %s\n", strings.Join(dnslist, " ")))
  1011. dnss = append(dnss, dnslist...)
  1012. if len(nicDesc.Domain) > 0 {
  1013. cmds.WriteString(fmt.Sprintf(" dns-search %s\n", nicDesc.Domain))
  1014. domains = append(domains, nicDesc.Domain)
  1015. }
  1016. }
  1017. cmds.WriteString("\n")
  1018. }
  1019. } else {
  1020. if len(nicDesc.Ip) > 0 {
  1021. cmds.WriteString(fmt.Sprintf("iface %s inet dhcp\n", nicDesc.Name))
  1022. }
  1023. if len(nicDesc.Ip6) > 0 {
  1024. cmds.WriteString(fmt.Sprintf("iface %s inet6 dhcp\n", nicDesc.Name))
  1025. }
  1026. if len(nicDesc.Ip) > 0 || len(nicDesc.Ip6) > 0 {
  1027. if len(nicDesc.TeamingSlaves) > 0 {
  1028. cmds.WriteString(getNicTeamingConfigCmds(nicDesc.TeamingSlaves))
  1029. }
  1030. cmds.WriteString("\n")
  1031. }
  1032. }
  1033. }
  1034. if len(dnss) != 0 {
  1035. systemdResolveConfig.WriteString("[Resolve]\n")
  1036. systemdResolveConfig.WriteString(fmt.Sprintf("DNS=%s\n", strings.Join(dnss, " ")))
  1037. if len(domains) != 0 {
  1038. systemdResolveConfig.WriteString(fmt.Sprintf("Domains=%s\n", strings.Join(domains, " ")))
  1039. }
  1040. systemdResolveFn := "/etc/systemd/resolved.conf"
  1041. content := systemdResolveConfig.String()
  1042. if err := rootFs.FilePutContents(systemdResolveFn, content, false, false); err != nil {
  1043. log.Warningf("Put %s to %s error: %v", content, systemdResolveFn, err)
  1044. }
  1045. }
  1046. log.Debugf("%s", cmds.String())
  1047. return rootFs.FilePutContents(fn, cmds.String(), false, false)
  1048. }
  1049. func (r *sDebianLikeRootFs) ChangeUserPasswd(rootFs IDiskPartition, account, gid, publicKey, password string, isRandomPassword bool) (string, error) {
  1050. if isRandomPassword {
  1051. var pwqualityConf *pwquality.Config
  1052. if rootFs.Exists("/etc/security/pwquality.conf", false) {
  1053. pwConfig, err := rootFs.FileGetContents("/etc/security/pwquality.conf", false)
  1054. if err == nil {
  1055. pwqualityConf = pwquality.ParseConfig(pwConfig)
  1056. }
  1057. }
  1058. if rootFs.Exists("/etc/pam.d/common-password", false) {
  1059. pamConfig, err := rootFs.FileGetContents("/etc/pam.d/common-password", false)
  1060. if err == nil {
  1061. pwqualityConf = pwquality.ParsePAMConfig(pamConfig, pwqualityConf)
  1062. }
  1063. }
  1064. password = r.checkInputPasswd(rootFs, pwqualityConf, account, gid, publicKey, password)
  1065. }
  1066. return r.sLinuxRootFs.ChangeUserPasswd(rootFs, account, gid, publicKey, password, isRandomPassword)
  1067. }
  1068. type SDebianRootFs struct {
  1069. *sDebianLikeRootFs
  1070. }
  1071. func NewDebianRootFs(part IDiskPartition) IRootFsDriver {
  1072. driver := new(SDebianRootFs)
  1073. driver.sDebianLikeRootFs = newDebianLikeRootFs(part)
  1074. return driver
  1075. }
  1076. func (d *SDebianRootFs) String() string {
  1077. return "DebianRootFs"
  1078. }
  1079. func (d *SDebianRootFs) GetName() string {
  1080. return "Debian"
  1081. }
  1082. func (d *SDebianRootFs) DistroName() string {
  1083. return d.GetName()
  1084. }
  1085. func (d *SDebianRootFs) VersionFilePath() string {
  1086. return "/etc/debian_version"
  1087. }
  1088. func (d *SDebianRootFs) rootSignatures(driver IDebianRootFsDriver) []string {
  1089. sig := d.sDebianLikeRootFs.RootSignatures()
  1090. return append([]string{driver.VersionFilePath()}, sig...)
  1091. }
  1092. func (d *SDebianRootFs) RootSignatures() []string {
  1093. return d.rootSignatures(d)
  1094. }
  1095. func (d *SDebianRootFs) RootExcludeSignatures() []string {
  1096. return []string{"/etc/lsb-release"}
  1097. }
  1098. func (d *SDebianRootFs) GetReleaseInfo(rootFs IDiskPartition) *deployapi.ReleaseInfo {
  1099. return d.sDebianLikeRootFs.GetReleaseInfo(rootFs, d)
  1100. }
  1101. type SCirrosRootFs struct {
  1102. *SDebianRootFs
  1103. }
  1104. func NewCirrosRootFs(part IDiskPartition) IRootFsDriver {
  1105. driver := new(SCirrosRootFs)
  1106. driver.SDebianRootFs = NewDebianRootFs(part).(*SDebianRootFs)
  1107. return driver
  1108. }
  1109. func (d *SCirrosRootFs) GetName() string {
  1110. return "Cirros"
  1111. }
  1112. func (d *SCirrosRootFs) String() string {
  1113. return "CirrosRootFs"
  1114. }
  1115. func (d *SCirrosRootFs) DistroName() string {
  1116. return d.GetName()
  1117. }
  1118. func (d *SCirrosRootFs) VersionFilePath() string {
  1119. return "/etc/br-version"
  1120. }
  1121. func (d *SCirrosRootFs) GetReleaseInfo(rootFs IDiskPartition) *deployapi.ReleaseInfo {
  1122. return d.SDebianRootFs.sDebianLikeRootFs.GetReleaseInfo(rootFs, d)
  1123. }
  1124. func (d *SCirrosRootFs) RootSignatures() []string {
  1125. return d.rootSignatures(d)
  1126. }
  1127. type SCirrosNewRootFs struct {
  1128. *SDebianRootFs
  1129. }
  1130. func NewCirrosNewRootFs(part IDiskPartition) IRootFsDriver {
  1131. driver := new(SCirrosNewRootFs)
  1132. driver.SDebianRootFs = NewDebianRootFs(part).(*SDebianRootFs)
  1133. return driver
  1134. }
  1135. func (d *SCirrosNewRootFs) GetName() string {
  1136. return "Cirros"
  1137. }
  1138. func (d *SCirrosNewRootFs) String() string {
  1139. return "CirrosNewRootFs"
  1140. }
  1141. func (d *SCirrosNewRootFs) DistroName() string {
  1142. return d.GetName()
  1143. }
  1144. func (d *SCirrosNewRootFs) VersionFilePath() string {
  1145. return "/etc/cirros/version"
  1146. }
  1147. func (d *SCirrosNewRootFs) RootSignatures() []string {
  1148. return d.rootSignatures(d)
  1149. }
  1150. func (d *SCirrosNewRootFs) GetReleaseInfo(rootFs IDiskPartition) *deployapi.ReleaseInfo {
  1151. return d.SDebianRootFs.sDebianLikeRootFs.GetReleaseInfo(rootFs, d)
  1152. }
  1153. type SUbuntuRootFs struct {
  1154. *sDebianLikeRootFs
  1155. }
  1156. func NewUbuntuRootFs(part IDiskPartition) IRootFsDriver {
  1157. driver := new(SUbuntuRootFs)
  1158. driver.sDebianLikeRootFs = newDebianLikeRootFs(part)
  1159. return driver
  1160. }
  1161. func (d *SUbuntuRootFs) RootSignatures() []string {
  1162. sig := d.sDebianLikeRootFs.RootSignatures()
  1163. return append([]string{"/etc/lsb-release"}, sig...)
  1164. }
  1165. func (d *SUbuntuRootFs) GetName() string {
  1166. return "Ubuntu"
  1167. }
  1168. func (d *SUbuntuRootFs) String() string {
  1169. return "UbuntuRootFs"
  1170. }
  1171. func (d *SUbuntuRootFs) GetReleaseInfo(rootFs IDiskPartition) *deployapi.ReleaseInfo {
  1172. distroKey := "DISTRIB_RELEASE="
  1173. distroId := "DISTRIB_ID="
  1174. rel, err := rootFs.FileGetContents("/etc/lsb-release", false)
  1175. if err != nil {
  1176. log.Errorf("Get ubuntu release info error: %v", err)
  1177. return nil
  1178. }
  1179. var version, distro string
  1180. lines := strings.Split(string(rel), "\n")
  1181. for _, l := range lines {
  1182. if strings.HasPrefix(l, distroKey) {
  1183. version = strings.TrimSpace(l[len(distroKey):])
  1184. } else if strings.HasPrefix(l, distroId) {
  1185. distro = strings.TrimSpace(l[len(distroId):])
  1186. }
  1187. }
  1188. if distro == "" {
  1189. distro = d.GetName()
  1190. }
  1191. return deployapi.NewReleaseInfo(distro, version, d.GetArch(rootFs))
  1192. }
  1193. func (d *SUbuntuRootFs) EnableSerialConsole(rootFs IDiskPartition, sysInfo *jsonutils.JSONDict) error {
  1194. relInfo := d.GetReleaseInfo(rootFs)
  1195. ver := strings.Split(relInfo.Version, ".")
  1196. verInt, _ := strconv.Atoi(ver[0])
  1197. if verInt < 16 {
  1198. return d.enableSerialConsoleInit(rootFs)
  1199. }
  1200. return d.enableSerialConsoleSystemd(rootFs)
  1201. }
  1202. func (d *SUbuntuRootFs) DisableSerialConcole(rootFs IDiskPartition) error {
  1203. relInfo := d.GetReleaseInfo(rootFs)
  1204. ver := strings.Split(relInfo.Version, ".")
  1205. verInt, _ := strconv.Atoi(ver[0])
  1206. if verInt < 16 {
  1207. d.disableSerialConsoleInit(rootFs)
  1208. return nil
  1209. }
  1210. d.disableSerialConsoleSystemd(rootFs)
  1211. return nil
  1212. }
  1213. type SUKylinRootfs struct {
  1214. *SUbuntuRootFs
  1215. }
  1216. func NewUKylinRootfs(part IDiskPartition) IRootFsDriver {
  1217. return &SUKylinRootfs{SUbuntuRootFs: NewUbuntuRootFs(part).(*SUbuntuRootFs)}
  1218. }
  1219. func (d *SUKylinRootfs) GetName() string {
  1220. return "UbuntuKylin"
  1221. }
  1222. func (d *SUKylinRootfs) String() string {
  1223. return "UKylinuRootFs"
  1224. }
  1225. func (d *SUKylinRootfs) RootSignatures() []string {
  1226. sig := d.sDebianLikeRootFs.RootSignatures()
  1227. return append([]string{"/etc/lsb-release", "/etc/kylin-build"}, sig...)
  1228. }
  1229. func (d *SUKylinRootfs) GetReleaseInfo(rootFs IDiskPartition) *deployapi.ReleaseInfo {
  1230. info := d.SUbuntuRootFs.GetReleaseInfo(rootFs)
  1231. info.Distro = d.GetName()
  1232. return info
  1233. }
  1234. func (d *SUKylinRootfs) AllowAdminLogin() bool {
  1235. return false
  1236. }
  1237. type sRedhatLikeRootFs struct {
  1238. *sLinuxRootFs
  1239. }
  1240. func newRedhatLikeRootFs(part IDiskPartition) *sRedhatLikeRootFs {
  1241. return &sRedhatLikeRootFs{
  1242. sLinuxRootFs: newLinuxRootFs(part),
  1243. }
  1244. }
  1245. func (r *sRedhatLikeRootFs) PrepareFsForTemplate(rootFs IDiskPartition) error {
  1246. if err := r.sLinuxRootFs.PrepareFsForTemplate(rootFs); err != nil {
  1247. return err
  1248. }
  1249. return r.CleanNetworkScripts(rootFs)
  1250. }
  1251. func (r *sRedhatLikeRootFs) cleanNetworkManagerConfigurations(rootFs IDiskPartition) error {
  1252. networkPath := "/etc/NetworkManager/system-connections"
  1253. if !rootFs.Exists(networkPath, false) {
  1254. return nil
  1255. }
  1256. files := rootFs.ListDir(networkPath, false)
  1257. for _, f := range files {
  1258. rootFs.Remove(filepath.Join(networkPath, f), false)
  1259. }
  1260. return nil
  1261. }
  1262. func (r *sRedhatLikeRootFs) CleanNetworkScripts(rootFs IDiskPartition) error {
  1263. networkPath := "/etc/sysconfig/network-scripts"
  1264. if !rootFs.Exists(networkPath, false) {
  1265. return r.cleanNetworkManagerConfigurations(rootFs)
  1266. }
  1267. files := rootFs.ListDir(networkPath, false)
  1268. for i := 0; i < len(files); i++ {
  1269. if strings.HasPrefix(files[i], "ifcfg-") && files[i] != "ifcfg-lo" {
  1270. rootFs.Remove(path.Join(networkPath, files[i]), false)
  1271. continue
  1272. }
  1273. if strings.HasPrefix(files[i], "route-") {
  1274. rootFs.Remove(path.Join(networkPath, files[i]), false)
  1275. }
  1276. }
  1277. return nil
  1278. }
  1279. func (r *sRedhatLikeRootFs) RootSignatures() []string {
  1280. sig := r.sLinuxRootFs.RootSignatures()
  1281. return append([]string{"/etc/redhat-release"}, sig...)
  1282. }
  1283. func (r *sRedhatLikeRootFs) DeployHostname(rootFs IDiskPartition, hn, domain string) error {
  1284. var sPath = "/etc/sysconfig/network"
  1285. if r.rootFs.Exists(sPath, false) {
  1286. centosHn := ""
  1287. centosHn += "NETWORKING=yes\n"
  1288. centosHn += fmt.Sprintf("HOSTNAME=%s\n", getHostname(hn, domain))
  1289. if err := rootFs.FilePutContents(sPath, centosHn, false, false); err != nil {
  1290. return errors.Wrapf(err, "DeployHostname %s", sPath)
  1291. }
  1292. }
  1293. if err := rootFs.FilePutContents("/etc/hostname", hn, false, false); err != nil {
  1294. return errors.Wrapf(err, "DeployHostname %s", "/etc/hostname")
  1295. }
  1296. return nil
  1297. }
  1298. func (r *sRedhatLikeRootFs) Centos5DeployNetworkingScripts(rootFs IDiskPartition, nics []*types.SServerNic) error {
  1299. var netDevPrefix = GetNetDevPrefix(nics)
  1300. var udevPath = "/etc/udev/rules.d/"
  1301. if rootFs.Exists(udevPath, false) {
  1302. var nicRules = ""
  1303. for _, nic := range nics {
  1304. nicRules += `KERNEL=="*", `
  1305. nicRules += fmt.Sprintf(`SYSFS{address}=="%s", `, strings.ToLower(nic.Mac))
  1306. nicRules += fmt.Sprintf("NAME=\"%s%d\"\n", netDevPrefix, nic.Index)
  1307. }
  1308. return rootFs.FilePutContents(path.Join(udevPath, "60-net.rules"),
  1309. nicRules, false, false)
  1310. }
  1311. return nil
  1312. }
  1313. func (r *sRedhatLikeRootFs) ChangeUserPasswd(rootFs IDiskPartition, account, gid, publicKey, password string, isRandomPassword bool) (string, error) {
  1314. if isRandomPassword {
  1315. var pwqualityConf *pwquality.Config
  1316. if rootFs.Exists("/etc/security/pwquality.conf", false) {
  1317. pwConfig, err := rootFs.FileGetContents("/etc/security/pwquality.conf", false)
  1318. if err == nil {
  1319. pwqualityConf = pwquality.ParseConfig(pwConfig)
  1320. }
  1321. }
  1322. if rootFs.Exists("/etc/pam.d/system-auth", false) {
  1323. pamConfig, err := rootFs.FileGetContents("/etc/pam.d/system-auth", false)
  1324. if err == nil {
  1325. pwqualityConf = pwquality.ParsePAMConfig(pamConfig, pwqualityConf)
  1326. }
  1327. }
  1328. password = r.checkInputPasswd(rootFs, pwqualityConf, account, gid, publicKey, password)
  1329. }
  1330. return r.sLinuxRootFs.ChangeUserPasswd(rootFs, account, gid, publicKey, password, isRandomPassword)
  1331. }
  1332. func getMainNic(nics []*types.SServerNic) *types.SServerNic {
  1333. for i := range nics {
  1334. if nics[i].IsDefault {
  1335. return nics[i]
  1336. }
  1337. }
  1338. for i := range nics {
  1339. if len(nics[i].Ip) > 0 && len(nics[i].Gateway) > 0 {
  1340. return nics[i]
  1341. }
  1342. }
  1343. return nil
  1344. }
  1345. func getMainNic6(nics []*types.SServerNic) *types.SServerNic {
  1346. for i := range nics {
  1347. if nics[i].IsDefault {
  1348. return nics[i]
  1349. }
  1350. }
  1351. for i := range nics {
  1352. if len(nics[i].Ip6) > 0 && len(nics[i].Gateway6) > 0 {
  1353. return nics[i]
  1354. }
  1355. }
  1356. return nil
  1357. }
  1358. func (r *sRedhatLikeRootFs) enableBondingModule(rootFs IDiskPartition, bondNics []*types.SServerNic) error {
  1359. var content strings.Builder
  1360. for i := range bondNics {
  1361. content.WriteString("alias ")
  1362. content.WriteString(bondNics[i].Name)
  1363. content.WriteString(" bonding\n options ")
  1364. content.WriteString(bondNics[i].Name)
  1365. content.WriteString(" miimon=100 mode=4 lacp_rate=1 xmit_hash_policy=1\n")
  1366. }
  1367. return rootFs.FilePutContents("/etc/modprobe.d/bonding.conf", content.String(), false, false)
  1368. }
  1369. // check if NetworkManager is enabled
  1370. func (r *sRedhatLikeRootFs) isNetworkManagerEnabled(rootFs IDiskPartition) bool {
  1371. return rootFs.Exists("/etc/systemd/system/multi-user.target.wants/NetworkManager.service", false)
  1372. }
  1373. func (r *sRedhatLikeRootFs) deployNetworkManagerConfigurations(rootFs IDiskPartition, nics []*types.SServerNic, relInfo *deployapi.ReleaseInfo) error {
  1374. const scriptPath = "/etc/NetworkManager/system-connections"
  1375. if !rootFs.Exists(scriptPath, false) {
  1376. return errors.Wrap(errors.ErrNotSupported, "unsupported system, neither network-scripts nor NetworkManager")
  1377. }
  1378. // remove all connections profiles
  1379. files := rootFs.ListDir(scriptPath, false)
  1380. for _, f := range files {
  1381. log.Infof("remove %s in %s", f, scriptPath)
  1382. rootFs.Remove(filepath.Join(scriptPath, f), false)
  1383. }
  1384. allNics, bondNics := convertNicConfigs(nics)
  1385. if len(bondNics) > 0 {
  1386. err := r.enableBondingModule(rootFs, bondNics)
  1387. if err != nil {
  1388. return errors.Wrap(err, "enableBondingModule")
  1389. }
  1390. }
  1391. nicCnt := len(allNics) - len(bondNics)
  1392. mainNic := getMainNic(allNics)
  1393. var mainIp string
  1394. if mainNic != nil {
  1395. mainIp = mainNic.Ip
  1396. }
  1397. mainNic6 := getMainNic6(allNics)
  1398. var mainIp6 string
  1399. if mainNic6 != nil {
  1400. mainIp6 = mainNic6.Ip6
  1401. }
  1402. for i := range allNics {
  1403. nicDesc := allNics[i]
  1404. profile := nicDescToNetworkManager(nicDesc, mainIp, mainIp6, nicCnt)
  1405. var fn = fmt.Sprintf("%s/%s.nmconnection", scriptPath, nicDesc.Name)
  1406. if err := rootFs.FilePutContents(fn, profile, false, false); err != nil {
  1407. return err
  1408. }
  1409. }
  1410. return nil
  1411. }
  1412. func (r *sRedhatLikeRootFs) deployNetworkingScripts(rootFs IDiskPartition, nics []*types.SServerNic, relInfo *deployapi.ReleaseInfo) error {
  1413. ver := strings.Split(relInfo.Version, ".")
  1414. iv, err := strconv.ParseInt(ver[0], 10, 0)
  1415. if err == nil && iv < 6 {
  1416. err = r.Centos5DeployNetworkingScripts(rootFs, nics)
  1417. } else {
  1418. err = r.sLinuxRootFs.DeployNetworkingScripts(rootFs, nics)
  1419. }
  1420. if err != nil {
  1421. return errors.Wrap(err, "DeployNetworkingScripts")
  1422. }
  1423. const scriptPath = "/etc/sysconfig/network-scripts"
  1424. if !rootFs.Exists(scriptPath, false) {
  1425. // NetworkManager is enabled, but no network-scripts directory, deploy NetworkManager configurations
  1426. return r.deployNetworkManagerConfigurations(rootFs, nics, relInfo)
  1427. }
  1428. // remove all ifcfg-*
  1429. files := rootFs.ListDir(scriptPath, false)
  1430. for _, f := range files {
  1431. if strings.HasPrefix(f, "ifcfg-") && f != "ifcfg-lo" {
  1432. log.Infof("remove %s in %s", f, scriptPath)
  1433. rootFs.Remove(filepath.Join(scriptPath, f), false)
  1434. }
  1435. }
  1436. // ToServerNics(nics)
  1437. allNics, bondNics := convertNicConfigs(nics)
  1438. if len(bondNics) > 0 {
  1439. err = r.enableBondingModule(rootFs, bondNics)
  1440. if err != nil {
  1441. return errors.Wrap(err, "enableBondingModule")
  1442. }
  1443. }
  1444. nicCnt := len(allNics) - len(bondNics)
  1445. mainNic := getMainNic(allNics)
  1446. var mainIp string
  1447. if mainNic != nil {
  1448. mainIp = mainNic.Ip
  1449. }
  1450. mainNic6 := getMainNic6(allNics)
  1451. var mainIp6 string
  1452. if mainNic6 != nil {
  1453. mainIp6 = mainNic6.Ip6
  1454. }
  1455. for i := range allNics {
  1456. nicDesc := allNics[i]
  1457. var cmds strings.Builder
  1458. cmds.WriteString("DEVICE=")
  1459. cmds.WriteString(nicDesc.Name)
  1460. cmds.WriteString("\n")
  1461. cmds.WriteString("NAME=")
  1462. cmds.WriteString(nicDesc.Name)
  1463. cmds.WriteString("\n")
  1464. cmds.WriteString("ONBOOT=yes\n")
  1465. if r.isNetworkManagerEnabled(rootFs) {
  1466. cmds.WriteString("NM_CONTROLLED=yes\n")
  1467. } else {
  1468. cmds.WriteString("NM_CONTROLLED=no\n")
  1469. }
  1470. cmds.WriteString("USERCTL=no\n")
  1471. if nicDesc.Mtu > 0 {
  1472. cmds.WriteString(fmt.Sprintf("MTU=%d\n", nicDesc.Mtu))
  1473. }
  1474. if len(nicDesc.Mac) > 0 && nicDesc.NicType != api.NIC_TYPE_INFINIBAND {
  1475. if len(nicDesc.TeamingSlaves) == 0 {
  1476. // only real physical nic can set HWADDR
  1477. cmds.WriteString("HWADDR=")
  1478. cmds.WriteString(nicDesc.Mac)
  1479. cmds.WriteString("\n")
  1480. }
  1481. cmds.WriteString("MACADDR=")
  1482. cmds.WriteString(nicDesc.Mac)
  1483. cmds.WriteString("\n")
  1484. }
  1485. if len(nicDesc.TeamingSlaves) > 0 {
  1486. // bonding master
  1487. cmds.WriteString(`BONDING_OPTS="mode=4 miimon=100"`)
  1488. cmds.WriteString("\n")
  1489. }
  1490. if nicDesc.TeamingMaster != nil {
  1491. cmds.WriteString("BOOTPROTO=none\n")
  1492. cmds.WriteString("MASTER=")
  1493. cmds.WriteString(nicDesc.TeamingMaster.Name)
  1494. cmds.WriteString("\n")
  1495. cmds.WriteString("SLAVE=yes\n")
  1496. } else if nicDesc.Virtual {
  1497. cmds.WriteString("BOOTPROTO=none\n")
  1498. cmds.WriteString("NETMASK=255.255.255.255\n")
  1499. cmds.WriteString("IPADDR=")
  1500. cmds.WriteString(netutils2.PSEUDO_VIP)
  1501. cmds.WriteString("\n")
  1502. } else if nicDesc.Manual {
  1503. cmds.WriteString("BOOTPROTO=none\n")
  1504. if nicDesc.VlanInterface {
  1505. if err := r.deployVlanNetworkingScripts(rootFs, scriptPath, mainIp, mainIp6, nicCnt, nicDesc); err != nil {
  1506. return errors.Wrap(err, "deployVlanNetworkingScripts")
  1507. }
  1508. } else {
  1509. if len(nicDesc.Ip) > 0 {
  1510. netmask := netutils2.Netlen2Mask(int(nicDesc.Masklen))
  1511. cmds.WriteString("NETMASK=")
  1512. cmds.WriteString(netmask)
  1513. cmds.WriteString("\n")
  1514. cmds.WriteString("IPADDR=")
  1515. cmds.WriteString(nicDesc.Ip)
  1516. cmds.WriteString("\n")
  1517. if len(nicDesc.Gateway) > 0 && nicDesc.Ip == mainIp {
  1518. cmds.WriteString("GATEWAY=")
  1519. cmds.WriteString(nicDesc.Gateway)
  1520. cmds.WriteString("\n")
  1521. }
  1522. }
  1523. routes4 := make([]netutils2.SRouteInfo, 0)
  1524. routes6 := make([]netutils2.SRouteInfo, 0)
  1525. routes4, routes6 = netutils2.AddNicRoutes(routes4, routes6, nicDesc, mainIp, mainIp6, nicCnt)
  1526. var rtbl strings.Builder
  1527. for _, r := range routes4 {
  1528. rtbl.WriteString(fmt.Sprintf("%s/%d", r.Prefix, r.PrefixLen))
  1529. rtbl.WriteString(" via ")
  1530. rtbl.WriteString(r.Gateway.String())
  1531. rtbl.WriteString(" dev ")
  1532. rtbl.WriteString(nicDesc.Name)
  1533. rtbl.WriteString("\n")
  1534. }
  1535. for _, r := range routes6 {
  1536. rtbl.WriteString(fmt.Sprintf("%s/%d", r.Prefix, r.PrefixLen))
  1537. rtbl.WriteString(" via ")
  1538. rtbl.WriteString(r.Gateway.String())
  1539. rtbl.WriteString(" dev ")
  1540. rtbl.WriteString(nicDesc.Name)
  1541. rtbl.WriteString("\n")
  1542. }
  1543. rtblStr := rtbl.String()
  1544. if len(rtblStr) > 0 {
  1545. var fn = fmt.Sprintf("%s/route-%s", scriptPath, nicDesc.Name)
  1546. if err := rootFs.FilePutContents(fn, rtblStr, false, false); err != nil {
  1547. return err
  1548. }
  1549. }
  1550. dns4list, dns6list := netutils2.GetNicDns(nicDesc)
  1551. if len(dns4list)+len(dns6list) > 0 {
  1552. cmds.WriteString("PEERDNS=yes\n")
  1553. dnsIdx := 1
  1554. for i := 0; i < len(dns4list); i++ {
  1555. cmds.WriteString(fmt.Sprintf("DNS%d=%s\n", dnsIdx, dns4list[i]))
  1556. dnsIdx += 1
  1557. }
  1558. for i := 0; i < len(dns6list); i++ {
  1559. cmds.WriteString(fmt.Sprintf("DNS%d=%s\n", dnsIdx, dns6list[i]))
  1560. dnsIdx += 1
  1561. }
  1562. if len(nicDesc.Domain) > 0 {
  1563. cmds.WriteString(fmt.Sprintf("DOMAIN=%s\n", nicDesc.Domain))
  1564. }
  1565. }
  1566. if len(nicDesc.Ip6) > 0 {
  1567. cmds.WriteString("IPV6INIT=yes\n")
  1568. cmds.WriteString("DHCPV6C=no\n")
  1569. cmds.WriteString("IPV6_AUTOCONF=no\n")
  1570. cmds.WriteString(fmt.Sprintf("IPV6ADDR=%s/%d\n", nicDesc.Ip6, nicDesc.Masklen6))
  1571. if len(nicDesc.Gateway6) > 0 && nicDesc.Ip6 == mainIp6 {
  1572. cmds.WriteString(fmt.Sprintf("IPV6_DEFAULTGW=%s\n", nicDesc.Gateway6))
  1573. }
  1574. }
  1575. }
  1576. } else {
  1577. if len(nicDesc.Ip) > 0 {
  1578. cmds.WriteString("BOOTPROTO=dhcp\n")
  1579. }
  1580. if len(nicDesc.Ip6) > 0 {
  1581. cmds.WriteString("IPV6INIT=yes\n")
  1582. cmds.WriteString("DHCPV6C=yes\n")
  1583. cmds.WriteString("IPV6_AUTOCONF=yes\n")
  1584. }
  1585. }
  1586. var fn = fmt.Sprintf("%s/ifcfg-%s", scriptPath, nicDesc.Name)
  1587. log.Debugf("%s: %s", fn, cmds.String())
  1588. if err := rootFs.FilePutContents(fn, cmds.String(), false, false); err != nil {
  1589. return err
  1590. }
  1591. }
  1592. return nil
  1593. }
  1594. func (r *sRedhatLikeRootFs) deployVlanNetworkingScripts(rootFs IDiskPartition, scriptPath, mainIp, mainIp6 string, nicCnt int, nicDesc *types.SServerNic) error {
  1595. if nicDesc.Vlan <= 1 {
  1596. return nil
  1597. }
  1598. var cmds strings.Builder
  1599. cmds.WriteString("BOOTPROTO=none\n")
  1600. cmds.WriteString(fmt.Sprintf("DEVICE=%s.%d\n", nicDesc.Name, nicDesc.Vlan))
  1601. cmds.WriteString(fmt.Sprintf("NAME=%s.%d\n", nicDesc.Name, nicDesc.Vlan))
  1602. cmds.WriteString("ONBOOT=yes\n")
  1603. if r.isNetworkManagerEnabled(rootFs) {
  1604. cmds.WriteString("NM_CONTROLLED=yes\n")
  1605. } else {
  1606. cmds.WriteString("NM_CONTROLLED=no\n")
  1607. }
  1608. cmds.WriteString("USERCTL=no\n")
  1609. if nicDesc.Mtu > 0 {
  1610. cmds.WriteString(fmt.Sprintf("MTU=%d\n", nicDesc.Mtu))
  1611. }
  1612. if len(nicDesc.Ip) > 0 {
  1613. netmask := netutils2.Netlen2Mask(int(nicDesc.Masklen))
  1614. cmds.WriteString("NETMASK=")
  1615. cmds.WriteString(netmask)
  1616. cmds.WriteString("\n")
  1617. cmds.WriteString("IPADDR=")
  1618. cmds.WriteString(nicDesc.Ip)
  1619. cmds.WriteString("\n")
  1620. if len(nicDesc.Gateway) > 0 && nicDesc.Ip == mainIp {
  1621. cmds.WriteString("GATEWAY=")
  1622. cmds.WriteString(nicDesc.Gateway)
  1623. cmds.WriteString("\n")
  1624. }
  1625. }
  1626. if len(nicDesc.Ip6) > 0 {
  1627. cmds.WriteString("IPV6INIT=yes\n")
  1628. cmds.WriteString("DHCPV6C=no\n")
  1629. cmds.WriteString("IPV6_AUTOCONF=no\n")
  1630. cmds.WriteString(fmt.Sprintf("IPV6ADDR=%s/%d\n", nicDesc.Ip6, nicDesc.Masklen6))
  1631. if len(nicDesc.Gateway6) > 0 && nicDesc.Ip6 == mainIp6 {
  1632. cmds.WriteString(fmt.Sprintf("IPV6_DEFAULTGW=%s\n", nicDesc.Gateway6))
  1633. }
  1634. }
  1635. routes4 := make([]netutils2.SRouteInfo, 0)
  1636. routes6 := make([]netutils2.SRouteInfo, 0)
  1637. routes4, routes6 = netutils2.AddNicRoutes(routes4, routes6, nicDesc, mainIp, mainIp6, nicCnt)
  1638. var rtbl strings.Builder
  1639. for _, r := range routes4 {
  1640. rtbl.WriteString(fmt.Sprintf("%s/%d", r.Prefix, r.PrefixLen))
  1641. rtbl.WriteString(" via ")
  1642. rtbl.WriteString(r.Gateway.String())
  1643. rtbl.WriteString(" dev ")
  1644. rtbl.WriteString(fmt.Sprintf("%s.%d", nicDesc.Name, nicDesc.Vlan))
  1645. rtbl.WriteString("\n")
  1646. }
  1647. for _, r := range routes6 {
  1648. rtbl.WriteString(fmt.Sprintf("%s/%d", r.Prefix, r.PrefixLen))
  1649. rtbl.WriteString(" via ")
  1650. rtbl.WriteString(r.Gateway.String())
  1651. rtbl.WriteString(" dev ")
  1652. rtbl.WriteString(fmt.Sprintf("%s.%d", nicDesc.Name, nicDesc.Vlan))
  1653. rtbl.WriteString("\n")
  1654. }
  1655. rtblStr := rtbl.String()
  1656. if len(rtblStr) > 0 {
  1657. var fn = fmt.Sprintf("%s/route-%s", scriptPath, nicDesc.Name)
  1658. if err := rootFs.FilePutContents(fn, rtblStr, false, false); err != nil {
  1659. return err
  1660. }
  1661. }
  1662. dns4list, dns6list := netutils2.GetNicDns(nicDesc)
  1663. if len(dns4list)+len(dns6list) > 0 {
  1664. cmds.WriteString("PEERDNS=yes\n")
  1665. dnsIdx := 1
  1666. for i := 0; i < len(dns4list); i++ {
  1667. cmds.WriteString(fmt.Sprintf("DNS%d=%s\n", dnsIdx, dns4list[i]))
  1668. dnsIdx += 1
  1669. }
  1670. for i := 0; i < len(dns6list); i++ {
  1671. cmds.WriteString(fmt.Sprintf("DNS%d=%s\n", dnsIdx, dns6list[i]))
  1672. dnsIdx += 1
  1673. }
  1674. if len(nicDesc.Domain) > 0 {
  1675. cmds.WriteString(fmt.Sprintf("DOMAIN=%s\n", nicDesc.Domain))
  1676. }
  1677. }
  1678. cmds.WriteString("VLAN=yes\n")
  1679. var fn = fmt.Sprintf("%s/ifcfg-%s.%d", scriptPath, nicDesc.Name, nicDesc.Vlan)
  1680. log.Debugf("%s: %s", fn, cmds.String())
  1681. if err := rootFs.FilePutContents(fn, cmds.String(), false, false); err != nil {
  1682. return err
  1683. }
  1684. return nil
  1685. }
  1686. func (r *sRedhatLikeRootFs) DeployStandbyNetworkingScripts(rootFs IDiskPartition, nics, nicsStandby []*types.SServerNic) error {
  1687. if err := r.sLinuxRootFs.DeployStandbyNetworkingScripts(rootFs, nics, nicsStandby); err != nil {
  1688. return err
  1689. }
  1690. var netDevPrefix = GetNetDevPrefix(nics)
  1691. for _, nic := range nicsStandby {
  1692. var cmds string
  1693. if len(nic.NicType) == 0 || nic.NicType != "ipmi" {
  1694. cmds += fmt.Sprintf("DEVICE=%s%d\n", netDevPrefix, nic.Index)
  1695. cmds += fmt.Sprintf("NAME=%s%d\n", netDevPrefix, nic.Index)
  1696. cmds += fmt.Sprintf("HWADDR=%s\n", nic.Mac)
  1697. cmds += fmt.Sprintf("MACADDR=%s\n", nic.Mac)
  1698. cmds += "ONBOOT=no\n"
  1699. var fn = fmt.Sprintf("/etc/sysconfig/network-scripts/ifcfg-%s%d", netDevPrefix, nic.Index)
  1700. if err := rootFs.FilePutContents(fn, cmds, false, false); err != nil {
  1701. return err
  1702. }
  1703. }
  1704. }
  1705. return nil
  1706. }
  1707. func (r *sRedhatLikeRootFs) getReleaseMajorVersion(drv IRootFsDriver, rootFs IDiskPartition) (int, error) {
  1708. relInfo := drv.GetReleaseInfo(rootFs)
  1709. if len(relInfo.Version) == 0 {
  1710. return 0, fmt.Errorf("release info version is empty")
  1711. }
  1712. log.Infof("Get release info: %#v", relInfo)
  1713. ver, err := strconv.Atoi(string(relInfo.Version[0]))
  1714. if err != nil {
  1715. return 0, fmt.Errorf("Release version %s not start with digit", relInfo.Version)
  1716. }
  1717. return ver, nil
  1718. }
  1719. func (r *sRedhatLikeRootFs) enableSerialConsole(drv IRootFsDriver, rootFs IDiskPartition, sysInfo *jsonutils.JSONDict) error {
  1720. ver, err := r.getReleaseMajorVersion(drv, rootFs)
  1721. if err != nil {
  1722. return errors.Wrap(err, "Get release major version")
  1723. }
  1724. if ver <= 6 {
  1725. return r.enableSerialConsoleInitCentos(rootFs)
  1726. }
  1727. return r.enableSerialConsoleSystemd(rootFs)
  1728. }
  1729. func (r *sRedhatLikeRootFs) disableSerialConcole(drv IRootFsDriver, rootFs IDiskPartition) error {
  1730. ver, err := r.getReleaseMajorVersion(drv, rootFs)
  1731. if err != nil {
  1732. return errors.Wrap(err, "Get release major version")
  1733. }
  1734. if ver <= 6 {
  1735. r.disableSerialConsoleInit(rootFs)
  1736. return nil
  1737. }
  1738. r.disableSerialConsoleSystemd(rootFs)
  1739. return nil
  1740. }
  1741. type SCentosRootFs struct {
  1742. *sRedhatLikeRootFs
  1743. }
  1744. func NewCentosRootFs(part IDiskPartition) IRootFsDriver {
  1745. return &SCentosRootFs{sRedhatLikeRootFs: newRedhatLikeRootFs(part)}
  1746. }
  1747. func (c *SCentosRootFs) String() string {
  1748. return "CentosRootFs"
  1749. }
  1750. func (c *SCentosRootFs) GetName() string {
  1751. return "CentOS"
  1752. }
  1753. func (c *SCentosRootFs) RootSignatures() []string {
  1754. sig := c.sRedhatLikeRootFs.RootSignatures()
  1755. return append([]string{"/etc/centos-release"}, sig...)
  1756. }
  1757. func (c *SCentosRootFs) GetReleaseInfo(rootFs IDiskPartition) *deployapi.ReleaseInfo {
  1758. rel, _ := rootFs.FileGetContents("/etc/centos-release", false)
  1759. var version string
  1760. if len(rel) > 0 {
  1761. re := regexp.MustCompile(`^\d+\.\d+`)
  1762. dat := strings.Split(string(rel), " ")
  1763. for _, v := range dat {
  1764. if re.Match([]byte(v)) {
  1765. version = v
  1766. break
  1767. }
  1768. }
  1769. }
  1770. return deployapi.NewReleaseInfo(c.GetName(), version, c.GetArch(rootFs))
  1771. }
  1772. func (c *SCentosRootFs) DeployNetworkingScripts(rootFs IDiskPartition, nics []*types.SServerNic) error {
  1773. relInfo := c.GetReleaseInfo(rootFs)
  1774. if err := c.sRedhatLikeRootFs.deployNetworkingScripts(rootFs, nics, relInfo); err != nil {
  1775. return errors.Wrap(err, "sRedhatLikeRootFs.deployNetworkingScripts")
  1776. }
  1777. var udevPath = "/etc/udev/rules.d/"
  1778. var files = []string{"60-net.rules", "75-persistent-net-generator.rules"}
  1779. for _, f := range files {
  1780. sPath := path.Join(udevPath, f)
  1781. if !rootFs.Exists(sPath, false) {
  1782. if err := rootFs.FilePutContents(sPath, "", false, false); err != nil {
  1783. return errors.Wrapf(err, "save %s", sPath)
  1784. }
  1785. }
  1786. }
  1787. return nil
  1788. }
  1789. func (c *SCentosRootFs) EnableSerialConsole(rootFs IDiskPartition, sysInfo *jsonutils.JSONDict) error {
  1790. return c.enableSerialConsole(c, rootFs, sysInfo)
  1791. }
  1792. func (c *SCentosRootFs) DisableSerialConsole(rootFs IDiskPartition) error {
  1793. return c.disableSerialConcole(c, rootFs)
  1794. }
  1795. type SFedoraRootFs struct {
  1796. *sRedhatLikeRootFs
  1797. }
  1798. func NewFedoraRootFs(part IDiskPartition) IRootFsDriver {
  1799. return &SFedoraRootFs{sRedhatLikeRootFs: newRedhatLikeRootFs(part)}
  1800. }
  1801. func (c *SFedoraRootFs) String() string {
  1802. return "FedoraRootFs"
  1803. }
  1804. func (c *SFedoraRootFs) GetName() string {
  1805. return "Fedora"
  1806. }
  1807. func (c *SFedoraRootFs) RootSignatures() []string {
  1808. sig := c.sRedhatLikeRootFs.RootSignatures()
  1809. return append([]string{"/etc/fedora-release"}, sig...)
  1810. }
  1811. func (c *SFedoraRootFs) GetReleaseInfo(rootFs IDiskPartition) *deployapi.ReleaseInfo {
  1812. rel, _ := rootFs.FileGetContents("/etc/fedora-release", false)
  1813. var version string
  1814. if len(rel) > 0 {
  1815. re := regexp.MustCompile(`^\d+`)
  1816. dat := strings.Split(string(rel), " ")
  1817. for _, v := range dat {
  1818. if re.Match([]byte(v)) {
  1819. version = v
  1820. break
  1821. }
  1822. }
  1823. }
  1824. return deployapi.NewReleaseInfo(c.GetName(), version, c.GetArch(rootFs))
  1825. }
  1826. func (c *SFedoraRootFs) DeployNetworkingScripts(rootFs IDiskPartition, nics []*types.SServerNic) error {
  1827. relInfo := c.GetReleaseInfo(rootFs)
  1828. if err := c.sRedhatLikeRootFs.deployNetworkingScripts(rootFs, nics, relInfo); err != nil {
  1829. return err
  1830. }
  1831. return nil
  1832. }
  1833. func (c *SFedoraRootFs) EnableSerialConsole(rootFs IDiskPartition, sysInfo *jsonutils.JSONDict) error {
  1834. return c.enableSerialConsole(c, rootFs, sysInfo)
  1835. }
  1836. func (c *SFedoraRootFs) DisableSerialConsole(rootFs IDiskPartition) error {
  1837. return c.disableSerialConcole(c, rootFs)
  1838. }
  1839. type SRhelRootFs struct {
  1840. *sRedhatLikeRootFs
  1841. }
  1842. func NewRhelRootFs(part IDiskPartition) IRootFsDriver {
  1843. return &SRhelRootFs{sRedhatLikeRootFs: newRedhatLikeRootFs(part)}
  1844. }
  1845. func (d *SRhelRootFs) GetName() string {
  1846. return "RHEL"
  1847. }
  1848. func (d *SRhelRootFs) String() string {
  1849. return "RhelRootFs"
  1850. }
  1851. func (d *SRhelRootFs) GetReleaseInfo(rootFs IDiskPartition) *deployapi.ReleaseInfo {
  1852. rel, _ := rootFs.FileGetContents("/etc/redhat-release", false)
  1853. var version string
  1854. if len(rel) > 0 {
  1855. dat := strings.Split(string(rel), " ")
  1856. if len(dat) > 6 {
  1857. version = dat[6]
  1858. }
  1859. }
  1860. return deployapi.NewReleaseInfo(d.GetName(), version, d.GetArch(rootFs))
  1861. }
  1862. func (d *SRhelRootFs) DeployNetworkingScripts(rootFs IDiskPartition, nics []*types.SServerNic) error {
  1863. relInfo := d.GetReleaseInfo(rootFs)
  1864. if err := d.sRedhatLikeRootFs.deployNetworkingScripts(rootFs, nics, relInfo); err != nil {
  1865. return err
  1866. }
  1867. return nil
  1868. }
  1869. func (c *SRhelRootFs) EnableSerialConsole(rootFs IDiskPartition, sysInfo *jsonutils.JSONDict) error {
  1870. return c.enableSerialConsole(c, rootFs, sysInfo)
  1871. }
  1872. func (c *SRhelRootFs) DisableSerialConsole(rootFs IDiskPartition) error {
  1873. return c.disableSerialConcole(c, rootFs)
  1874. }
  1875. type SOpenEulerRootFs struct {
  1876. *SCentosRootFs
  1877. }
  1878. func NewOpenEulerRootFs(part IDiskPartition) IRootFsDriver {
  1879. return &SOpenEulerRootFs{
  1880. SCentosRootFs: NewCentosRootFs(part).(*SCentosRootFs),
  1881. }
  1882. }
  1883. func (c *SOpenEulerRootFs) String() string {
  1884. return "OpenEulerRootFs"
  1885. }
  1886. func (c *SOpenEulerRootFs) GetName() string {
  1887. return "OpenEuler"
  1888. }
  1889. func (c *SOpenEulerRootFs) RootSignatures() []string {
  1890. sig := c.sLinuxRootFs.RootSignatures()
  1891. return append([]string{"/etc/sysconfig/network", "/etc/openEuler-release"}, sig...)
  1892. }
  1893. func (c *SOpenEulerRootFs) GetReleaseInfo(rootFs IDiskPartition) *deployapi.ReleaseInfo {
  1894. rel, _ := rootFs.FileGetContents("/etc/openEuler-release", false)
  1895. var version string
  1896. if len(rel) > 0 {
  1897. re := regexp.MustCompile(`^\d+\.\d+`)
  1898. dat := strings.Split(string(rel), " ")
  1899. for _, v := range dat {
  1900. if re.Match([]byte(v)) {
  1901. version = v
  1902. break
  1903. }
  1904. }
  1905. }
  1906. version = strings.TrimSpace(version)
  1907. return deployapi.NewReleaseInfo(c.GetName(), version, c.GetArch(rootFs))
  1908. }
  1909. func (c *SOpenEulerRootFs) DeployNetworkingScripts(rootFs IDiskPartition, nics []*types.SServerNic) error {
  1910. relInfo := c.GetReleaseInfo(rootFs)
  1911. if err := c.sRedhatLikeRootFs.deployNetworkingScripts(rootFs, nics, relInfo); err != nil {
  1912. return err
  1913. }
  1914. return nil
  1915. }
  1916. type SGentooRootFs struct {
  1917. *sLinuxRootFs
  1918. }
  1919. func NewGentooRootFs(part IDiskPartition) IRootFsDriver {
  1920. return &SGentooRootFs{sLinuxRootFs: newLinuxRootFs(part)}
  1921. }
  1922. func (d *SGentooRootFs) GetName() string {
  1923. return "Gentoo"
  1924. }
  1925. func (d *SGentooRootFs) String() string {
  1926. return "GentooRootFs"
  1927. }
  1928. func (d *SGentooRootFs) RootSignatures() []string {
  1929. sig := d.sLinuxRootFs.RootSignatures()
  1930. if sig != nil {
  1931. return append(sig, "/etc/gentoo-release")
  1932. } else {
  1933. return []string{"/etc/gentoo-release"}
  1934. }
  1935. }
  1936. func (d *SGentooRootFs) DeployHostname(rootFs IDiskPartition, hn, domain string) error {
  1937. spath := "/etc/conf.d/hostname"
  1938. content := fmt.Sprintf(`hostname="%s"\n`, hn)
  1939. return rootFs.FilePutContents(spath, content, false, false)
  1940. }
  1941. func (l *SGentooRootFs) DeployNetworkingScripts(rootFs IDiskPartition, nics []*types.SServerNic) error {
  1942. if err := l.sLinuxRootFs.DeployNetworkingScripts(rootFs, nics); err != nil {
  1943. return err
  1944. }
  1945. var (
  1946. fn = "/etc/conf.d/net"
  1947. cmds = ""
  1948. )
  1949. var netDevPrefix = GetNetDevPrefix(nics)
  1950. // Ref https://wiki.gentoo.org/wiki/Netifrc
  1951. for _, nic := range nics {
  1952. nicIndex := nic.Index
  1953. if nic.Virtual {
  1954. cmds += fmt.Sprintf(`config_%s%d="`, netDevPrefix, nicIndex)
  1955. cmds += fmt.Sprintf("%s netmask 255.255.255.255", netutils2.PSEUDO_VIP)
  1956. cmds += `"\n`
  1957. } else {
  1958. cmds += fmt.Sprintf(`config_%s%d="dhcp"\n`, netDevPrefix, nicIndex)
  1959. }
  1960. if nic.Mtu > 0 {
  1961. cmds += fmt.Sprintf(`mtu_%s%d="%d"\n`, netDevPrefix, nicIndex, nic.Mtu)
  1962. }
  1963. }
  1964. if err := rootFs.FilePutContents(fn, cmds, false, false); err != nil {
  1965. return err
  1966. }
  1967. for _, nic := range nics {
  1968. nicIndex := nic.Index
  1969. netname := fmt.Sprintf("net.%s%d", netDevPrefix, nicIndex)
  1970. procutils.NewCommand("ln", "-s", "net.lo",
  1971. fmt.Sprintf("%s/etc/init.d/%s", rootFs.GetMountPath(), netname)).Run()
  1972. procutils.NewCommand("chroot",
  1973. rootFs.GetMountPath(), "rc-update", "add", netname, "default").Run()
  1974. }
  1975. return nil
  1976. }
  1977. func (d *SGentooRootFs) GetReleaseInfo(rootFs IDiskPartition) *deployapi.ReleaseInfo {
  1978. return &deployapi.ReleaseInfo{
  1979. Distro: "Gentoo",
  1980. Arch: d.GetArch(rootFs),
  1981. }
  1982. }
  1983. type SArchLinuxRootFs struct {
  1984. *sLinuxRootFs
  1985. }
  1986. func NewArchLinuxRootFs(part IDiskPartition) IRootFsDriver {
  1987. return &SArchLinuxRootFs{sLinuxRootFs: newLinuxRootFs(part)}
  1988. }
  1989. func (d *SArchLinuxRootFs) GetName() string {
  1990. return "ArchLinux"
  1991. }
  1992. func (d *SArchLinuxRootFs) String() string {
  1993. return "ArchLinuxRootFs"
  1994. }
  1995. func (d *SArchLinuxRootFs) RootSignatures() []string {
  1996. sig := d.sLinuxRootFs.RootSignatures()
  1997. if sig != nil {
  1998. return append(sig, "/etc/arch-release")
  1999. } else {
  2000. return []string{"/etc/arch-release"}
  2001. }
  2002. }
  2003. func (d *SArchLinuxRootFs) DeployHostname(rootFs IDiskPartition, hn, domain string) error {
  2004. return rootFs.FilePutContents("/etc/hostname", hn, false, false)
  2005. }
  2006. func (d *SArchLinuxRootFs) GetReleaseInfo(rootFs IDiskPartition) *deployapi.ReleaseInfo {
  2007. return &deployapi.ReleaseInfo{
  2008. Distro: "ArchLinux",
  2009. Arch: d.GetArch(rootFs),
  2010. }
  2011. }
  2012. type SOpenWrtRootFs struct {
  2013. *sLinuxRootFs
  2014. }
  2015. func NewOpenWrtRootFs(part IDiskPartition) IRootFsDriver {
  2016. return &SOpenWrtRootFs{sLinuxRootFs: newLinuxRootFs(part)}
  2017. }
  2018. func (d *SOpenWrtRootFs) GetName() string {
  2019. return "OpenWrt"
  2020. }
  2021. func (d *SOpenWrtRootFs) String() string {
  2022. return "OpenWrtRootFs"
  2023. }
  2024. func (d *SOpenWrtRootFs) RootSignatures() []string {
  2025. return []string{"/bin", "/etc/", "/lib", "/sbin", "/overlay", "/etc/openwrt_release", "/etc/openwrt_version"}
  2026. }
  2027. func (d *SOpenWrtRootFs) featureBoardConfig(rootFs IDiskPartition) bool {
  2028. if rootFs.Exists("/etc/board.d", false) {
  2029. return true
  2030. }
  2031. return false
  2032. }
  2033. func (d *SOpenWrtRootFs) putBoardConfig(rootFs IDiskPartition, f, c string) error {
  2034. if err := rootFs.FilePutContents(f, c, false, false); err != nil {
  2035. return err
  2036. }
  2037. if err := rootFs.Chmod(f, 0755, false); err != nil {
  2038. return err
  2039. }
  2040. return nil
  2041. }
  2042. func (d *SOpenWrtRootFs) DeployPublicKey(rootFs IDiskPartition, selUsr string, pubkeys *deployapi.SSHKeys) error {
  2043. if selUsr == "root" && rootFs.Exists("/etc/dropbear", false) {
  2044. var (
  2045. authFile = "/etc/dropbear/authorized_keys"
  2046. uid = 0
  2047. gid = 0
  2048. replace = false
  2049. )
  2050. return deployAuthorizedKeys(rootFs, authFile, uid, gid, pubkeys, replace, false)
  2051. }
  2052. return d.sLinuxRootFs.DeployPublicKey(rootFs, selUsr, pubkeys)
  2053. }
  2054. func (d *SOpenWrtRootFs) DeployHostname(rootFs IDiskPartition, hn, domain string) error {
  2055. if d.featureBoardConfig(rootFs) {
  2056. f := "/etc/board.d/00-00-onecloud-hostname"
  2057. c := fmt.Sprintf(`. /lib/functions/uci-defaults.sh
  2058. board_config_update
  2059. ucidef_set_hostname '%s'
  2060. board_config_flush
  2061. exit 0
  2062. `, hn)
  2063. return d.putBoardConfig(rootFs, f, c)
  2064. }
  2065. spath := "/etc/config/system"
  2066. if !rootFs.Exists(spath, false) {
  2067. return nil
  2068. }
  2069. bcont, err := rootFs.FileGetContents(spath, false)
  2070. if err != nil {
  2071. return err
  2072. }
  2073. cont := string(bcont)
  2074. re := regexp.MustCompile("option hostname [^\n]+")
  2075. cont = re.ReplaceAllString(cont, fmt.Sprintf("option hostname %s", hn))
  2076. return rootFs.FilePutContents(spath, cont, false, false)
  2077. }
  2078. func (d *SOpenWrtRootFs) DeployNetworkingScripts(rootFs IDiskPartition, nics []*types.SServerNic) error {
  2079. if d.featureBoardConfig(rootFs) {
  2080. macs := ""
  2081. for _, nic := range nics {
  2082. macs = "," + nic.Mac
  2083. }
  2084. f := "/etc/board.d/00-01-onecloud-network"
  2085. c := fmt.Sprintf(`. /lib/functions/uci-defaults.sh
  2086. [ -d /sys/class/net ] || exit 0
  2087. board_config_update
  2088. macs='%s'
  2089. i=0
  2090. oc_set_ifname() {
  2091. local net="$1"; shift
  2092. local ifname="$1"; shift
  2093. if type ucidef_set_interface &>/dev/null; then
  2094. ucidef_set_interface "$net" ifname "$ifname" protocol dhcp
  2095. elif type ucidef_set_interface_raw &>/dev/null; then
  2096. ucidef_set_interface_raw "$net" "$ifname" "dhcp"
  2097. else
  2098. echo "no ucidef function to do network ifname config" >&2
  2099. exit 0
  2100. fi
  2101. }
  2102. for ifname in $(ls /sys/class/net/); do
  2103. p="/sys/class/net/$ifname"
  2104. mac="$(cat "$p/address")"
  2105. if [ "${macs#*,$mac}" != "$macs" ]; then
  2106. oc_set_ifname "lan$i" "$ifname"
  2107. i="$(($i + 1))"
  2108. fi
  2109. done
  2110. board_config_flush
  2111. exit 0
  2112. `, macs)
  2113. return d.putBoardConfig(rootFs, f, c)
  2114. }
  2115. return nil
  2116. }
  2117. func (d *SOpenWrtRootFs) GetReleaseInfo(rootFs IDiskPartition) *deployapi.ReleaseInfo {
  2118. ver, _ := rootFs.FileGetContents("/etc/openwrt_version", false)
  2119. return &deployapi.ReleaseInfo{
  2120. Distro: "OpenWrt",
  2121. Version: string(ver),
  2122. Arch: d.GetArch(rootFs),
  2123. }
  2124. }
  2125. type SCoreOsRootFs struct {
  2126. *sGuestRootFsDriver
  2127. config *coreosutils.SCloudConfig
  2128. }
  2129. func NewCoreOsRootFs(part IDiskPartition) IRootFsDriver {
  2130. return &SCoreOsRootFs{sGuestRootFsDriver: newGuestRootFsDriver(part)}
  2131. }
  2132. func (d *SCoreOsRootFs) GetName() string {
  2133. return "CoreOs"
  2134. }
  2135. func (d *SCoreOsRootFs) String() string {
  2136. return "CoreOsRootFs"
  2137. }
  2138. func (d *SCoreOsRootFs) GetOs() string {
  2139. return "Linux"
  2140. }
  2141. func (d *SCoreOsRootFs) GetReleaseInfo(rootFs IDiskPartition) *deployapi.ReleaseInfo {
  2142. return &deployapi.ReleaseInfo{
  2143. Distro: "CoreOS",
  2144. Version: "stable",
  2145. }
  2146. }
  2147. func (d *SCoreOsRootFs) RootSignatures() []string {
  2148. return []string{"cloud-config.yml"}
  2149. }
  2150. func (d *SCoreOsRootFs) PrepareFsForTemplate(rootFs IDiskPartition) error {
  2151. return nil
  2152. }
  2153. func (d *SCoreOsRootFs) GetConfig() *coreosutils.SCloudConfig {
  2154. if d.config == nil {
  2155. d.config = coreosutils.NewCloudConfig()
  2156. d.config.YunionInit()
  2157. d.config.SetTimezone("Asia/Shanghai")
  2158. }
  2159. return d.config
  2160. }
  2161. func (d *SCoreOsRootFs) DeployHostname(rootFs IDiskPartition, hn, domain string) error {
  2162. d.GetConfig().SetHostname(hn)
  2163. return nil
  2164. }
  2165. func (d *SCoreOsRootFs) DeployPublicKey(rootFs IDiskPartition, selUsr string, pubkeys *deployapi.SSHKeys) error {
  2166. return nil
  2167. }
  2168. func (d *SCoreOsRootFs) DeployHosts(rootFs IDiskPartition, hostname, domain string, ips []string) error {
  2169. d.GetConfig().SetEtcHosts("localhost")
  2170. return nil
  2171. }
  2172. func (d *SCoreOsRootFs) DeployNetworkingScripts(rootFs IDiskPartition, nics []*types.SServerNic) error {
  2173. var netDevPrefix = GetNetDevPrefix(nics)
  2174. for _, nic := range nics {
  2175. name := fmt.Sprintf("%s%d", netDevPrefix, nic.Index)
  2176. cont := "[Match]\n"
  2177. cont += "Name=" + name + "\n"
  2178. cont += "\n[Network]\n"
  2179. cont += "DHCP=yes\n"
  2180. if nic.Mtu > 0 {
  2181. cont += "\n[Link]\n"
  2182. cont += fmt.Sprintf("MTUBytes=%d\n", nic.Mtu)
  2183. }
  2184. runtime := true
  2185. d.GetConfig().AddUnits("00-dhcp-"+name+".network", nil, nil, &runtime, cont, "", nil)
  2186. }
  2187. return nil
  2188. }
  2189. func (d *SCoreOsRootFs) DeployFstabScripts(rootFs IDiskPartition, disks []*deployapi.Disk) error {
  2190. dataDiskIdx := 0
  2191. for i := 1; i < len(disks); i++ {
  2192. dev := fmt.Sprintf("UUID=%s", disks[i].DiskId)
  2193. fs := disks[i].Fs
  2194. if len(fs) > 0 {
  2195. if fs == "swap" {
  2196. d.GetConfig().AddSwap(dev)
  2197. } else {
  2198. mtPath := disks[i].Mountpoint
  2199. if len(mtPath) == 0 {
  2200. mtPath = "/data"
  2201. if dataDiskIdx > 0 {
  2202. mtPath += fmt.Sprintf("%d", dataDiskIdx)
  2203. }
  2204. dataDiskIdx += 1
  2205. }
  2206. d.GetConfig().AddPartition(dev, mtPath, fs)
  2207. }
  2208. }
  2209. }
  2210. return nil
  2211. }
  2212. func (d *SCoreOsRootFs) ChangeUserPasswd(part IDiskPartition, account, gid, publicKey, password string, isRandomPassword bool) (string, error) {
  2213. keys := []string{}
  2214. if len(publicKey) > 0 {
  2215. keys = append(keys, publicKey)
  2216. }
  2217. d.GetConfig().AddUser("core", password, keys, false)
  2218. if len(publicKey) > 0 {
  2219. return seclib2.EncryptBase64(publicKey, password)
  2220. } else {
  2221. return utils.EncryptAESBase64(gid, password)
  2222. }
  2223. }
  2224. func (d *SCoreOsRootFs) GetLoginAccount(rootFs IDiskPartition, user string, defaultRootUser bool, windowsDefaultAdminUser bool) (string, error) {
  2225. return "core", nil
  2226. }
  2227. func (d *SCoreOsRootFs) DeployFiles(deploys []*deployapi.DeployContent) error {
  2228. for _, deploy := range deploys {
  2229. d.GetConfig().AddWriteFile(deploy.Path, deploy.Content, "", "", false)
  2230. }
  2231. return nil
  2232. }
  2233. func (d *SCoreOsRootFs) CommitChanges(IDiskPartition) error {
  2234. ocont, err := d.rootFs.FileGetContents("/cloud-config.yml", false)
  2235. if err != nil {
  2236. return err
  2237. }
  2238. ocfg := coreosutils.NewCloudConfig()
  2239. err = yaml.Unmarshal(ocont, ocfg)
  2240. if err != nil {
  2241. log.Errorln(err)
  2242. }
  2243. conf := d.GetConfig()
  2244. if len(ocfg.Users) > 0 {
  2245. for _, u := range ocfg.Users {
  2246. if conf.HasUser(u.Name) {
  2247. conf.AddUser(u.Name, u.Passwd, u.SshAuthorizedKeys, true)
  2248. }
  2249. }
  2250. }
  2251. if len(ocfg.WriteFiles) > 0 {
  2252. for _, f := range ocfg.WriteFiles {
  2253. if !conf.HasWriteFile(f.Path) {
  2254. conf.AddWriteFile(f.Path, f.Content, f.Permissions, f.Owner, f.Encoding == "base64")
  2255. }
  2256. }
  2257. }
  2258. return d.rootFs.FilePutContents("/cloud-config.yml", conf.String(), false, false)
  2259. }
  2260. func (d *SCoreOsRootFs) ConfigSshd(loginAccount, loginPassword string, sshPort int) error {
  2261. return nil
  2262. }