func (_ *File) RenderLocal(t *local.LocalTarget, a, e, changes *File) error { dirMode := os.FileMode(0755) fileMode, err := fi.ParseFileMode(fi.StringValue(e.Mode), 0644) if err != nil { return fmt.Errorf("invalid file mode for %q: %q", e.Path, fi.StringValue(e.Mode)) } if a != nil { if e.IfNotExists { glog.V(2).Infof("file exists and IfNotExists set; skipping %q", e.Path) return nil } } changed := false if e.Type == FileType_Symlink { if changes.Symlink != nil { // This will currently fail if the target already exists. // That's probably a good thing for now ... it is hard to know what to do here! glog.Infof("Creating symlink %q -> %q", e.Path, *changes.Symlink) err := os.Symlink(*changes.Symlink, e.Path) if err != nil { return fmt.Errorf("error creating symlink %q -> %q: %v", e.Path, *changes.Symlink, err) } changed = true } } else if e.Type == FileType_Directory { if a == nil { parent := filepath.Dir(strings.TrimSuffix(e.Path, "/")) err := os.MkdirAll(parent, dirMode) if err != nil { return fmt.Errorf("error creating parent directories %q: %v", parent, err) } err = os.MkdirAll(e.Path, fileMode) if err != nil { return fmt.Errorf("error creating directory %q: %v", e.Path, err) } changed = true } } else if e.Type == FileType_File { if changes.Contents != nil { err = fi.WriteFile(e.Path, e.Contents, fileMode, dirMode) if err != nil { return fmt.Errorf("error copying file %q: %v", e.Path, err) } changed = true } } else { return fmt.Errorf("File type=%q not valid/supported", e.Type) } if changes.Mode != nil { modeChanged, err := fi.EnsureFileMode(e.Path, fileMode) if err != nil { return fmt.Errorf("error changing mode on %q: %v", e.Path, err) } changed = changed || modeChanged } if changes.Owner != nil || changes.Group != nil { ownerChanged, err := fi.EnsureFileOwner(e.Path, fi.StringValue(e.Owner), fi.StringValue(e.Group)) if err != nil { return fmt.Errorf("error changing owner/group on %q: %v", e.Path, err) } changed = changed || ownerChanged } if changed && e.OnChangeExecute != nil { args := e.OnChangeExecute human := strings.Join(args, " ") glog.Infof("Changed; will execute OnChangeExecute command: %q", human) cmd := exec.Command(args[0], args[1:]...) output, err := cmd.CombinedOutput() if err != nil { return fmt.Errorf("error executing command %q: %v\nOutput: %s", human, err, output) } } return nil }
func (_ *Service) RenderLocal(t *local.LocalTarget, a, e, changes *Service) error { serviceName := e.Name action := "" if changes.Running != nil && fi.BoolValue(e.ManageState) { if fi.BoolValue(e.Running) { action = "restart" } else { action = "stop" } } if changes.Definition != nil { servicePath := path.Join(systemdSystemPath, serviceName) err := fi.WriteFile(servicePath, fi.NewStringResource(*e.Definition), 0644, 0755) if err != nil { return fmt.Errorf("error writing systemd service file: %v", err) } glog.Infof("Reloading systemd configuration") cmd := exec.Command("systemctl", "daemon-reload") output, err := cmd.CombinedOutput() if err != nil { return fmt.Errorf("error doing systemd daemon-reload: %v\nOutput: %s", err, output) } } // "SmartRestart" - look at the obvious dependencies in the systemd service, restart if start time older if fi.BoolValue(e.ManageState) && fi.BoolValue(e.SmartRestart) { definition := fi.StringValue(e.Definition) if definition == "" && a != nil { definition = fi.StringValue(a.Definition) } if action == "" && fi.BoolValue(e.Running) && definition != "" { dependencies, err := getSystemdDependencies(serviceName, definition) if err != nil { return err } var newest time.Time for _, dependency := range dependencies { stat, err := os.Stat(dependency) if err != nil { glog.Infof("Ignoring error checking service dependency %q: %v", dependency, err) continue } modTime := stat.ModTime() if newest.IsZero() || newest.Before(modTime) { newest = modTime } } if !newest.IsZero() { properties, err := getSystemdStatus(e.Name) if err != nil { return err } startedAt := properties["ExecMainStartTimestamp"] if startedAt == "" { glog.Warningf("service was running, but did not have ExecMainStartTimestamp: %q", serviceName) } else { startedAtTime, err := time.Parse("Mon 2006-01-02 15:04:05 MST", startedAt) if err != nil { return fmt.Errorf("unable to parse service ExecMainStartTimestamp: %q", startedAt) } if startedAtTime.Before(newest) { glog.V(2).Infof("will restart service %q because dependency changed after service start", serviceName) action = "restart" } else { glog.V(2).Infof("will not restart service %q - started after dependencies", serviceName) } } } } } if action != "" && fi.BoolValue(e.ManageState) { glog.Infof("Restarting service %q", serviceName) cmd := exec.Command("systemctl", action, serviceName) output, err := cmd.CombinedOutput() if err != nil { return fmt.Errorf("error doing systemd %s %s: %v\nOutput: %s", action, serviceName, err, output) } } return nil }