scratch.go 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727
  1. package dfs
  2. import (
  3. "bufio"
  4. "io"
  5. "io/ioutil"
  6. "os"
  7. "os/exec"
  8. "path"
  9. "strconv"
  10. "strings"
  11. "syscall"
  12. "github.com/rancher/os/pkg/init/one"
  13. "github.com/rancher/os/pkg/log"
  14. "github.com/rancher/os/pkg/netconf"
  15. "github.com/rancher/os/pkg/selinux"
  16. "github.com/rancher/os/pkg/util"
  17. "github.com/docker/libnetwork/resolvconf"
  18. )
  19. const (
  20. defaultPrefix = "/usr"
  21. iptables = "/sbin/iptables"
  22. modprobe = "/sbin/modprobe"
  23. distSuffix = ".dist"
  24. )
  25. var (
  26. mounts = [][]string{
  27. {"devtmpfs", "/dev", "devtmpfs", ""},
  28. {"none", "/dev/pts", "devpts", ""},
  29. {"shm", "/dev/shm", "tmpfs", "rw,nosuid,nodev,noexec,relatime,size=65536k"},
  30. {"mqueue", "/dev/mqueue", "mqueue", "rw,nosuid,nodev,noexec,relatime"},
  31. {"none", "/proc", "proc", ""},
  32. {"none", "/run", "tmpfs", ""},
  33. {"none", "/sys", "sysfs", ""},
  34. {"none", "/sys/fs/cgroup", "tmpfs", ""},
  35. }
  36. optionalMounts = [][]string{
  37. {"none", "/sys/fs/selinux", "selinuxfs", "ro"},
  38. }
  39. )
  40. type Config struct {
  41. Fork bool
  42. PidOne bool
  43. CommandName string
  44. DNSConfig netconf.DNSConfig
  45. BridgeName string
  46. BridgeAddress string
  47. BridgeMtu int
  48. CgroupHierarchy map[string]string
  49. LogFile string
  50. NoLog bool
  51. NoFiles uint64
  52. Environment []string
  53. GraphDirectory string
  54. DaemonConfig string
  55. }
  56. func createMounts(mounts ...[]string) error {
  57. for _, mount := range mounts {
  58. log.Debugf("Mounting %s %s %s %s", mount[0], mount[1], mount[2], mount[3])
  59. err := util.Mount(mount[0], mount[1], mount[2], mount[3])
  60. if err != nil {
  61. return err
  62. }
  63. }
  64. return nil
  65. }
  66. func createOptionalMounts(mounts ...[]string) {
  67. for _, mount := range mounts {
  68. log.Debugf("Mounting %s %s %s %s", mount[0], mount[1], mount[2], mount[3])
  69. err := util.Mount(mount[0], mount[1], mount[2], mount[3])
  70. if err != nil {
  71. log.Debugf("Unable to mount %s %s %s %s: %v", mount[0], mount[1], mount[2], mount[3], err)
  72. }
  73. }
  74. }
  75. func createDirs(dirs ...string) error {
  76. for _, dir := range dirs {
  77. if _, err := os.Stat(dir); os.IsNotExist(err) {
  78. log.Debugf("Creating %s", dir)
  79. err = os.MkdirAll(dir, 0755)
  80. if err != nil {
  81. return err
  82. }
  83. }
  84. }
  85. return nil
  86. }
  87. func mountCgroups(hierarchyConfig map[string]string) error {
  88. f, err := os.Open("/proc/cgroups")
  89. if err != nil {
  90. return err
  91. }
  92. defer f.Close()
  93. scanner := bufio.NewScanner(f)
  94. hierarchies := make(map[string][]string)
  95. for scanner.Scan() {
  96. text := scanner.Text()
  97. log.Debugf("/proc/cgroups: %s", text)
  98. fields := strings.Split(text, "\t")
  99. cgroup := fields[0]
  100. if cgroup == "" || cgroup[0] == '#' || (len(fields) > 3 && fields[3] == "0") {
  101. continue
  102. }
  103. hierarchy := hierarchyConfig[cgroup]
  104. if hierarchy == "" {
  105. hierarchy = fields[1]
  106. }
  107. if hierarchy == "0" {
  108. hierarchy = cgroup
  109. }
  110. hierarchies[hierarchy] = append(hierarchies[hierarchy], cgroup)
  111. }
  112. for _, hierarchy := range hierarchies {
  113. if err := mountCgroup(strings.Join(hierarchy, ",")); err != nil {
  114. return err
  115. }
  116. }
  117. if err = scanner.Err(); err != nil {
  118. return err
  119. }
  120. log.Debug("Done mouting cgroupfs")
  121. return nil
  122. }
  123. func CreateSymlinks(pathSets [][]string) error {
  124. for _, paths := range pathSets {
  125. if err := CreateSymlink(paths[0], paths[1]); err != nil {
  126. return err
  127. }
  128. }
  129. return nil
  130. }
  131. func CreateSymlink(src, dest string) error {
  132. if _, err := os.Lstat(dest); os.IsNotExist(err) {
  133. log.Debugf("Symlinking %s => %s", dest, src)
  134. if err = os.Symlink(src, dest); err != nil {
  135. return err
  136. }
  137. }
  138. return nil
  139. }
  140. func mountCgroup(cgroup string) error {
  141. if err := createDirs("/sys/fs/cgroup/" + cgroup); err != nil {
  142. return err
  143. }
  144. if err := createMounts([][]string{{"none", "/sys/fs/cgroup/" + cgroup, "cgroup", cgroup}}...); err != nil {
  145. return err
  146. }
  147. parts := strings.Split(cgroup, ",")
  148. if len(parts) > 1 {
  149. for _, part := range parts {
  150. if err := CreateSymlink("/sys/fs/cgroup/"+cgroup, "/sys/fs/cgroup/"+part); err != nil {
  151. return err
  152. }
  153. }
  154. }
  155. return nil
  156. }
  157. func execDocker(config *Config, docker, cmd string, args []string) (*exec.Cmd, error) {
  158. if len(args) > 0 && args[0] == "docker" {
  159. args = args[1:]
  160. }
  161. log.Debugf("Launching Docker %s %s %v", docker, cmd, args)
  162. env := os.Environ()
  163. if len(config.Environment) != 0 {
  164. env = append(env, config.Environment...)
  165. }
  166. if config.Fork {
  167. cmd := exec.Command(docker, args...)
  168. if !config.NoLog {
  169. cmd.Stdout = os.Stdout
  170. cmd.Stderr = os.Stderr
  171. }
  172. cmd.Env = env
  173. err := cmd.Start()
  174. if err != nil {
  175. return cmd, err
  176. }
  177. if config.PidOne {
  178. one.PidOne()
  179. }
  180. return cmd, err
  181. }
  182. return nil, syscall.Exec(expand(docker), append([]string{cmd}, args...), env)
  183. }
  184. func copyDefault(folder, name string) error {
  185. defaultFile := path.Join(defaultPrefix, folder, name)
  186. return CopyFile(defaultFile, folder, name)
  187. }
  188. func copyDefaultFolder(folder string) error {
  189. log.Debugf("Copying folder %s", folder)
  190. defaultFolder := path.Join(defaultPrefix, folder)
  191. files, _ := ioutil.ReadDir(defaultFolder)
  192. for _, file := range files {
  193. var err error
  194. if file.IsDir() {
  195. err = copyDefaultFolder(path.Join(folder, file.Name()))
  196. } else {
  197. err = copyDefault(folder, file.Name())
  198. }
  199. if err != nil {
  200. return err
  201. }
  202. }
  203. return nil
  204. }
  205. func defaultFiles(files ...string) error {
  206. for _, file := range files {
  207. dir := path.Dir(file)
  208. name := path.Base(file)
  209. if err := copyDefault(dir, name); err != nil {
  210. return err
  211. }
  212. }
  213. return nil
  214. }
  215. func defaultFolders(folders ...string) error {
  216. for _, folder := range folders {
  217. if err := copyDefaultFolder(folder); err != nil {
  218. return err
  219. }
  220. }
  221. return nil
  222. }
  223. func CopyFile(src, folder, name string) error {
  224. return CopyFileOverwrite(src, folder, name, false)
  225. }
  226. func CopyFileOverwrite(src, folder, name string, overwrite bool) error {
  227. if _, err := os.Lstat(src); os.IsNotExist(err) {
  228. log.Debugf("Not copying %s, does not exists", src)
  229. return nil
  230. }
  231. dst := path.Join(folder, name)
  232. if !overwrite {
  233. if _, err := os.Lstat(dst); err == nil {
  234. log.Debugf("Not copying %s => %s already exists", src, dst)
  235. return nil
  236. }
  237. }
  238. if err := createDirs(folder); err != nil {
  239. return err
  240. }
  241. stat, err := os.Lstat(src)
  242. if err != nil {
  243. return err
  244. }
  245. if stat.Mode()&os.ModeSymlink != 0 {
  246. symDst, err := os.Readlink(src)
  247. if err != nil {
  248. log.Errorf("Failed to readlink: %v", err)
  249. return err
  250. }
  251. // file is a symlink
  252. log.Debugf("Symlinking %s => %s", dst, symDst)
  253. return os.Symlink(symDst, dst)
  254. }
  255. srcFile, err := os.Open(src)
  256. if err != nil {
  257. return err
  258. }
  259. defer srcFile.Close()
  260. dstFile, err := os.Create(dst)
  261. if err != nil {
  262. return err
  263. }
  264. defer dstFile.Close()
  265. log.Debugf("Copying %s => %s", src, dst)
  266. _, err = io.Copy(dstFile, srcFile)
  267. return err
  268. }
  269. func tryCreateFile(name, content string) error {
  270. if _, err := os.Stat(name); err == nil {
  271. return nil
  272. }
  273. if err := createDirs(path.Dir(name)); err != nil {
  274. return err
  275. }
  276. return ioutil.WriteFile(name, []byte(content), 0644)
  277. }
  278. func createPasswd() error {
  279. return tryCreateFile("/etc/passwd", "root:x:0:0:root:/root:/bin/sh\n")
  280. }
  281. func createGroup() error {
  282. return tryCreateFile("/etc/group", "root:x:0:\n")
  283. }
  284. func setupNetworking(cfg *Config) error {
  285. if cfg == nil {
  286. return nil
  287. }
  288. hostname, err := os.Hostname()
  289. if err != nil {
  290. return err
  291. }
  292. tryCreateFile("/etc/hosts", `127.0.0.1 localhost
  293. ::1 localhost ip6-localhost ip6-loopback
  294. fe00::0 ip6-localnet
  295. ff00::0 ip6-mcastprefix
  296. ff02::1 ip6-allnodes
  297. ff02::2 ip6-allrouters
  298. 127.0.1.1 `+hostname)
  299. if len(cfg.DNSConfig.Nameservers) != 0 {
  300. resolve, err := ioutil.ReadFile("/etc/resolv.conf")
  301. log.Debugf("Resolve.conf == [%s], %v", resolve, err)
  302. if err != nil {
  303. log.Infof("scratch Writing empty resolv.conf (%v) %v", []string{}, []string{})
  304. if _, err := resolvconf.Build("/etc/resolv.conf", []string{}, []string{}, nil); err != nil {
  305. return err
  306. }
  307. }
  308. }
  309. if cfg.BridgeName != "" && cfg.BridgeName != "none" {
  310. log.Debugf("Creating bridge %s (%s)", cfg.BridgeName, cfg.BridgeAddress)
  311. if _, err := netconf.ApplyNetworkConfigs(&netconf.NetworkConfig{
  312. Interfaces: map[string]netconf.InterfaceConfig{
  313. cfg.BridgeName: {
  314. Address: cfg.BridgeAddress,
  315. MTU: cfg.BridgeMtu,
  316. Bridge: "true",
  317. },
  318. },
  319. }, false, false); err != nil {
  320. log.Errorf("Error creating bridge: %s", err)
  321. return err
  322. }
  323. }
  324. return nil
  325. }
  326. func GetValue(index int, args []string) string {
  327. val := args[index]
  328. parts := strings.SplitN(val, "=", 2)
  329. if len(parts) == 1 {
  330. if len(args) > index+1 {
  331. return args[index+1]
  332. }
  333. return ""
  334. }
  335. return parts[1]
  336. }
  337. func ParseConfig(config *Config, args ...string) []string {
  338. for i, arg := range args {
  339. if strings.HasPrefix(arg, "--bip") {
  340. config.BridgeAddress = GetValue(i, args)
  341. } else if strings.HasPrefix(arg, "--fixed-cidr") {
  342. config.BridgeAddress = GetValue(i, args)
  343. } else if strings.HasPrefix(arg, "-b") || strings.HasPrefix(arg, "--bridge") {
  344. config.BridgeName = GetValue(i, args)
  345. } else if strings.HasPrefix(arg, "--config-file") {
  346. config.DaemonConfig = GetValue(i, args)
  347. } else if strings.HasPrefix(arg, "--mtu") {
  348. mtu, err := strconv.Atoi(GetValue(i, args))
  349. if err != nil {
  350. config.BridgeMtu = mtu
  351. }
  352. } else if strings.HasPrefix(arg, "-g") || strings.HasPrefix(arg, "--graph") {
  353. config.GraphDirectory = GetValue(i, args)
  354. }
  355. }
  356. if config.BridgeName != "" && config.BridgeAddress != "" {
  357. newArgs := []string{}
  358. skip := false
  359. for _, arg := range args {
  360. if skip {
  361. skip = false
  362. continue
  363. }
  364. if arg == "--bip" {
  365. skip = true
  366. continue
  367. } else if strings.HasPrefix(arg, "--bip=") {
  368. continue
  369. }
  370. newArgs = append(newArgs, arg)
  371. }
  372. args = newArgs
  373. }
  374. return args
  375. }
  376. func PrepareFs(config *Config) error {
  377. if err := createMounts(mounts...); err != nil {
  378. return err
  379. }
  380. createOptionalMounts(optionalMounts...)
  381. if err := mountCgroups(config.CgroupHierarchy); err != nil {
  382. return err
  383. }
  384. if err := createLayout(config); err != nil {
  385. return err
  386. }
  387. return firstPrepare()
  388. }
  389. func touchSocket(path string) error {
  390. if err := syscall.Unlink(path); err != nil && !os.IsNotExist(err) {
  391. return err
  392. }
  393. return ioutil.WriteFile(path, []byte{}, 0700)
  394. }
  395. func touchSockets(args ...string) error {
  396. touched := false
  397. for i, arg := range args {
  398. if strings.HasPrefix(arg, "-H") {
  399. val := GetValue(i, args)
  400. if strings.HasPrefix(val, "unix://") {
  401. val = val[len("unix://"):]
  402. log.Debugf("Creating temp file at %s", val)
  403. if err := touchSocket(val); err != nil {
  404. return err
  405. }
  406. touched = true
  407. }
  408. }
  409. }
  410. if !touched {
  411. return touchSocket("/var/run/docker.sock")
  412. }
  413. return nil
  414. }
  415. func createDaemonConfig(config *Config) error {
  416. if config.DaemonConfig == "" {
  417. return nil
  418. }
  419. if _, err := os.Stat(config.DaemonConfig); os.IsNotExist(err) {
  420. if err := os.MkdirAll(path.Dir(config.DaemonConfig), 0755); err != nil {
  421. return err
  422. }
  423. return ioutil.WriteFile(config.DaemonConfig, []byte("{}"), 0600)
  424. }
  425. return nil
  426. }
  427. func cleanupFiles(graphDirectory string) {
  428. zeroFiles := []string{
  429. "/etc/docker/key.json",
  430. "/etc/docker/daemon.json",
  431. "/etc/docker/system-daemon.json",
  432. path.Join(graphDirectory, "image/overlay/repositories.json"),
  433. }
  434. for _, file := range zeroFiles {
  435. if stat, err := os.Stat(file); err == nil {
  436. if stat.Size() < 2 {
  437. log.Warnf("Deleting invalid json file: %s", file)
  438. os.Remove(file)
  439. }
  440. }
  441. }
  442. }
  443. func createLayout(config *Config) error {
  444. if err := createDirs("/tmp", "/root/.ssh", "/var", "/usr/lib"); err != nil {
  445. return err
  446. }
  447. graphDirectory := config.GraphDirectory
  448. if config.GraphDirectory == "" {
  449. graphDirectory = "/var/lib/docker"
  450. }
  451. if err := createDirs(graphDirectory); err != nil {
  452. return err
  453. }
  454. if err := createDaemonConfig(config); err != nil {
  455. return err
  456. }
  457. cleanupFiles(graphDirectory)
  458. selinux.SetFileContext(graphDirectory, "system_u:object_r:var_lib_t:s0")
  459. return CreateSymlinks([][]string{
  460. {"usr/lib", "/lib"},
  461. {"usr/sbin", "/sbin"},
  462. {"../run", "/var/run"},
  463. })
  464. }
  465. func firstPrepare() error {
  466. os.Setenv("PATH", "/sbin:/usr/sbin:/usr/bin")
  467. if err := defaultFiles(
  468. "/etc/ssl/certs/ca-certificates.crt",
  469. "/etc/passwd",
  470. "/etc/group",
  471. ); err != nil {
  472. return err
  473. }
  474. if err := defaultFolders(
  475. "/etc/docker",
  476. "/etc/selinux",
  477. "/etc/selinux/ros",
  478. "/etc/selinux/ros/policy",
  479. "/etc/selinux/ros/contexts",
  480. ); err != nil {
  481. return err
  482. }
  483. if err := createPasswd(); err != nil {
  484. return err
  485. }
  486. return createGroup()
  487. }
  488. func secondPrepare(config *Config, docker string, args ...string) error {
  489. if err := setupNetworking(config); err != nil {
  490. return err
  491. }
  492. if err := touchSockets(args...); err != nil {
  493. return err
  494. }
  495. if err := setupLogging(config); err != nil {
  496. return err
  497. }
  498. for _, i := range []string{docker, iptables, modprobe} {
  499. if err := setupBin(config, i); err != nil {
  500. return err
  501. }
  502. }
  503. if err := setUlimit(config); err != nil {
  504. return err
  505. }
  506. ioutil.WriteFile("/proc/sys/net/ipv4/ip_forward", []byte("1"), 0655)
  507. return nil
  508. }
  509. func expand(bin string) string {
  510. expanded, err := exec.LookPath(bin)
  511. if err == nil {
  512. return expanded
  513. }
  514. return bin
  515. }
  516. func setupBin(config *Config, bin string) error {
  517. expanded, err := exec.LookPath(bin)
  518. if err == nil {
  519. return nil
  520. }
  521. expanded, err = exec.LookPath(bin + distSuffix)
  522. if err != nil {
  523. // Purposely not returning error
  524. return nil
  525. }
  526. return CreateSymlink(expanded, expanded[:len(expanded)-len(distSuffix)])
  527. }
  528. func setupLogging(config *Config) error {
  529. if config.LogFile == "" {
  530. return nil
  531. }
  532. if err := createDirs(path.Dir(config.LogFile)); err != nil {
  533. return err
  534. }
  535. output, err := os.OpenFile(config.LogFile, os.O_RDWR|os.O_CREATE|os.O_APPEND, 0666)
  536. if err != nil {
  537. return err
  538. }
  539. syscall.Dup3(int(output.Fd()), int(os.Stdout.Fd()), 0)
  540. syscall.Dup3(int(output.Fd()), int(os.Stderr.Fd()), 0)
  541. return nil
  542. }
  543. func setUlimit(cfg *Config) error {
  544. var rLimit syscall.Rlimit
  545. if err := syscall.Getrlimit(syscall.RLIMIT_NOFILE, &rLimit); err != nil {
  546. return err
  547. }
  548. if cfg.NoFiles == 0 {
  549. rLimit.Max = 1000000
  550. } else {
  551. rLimit.Max = cfg.NoFiles
  552. }
  553. rLimit.Cur = rLimit.Max
  554. return syscall.Setrlimit(syscall.RLIMIT_NOFILE, &rLimit)
  555. }
  556. func runOrExec(config *Config, docker string, args ...string) (*exec.Cmd, error) {
  557. if err := secondPrepare(config, docker, args...); err != nil {
  558. return nil, err
  559. }
  560. cmd := path.Base(docker)
  561. if config != nil && config.CommandName != "" {
  562. cmd = config.CommandName
  563. }
  564. if cmd == "dockerd" && len(args) > 1 && args[0] == "daemon" {
  565. args = args[1:]
  566. }
  567. return execDocker(config, docker, cmd, args)
  568. }
  569. func LaunchDocker(config *Config, docker string, args ...string) (*exec.Cmd, error) {
  570. if err := PrepareFs(config); err != nil {
  571. return nil, err
  572. }
  573. return runOrExec(config, docker, args...)
  574. }
  575. func Main() {
  576. log.InitLogger()
  577. if os.Getenv("DOCKER_LAUNCH_DEBUG") == "true" {
  578. log.SetLevel(log.DebugLevel)
  579. }
  580. if len(os.Args) < 2 {
  581. log.Fatalf("Usage Example: %s /usr/bin/docker -d -D", os.Args[0])
  582. }
  583. args := []string{}
  584. if len(os.Args) > 1 {
  585. args = os.Args[2:]
  586. }
  587. var config Config
  588. args = ParseConfig(&config, args...)
  589. if os.Getenv("DOCKER_LAUNCH_REAP") == "true" {
  590. config.Fork = true
  591. config.PidOne = true
  592. }
  593. log.Debugf("Launch config %#v", config)
  594. _, err := LaunchDocker(&config, os.Args[1], args...)
  595. if err != nil {
  596. log.Fatal(err)
  597. }
  598. }