Compare commits
6 Commits
Author | SHA1 | Date | |
---|---|---|---|
|
a9a910b5c4 | ||
|
8e94b4140a | ||
|
cd322863e9 | ||
|
786e4bef65 | ||
|
269a658d4b | ||
|
e317c7eb9a |
@@ -123,6 +123,7 @@ The `coreos.units.*` parameters define a list of arbitrary systemd units to star
|
|||||||
- **enable**: Boolean indicating whether or not to handle the [Install] section of the unit file. This is similar to running `systemctl enable <name>`. Default value is false.
|
- **enable**: Boolean indicating whether or not to handle the [Install] section of the unit file. This is similar to running `systemctl enable <name>`. Default value is false.
|
||||||
- **content**: Plaintext string representing entire unit file. If no value is provided, the unit is assumed to exist already.
|
- **content**: Plaintext string representing entire unit file. If no value is provided, the unit is assumed to exist already.
|
||||||
- **command**: Command to execute on unit: start, stop, reload, restart, try-restart, reload-or-restart, reload-or-try-restart. Default value is restart.
|
- **command**: Command to execute on unit: start, stop, reload, restart, try-restart, reload-or-restart, reload-or-try-restart. Default value is restart.
|
||||||
|
- **mask**: Whether to mask the unit file by symlinking it to `/dev/null` (analogous to `systemctl mask <name>`). Note that unlike `systemctl mask`, **this will destructively remove any existing unit file** located at `/etc/systemd/system/<unit>`, to ensure that the mask succeeds. Default value is false.
|
||||||
|
|
||||||
**NOTE:** The command field is ignored for all network, netdev, and link units. The systemd-networkd.service unit will be restarted in their place.
|
**NOTE:** The command field is ignored for all network, netdev, and link units. The systemd-networkd.service unit will be restarted in their place.
|
||||||
|
|
||||||
|
@@ -11,7 +11,7 @@ import (
|
|||||||
"github.com/coreos/coreos-cloudinit/system"
|
"github.com/coreos/coreos-cloudinit/system"
|
||||||
)
|
)
|
||||||
|
|
||||||
const version = "0.7.2"
|
const version = "0.7.3"
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
//Removes timestamp since it is displayed already during booting
|
//Removes timestamp since it is displayed already during booting
|
||||||
|
@@ -6,7 +6,6 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
"log"
|
"log"
|
||||||
"math"
|
|
||||||
"net"
|
"net"
|
||||||
"net/http"
|
"net/http"
|
||||||
neturl "net/url"
|
neturl "net/url"
|
||||||
@@ -43,6 +42,14 @@ func NewHttpClient() *HttpClient {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func expBackoff(interval, max time.Duration) time.Duration {
|
||||||
|
interval = interval * 2
|
||||||
|
if interval > max {
|
||||||
|
interval = max
|
||||||
|
}
|
||||||
|
return interval
|
||||||
|
}
|
||||||
|
|
||||||
// Fetches a given URL with support for exponential backoff and maximum retries
|
// Fetches a given URL with support for exponential backoff and maximum retries
|
||||||
func (h *HttpClient) Get(rawurl string) ([]byte, error) {
|
func (h *HttpClient) Get(rawurl string) ([]byte, error) {
|
||||||
if rawurl == "" {
|
if rawurl == "" {
|
||||||
@@ -84,6 +91,7 @@ func (h *HttpClient) Get(rawurl string) ([]byte, error) {
|
|||||||
Transport: transport,
|
Transport: transport,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
duration := 50 * time.Millisecond
|
||||||
for retry := 1; retry <= h.MaxRetries; retry++ {
|
for retry := 1; retry <= h.MaxRetries; retry++ {
|
||||||
log.Printf("Fetching data from %s. Attempt #%d", dataURL, retry)
|
log.Printf("Fetching data from %s. Attempt #%d", dataURL, retry)
|
||||||
|
|
||||||
@@ -106,13 +114,8 @@ func (h *HttpClient) Get(rawurl string) ([]byte, error) {
|
|||||||
log.Printf("Unable to fetch data: %s", err.Error())
|
log.Printf("Unable to fetch data: %s", err.Error())
|
||||||
}
|
}
|
||||||
|
|
||||||
duration := time.Millisecond * time.Duration((math.Pow(float64(2), float64(retry)) * 100))
|
duration = expBackoff(duration, h.MaxBackoff)
|
||||||
if duration > h.MaxBackoff {
|
|
||||||
duration = h.MaxBackoff
|
|
||||||
}
|
|
||||||
|
|
||||||
log.Printf("Sleeping for %v...", duration)
|
log.Printf("Sleeping for %v...", duration)
|
||||||
|
|
||||||
time.Sleep(duration)
|
time.Sleep(duration)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -3,23 +3,38 @@ package pkg
|
|||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
|
"math"
|
||||||
"net/http"
|
"net/http"
|
||||||
"net/http/httptest"
|
"net/http/httptest"
|
||||||
"testing"
|
"testing"
|
||||||
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
var expBackoffTests = []struct {
|
func TestExpBackoff(t *testing.T) {
|
||||||
count int
|
duration := time.Millisecond
|
||||||
body string
|
max := time.Hour
|
||||||
}{
|
for i := 0; i < math.MaxUint16; i++ {
|
||||||
{0, "number of attempts: 0"},
|
duration = expBackoff(duration, max)
|
||||||
{1, "number of attempts: 1"},
|
if duration < 0 {
|
||||||
{2, "number of attempts: 2"},
|
t.Fatalf("duration too small: %v %v", duration, i)
|
||||||
|
}
|
||||||
|
if duration > max {
|
||||||
|
t.Fatalf("duration too large: %v %v", duration, i)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Test exponential backoff and that it continues retrying if a 5xx response is
|
// Test exponential backoff and that it continues retrying if a 5xx response is
|
||||||
// received
|
// received
|
||||||
func TestGetURLExpBackOff(t *testing.T) {
|
func TestGetURLExpBackOff(t *testing.T) {
|
||||||
|
var expBackoffTests = []struct {
|
||||||
|
count int
|
||||||
|
body string
|
||||||
|
}{
|
||||||
|
{0, "number of attempts: 0"},
|
||||||
|
{1, "number of attempts: 1"},
|
||||||
|
{2, "number of attempts: 2"},
|
||||||
|
}
|
||||||
client := NewHttpClient()
|
client := NewHttpClient()
|
||||||
|
|
||||||
for i, tt := range expBackoffTests {
|
for i, tt := range expBackoffTests {
|
||||||
|
@@ -179,10 +179,18 @@ func MachineID(root string) string {
|
|||||||
return id
|
return id
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// MaskUnit masks a Unit by the given name by symlinking its unit file (in
|
||||||
|
// /etc/systemd/system) to /dev/null, analogous to `systemctl mask`
|
||||||
|
// N.B.: Unlike `systemctl mask`, this function will *remove any existing unit
|
||||||
|
// file* in /etc/systemd/system, to ensure that the mask will succeed.
|
||||||
func MaskUnit(unit string, root string) error {
|
func MaskUnit(unit string, root string) error {
|
||||||
masked := path.Join(root, "etc", "systemd", "system", unit)
|
masked := path.Join(root, "etc", "systemd", "system", unit)
|
||||||
|
if _, err := os.Stat(masked); os.IsNotExist(err) {
|
||||||
if err := os.MkdirAll(path.Dir(masked), os.FileMode(0755)); err != nil {
|
if err := os.MkdirAll(path.Dir(masked), os.FileMode(0755)); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
} else if err := os.Remove(masked); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
return os.Symlink("/dev/null", masked)
|
return os.Symlink("/dev/null", masked)
|
||||||
}
|
}
|
||||||
|
@@ -154,16 +154,33 @@ func TestMaskUnit(t *testing.T) {
|
|||||||
t.Fatalf("Unable to create tempdir: %v", err)
|
t.Fatalf("Unable to create tempdir: %v", err)
|
||||||
}
|
}
|
||||||
defer os.RemoveAll(dir)
|
defer os.RemoveAll(dir)
|
||||||
if err := MaskUnit("foo.service", dir); err != nil {
|
|
||||||
t.Fatalf("Unable to mask unit: %v", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
fullPath := path.Join(dir, "etc", "systemd", "system", "foo.service")
|
// Ensure mask works with units that do not currently exist
|
||||||
target, err := os.Readlink(fullPath)
|
if err := MaskUnit("foo.service", dir); err != nil {
|
||||||
|
t.Fatalf("Unable to mask new unit: %v", err)
|
||||||
|
}
|
||||||
|
fooPath := path.Join(dir, "etc", "systemd", "system", "foo.service")
|
||||||
|
fooTgt, err := os.Readlink(fooPath)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("Unable to read link", err)
|
t.Fatalf("Unable to read link", err)
|
||||||
}
|
}
|
||||||
if target != "/dev/null" {
|
if fooTgt != "/dev/null" {
|
||||||
t.Fatalf("unit not masked, got unit target", target)
|
t.Fatalf("unit not masked, got unit target", fooTgt)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Ensure mask works with unit files that already exist
|
||||||
|
barPath := path.Join(dir, "etc", "systemd", "system", "bar.service")
|
||||||
|
if _, err := os.Create(barPath); err != nil {
|
||||||
|
t.Fatalf("Error creating new unit file: %v", err)
|
||||||
|
}
|
||||||
|
if err := MaskUnit("bar.service", dir); err != nil {
|
||||||
|
t.Fatalf("Unable to mask existing unit: %v", err)
|
||||||
|
}
|
||||||
|
barTgt, err := os.Readlink(barPath)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("Unable to read link", err)
|
||||||
|
}
|
||||||
|
if barTgt != "/dev/null" {
|
||||||
|
t.Fatalf("unit not masked, got unit target", barTgt)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user