// serviceManip allows services manipulation either over chroot // (in case we need modify service state on an off-line image) or // without chrooting (in case we are deploying upon a running system) // Example: //<services> // <service> // <name>iptables</name> // <type>sysv</type> // <status>off</status> // <action></action> // </service> // <service> // <name>ip6tables</name> // <type>sysv</type> // <status>off</status> // <action></action> // <chroot>false</chroot> // </service> // <service> // <name>ssh</name> // <type>upstart</type> // <status></status> // <action>reload</action> // <chroot>false</chroot> // </service> //</services> func serviceManip(pathToXml, pathToSlash string) error { dataBuf, err := ioutil.ReadFile(pathToXml) if err != nil { return utils.FormatError(err) } servicesStruct := Services{} if err := xml.Unmarshal(dataBuf, &servicesStruct); err != nil { return utils.FormatError(err) } for _, val := range servicesStruct.Srvcs { // switch the service type switch val.Type { case SVC_TYPE_SYSV: switch val.Status { case SVC_STATUS_ON, SVC_STATUS_OFF: var cmd string var action string if val.Chroot { if err := exec.Command("chroot", pathToSlash, "which", "update-rc.d").Run(); err != nil { cmd = "chkconfig" action = val.Status } else { cmd = "update-rc.d" switch val.Status { case SVC_STATUS_ON: action = "enable" case SVC_STATUS_OFF: action = "disable" } } if err := exec.Command("chroot", pathToSlash, cmd, val.Name, action).Run(); err != nil { return utils.FormatError(fmt.Errorf("chroot %s %s %s %s", pathToSlash, cmd, val.Name, action)) } } else { if err := exec.Command(cmd, val.Name, action).Run(); err != nil { return utils.FormatError(fmt.Errorf("%s %s %s", cmd, val.Name, action)) } } default: return utils.FormatError(errors.New(`ServiceManip :sysv:status configuration error - unsupported service status`)) } // switch appropriate action towards the service switch val.Action { case ACTION_STOP, ACTION_START, ACTION_RESTART, ACTION_RELOAD: if err := exec.Command("service", val.Name, val.Action).Run(); err != nil { return utils.FormatError(fmt.Errorf("service %s %s", val.Name, val.Action)) } case "": default: return utils.FormatError(errors.New(`ServiceManip :sysv:action: configuration error - unsupported action ` + val.Action)) } case SVC_TYPE_UPSTART: fullPathToChrootDir := filepath.Join(pathToSlash, "/etc/init/") servicePath := filepath.Join(fullPathToChrootDir, val.Name+".conf") dummyServicePath := filepath.Join(fullPathToChrootDir, val.Name+".override") switch val.Status { case SVC_STATUS_OFF: if _, err := os.Stat(servicePath); err == nil { if err := ioutil.WriteFile(dummyServicePath, []byte("manual"), 0644); err != nil { return utils.FormatError(err) } } case SVC_STATUS_ON: if err := ioutils.RemoveIfExists(false, dummyServicePath); err != nil { return utils.FormatError(err) } default: return utils.FormatError(errors.New(`configuration error - unsupported service status`)) } switch val.Action { case ACTION_STOP, ACTION_START, ACTION_RESTART, ACTION_RELOAD: if err := exec.Command("initctl", val.Name, val.Action).Run(); err != nil { return utils.FormatError(fmt.Errorf("initctl %s %s", val.Name, val.Action)) } case "": default: return utils.FormatError(errors.New(`ServiceManip : upstart :configuration error - unsupported action`)) } } } return nil }
// injectStuff modifies a RAW image "on-the-fly" // by injecting appropriate stuff to the mounted vHDD // 1) it receives src and dst directories paths // 2) it looks for a file inject.config inside the src directory // 3) in case the file found parses it and inject appropriate stuff // according to the file. // Example: //<inject_items> // <inject_item> // <name>file1</name> // <bkp_name>file1.bkp</bkp_name> // <action>upload</action> // <type>file</type> // <location>/opt</location> // <permissions>0755</permissions> // <owner_id>0</owner_id> // <group_id>0</group_id> // </inject_item> //</inject_items func injectManip(pathToXml, pathToSlash string) error { dataBuf, err := ioutil.ReadFile(pathToXml) if err != nil { return utils.FormatError(err) } itemsStruct := InjectItems{} if err := xml.Unmarshal(dataBuf, &itemsStruct); err != nil { return utils.FormatError(err) } for _, val := range itemsStruct.InjItems { baseDir := filepath.Dir(pathToXml) srcPath := baseDir + "/items/" + val.Name targetLocationPath := filepath.Join(pathToSlash, val.Location) dstPath := filepath.Join(targetLocationPath, val.Name) dstBkpPath := filepath.Join(targetLocationPath, val.BkpName) switch val.Action { case ACTION_REMOVE: if val.BkpName == "" { if err := ioutils.RemoveIfExists(true, dstPath); err != nil { return utils.FormatError(err) } } else { if _, err := os.Stat(dstPath); err == nil { if err := os.Rename(dstPath, dstBkpPath); err != nil { return utils.FormatError(err) } } } case ACTION_UPLOAD, ACTION_CREATE: switch val.Type { case ITEM_TYPE_FILE: if err := ioutils.CreateDirRecursively(targetLocationPath, 0755, val.UID, val.GID, false); err != nil { if err != os.ErrExist { return utils.FormatError(err) } } if val.Action == ACTION_UPLOAD { if val.BkpName != "" { if _, err := os.Stat(dstPath); err == nil { if err := os.Rename(dstPath, dstBkpPath); err != nil { return utils.FormatError(err) } } } if err := ioutils.CopyFile(srcPath, dstPath, 0, val.UID, val.GID, false); err != nil { return utils.FormatError(err) } } else { fd, err := os.Create(dstPath) if err != nil { return utils.FormatError(err) } fd.Close() } // FIXME: // we shuld use val.Permissions for setting permissions ,example // if err := CopyFile(srcFilePath, dstFilePath, // val.Permissions, val.UID, val.GID); err != nil { // return err //} // Currently , it copies permission flags from the source case ITEM_TYPE_DIR: if err := ioutils.CreateDirRecursively(filepath.Join(targetLocationPath, val.Name), val.Permissions, val.UID, val.GID, false); err != nil { return utils.FormatError(err) } if val.Action == ACTION_UPLOAD { if val.BkpName != "" { if _, err := os.Stat(dstPath); err == nil { if err := os.Rename(dstPath, dstBkpPath); err != nil { return utils.FormatError(err) } } } if err := ioutils.CopyDir(srcPath, dstPath); err != nil { return utils.FormatError(err) } } case ITEM_TYPE_LINK: if _, err := os.Stat(val.BkpName); err != nil { return utils.FormatError(err) } if err := ioutils.RemoveIfExists(false, dstPath); err != nil { return utils.FormatError(err) } if err := ioutils.CreateDirRecursively(targetLocationPath, val.Permissions, val.UID, val.GID, false); err != nil { return utils.FormatError(err) } if err := os.Symlink(val.BkpName, dstPath); err != nil { return utils.FormatError(err) } default: return utils.FormatError(errors.New("injectManip: configuration error - unexpected element type")) } default: return utils.FormatError(errors.New("injectManip: configuration error - unexpected action")) } } return nil }