Compare commits

...

6 Commits

Author SHA1 Message Date
Jonathan Boulle
a9a910b5c4 chore(coreos-cloudinit): bump to 0.7.3 2014-05-29 14:52:58 -07:00
Jonathan Boulle
8e94b4140a Merge pull request #122 from jonboulle/122
ec2-cloudinit service fails after reboot with "reboot-strategy: off"
2014-05-29 14:25:58 -07:00
Jonathan Boulle
cd322863e9 Merge pull request #129 from jonboulle/exp
fix(pkg): simplify exponential backoff to avoid overflows
2014-05-29 14:02:47 -07:00
Jonathan Boulle
786e4bef65 fix(systemd): remove any existing unit when calling mask 2014-05-29 13:59:55 -07:00
Jonathan Boulle
269a658d4b fix(pkg): simplify exponential backoff to avoid overflows 2014-05-29 11:11:18 -07:00
Michael Marineau
e317c7eb9a chore(coreos-cloudinit): bump to 0.7.2+git 2014-05-27 14:02:11 -07:00
6 changed files with 67 additions and 23 deletions

View File

@@ -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.

View File

@@ -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

View File

@@ -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)
} }

View File

@@ -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 {

View File

@@ -179,9 +179,17 @@ 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.MkdirAll(path.Dir(masked), os.FileMode(0755)); err != nil { if _, err := os.Stat(masked); os.IsNotExist(err) {
if err := os.MkdirAll(path.Dir(masked), os.FileMode(0755)); err != nil {
return err
}
} else if err := os.Remove(masked); err != nil {
return err return err
} }
return os.Symlink("/dev/null", masked) return os.Symlink("/dev/null", masked)

View File

@@ -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)
} }
} }