(conn *systemdDbus.Conn, group string, properties []systemdDbus.Property, ignoreExists bool)
| 1078 | } |
| 1079 | |
| 1080 | func startUnit(conn *systemdDbus.Conn, group string, properties []systemdDbus.Property, ignoreExists bool) error { |
| 1081 | ctx := context.TODO() |
| 1082 | |
| 1083 | statusChan := make(chan string, 1) |
| 1084 | defer close(statusChan) |
| 1085 | |
| 1086 | retry := true |
| 1087 | started := false |
| 1088 | |
| 1089 | for !started { |
| 1090 | if _, err := conn.StartTransientUnitContext(ctx, group, "replace", properties, statusChan); err != nil { |
| 1091 | if !isUnitExists(err) { |
| 1092 | return err |
| 1093 | } |
| 1094 | |
| 1095 | if ignoreExists { |
| 1096 | return nil |
| 1097 | } |
| 1098 | |
| 1099 | if retry { |
| 1100 | retry = false |
| 1101 | // When a unit of the same name already exists, it may be a leftover failed unit. |
| 1102 | // If we reset it once, systemd can try to remove it. |
| 1103 | attemptFailedUnitReset(conn, group) |
| 1104 | continue |
| 1105 | } |
| 1106 | |
| 1107 | return err |
| 1108 | } else { |
| 1109 | started = true |
| 1110 | } |
| 1111 | } |
| 1112 | |
| 1113 | systemdStartUnitTimeout := 30 * time.Second |
| 1114 | select { |
| 1115 | case s := <-statusChan: |
| 1116 | if s != "done" { |
| 1117 | attemptFailedUnitReset(conn, group) |
| 1118 | return fmt.Errorf("error creating systemd unit `%s`: got `%s`", group, s) |
| 1119 | } |
| 1120 | case <-time.After(systemdStartUnitTimeout): |
| 1121 | attemptFailedUnitReset(conn, group) |
| 1122 | return fmt.Errorf("timed out while waiting for StartTransientUnit(%s) completion signal from dbus after %v", group, systemdStartUnitTimeout) |
| 1123 | } |
| 1124 | |
| 1125 | return nil |
| 1126 | } |
| 1127 | |
| 1128 | func attemptFailedUnitReset(conn *systemdDbus.Conn, group string) { |
| 1129 | ctx := context.TODO() |
no test coverage detected
searching dependent graphs…