Skip to content

Commit

Permalink
Merge pull request #238 from kacf/1.1.x
Browse files Browse the repository at this point in the history
1.1.x cherry-picks
  • Loading branch information
Kristian Amlie authored Aug 23, 2017
2 parents 81c66b1 + 64e0a00 commit 086b55e
Show file tree
Hide file tree
Showing 11 changed files with 178 additions and 46 deletions.
20 changes: 15 additions & 5 deletions client/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -191,22 +191,32 @@ func loadServerTrust(conf Config) (*x509.CertPool, error) {
return nil, nil
}

certs, err := x509.SystemCertPool()
syscerts, err := x509.SystemCertPool()
if err != nil {
return nil, err
}

// Read certificate file.
cacert, err := ioutil.ReadFile(conf.ServerCert)
servcert, err := ioutil.ReadFile(conf.ServerCert)
if err != nil {
return nil, err
}
certs.AppendCertsFromPEM(cacert)

if len(certs.Subjects()) == 0 {
if len(servcert) == 0 {
return nil, errors.New("unable to find system and server certificates")
}

if syscerts == nil {
log.Warn("No system certificates found.")
syscerts = x509.NewCertPool()
}

syscerts.AppendCertsFromPEM(servcert)

if len(syscerts.Subjects()) == 0 {
return nil, errorAddingServerCertificateToPool
}
return certs, nil
return syscerts, nil
}

func loadClientCert(conf Config) (*tls.Certificate, error) {
Expand Down
29 changes: 29 additions & 0 deletions client/client_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,9 +14,12 @@
package client

import (
"io/ioutil"
"net"
"net/http"
"net/http/httptest"
"os"
"runtime"
"strings"
"testing"
"time"
Expand Down Expand Up @@ -164,3 +167,29 @@ func TestCaLoading(t *testing.T) {
assert.True(t, systemOK)
assert.True(t, oursOK)
}

func TestEmptySystemCertPool(t *testing.T) {
version := runtime.Version()
if strings.HasPrefix(version, "1.6") || strings.HasPrefix(version, "1.7") || strings.HasPrefix(version, "1.8") {
// Environment variable not included until version 1.9. Therefore skipping this test.
t.SkipNow()
}

tmpdir, err := ioutil.TempDir("", "nocertsfolder")
assert.NoError(t, err)

// Fake the environment variables, to override ssl-cert lookup
err = os.Setenv("SSL_CERT_DIR", tmpdir)
assert.NoError(t, err)

err = os.Setenv("SSL_CERT_FILE", tmpdir+"idonotexist.crt") // fakes a non existing cert-file
assert.NoError(t, err)

conf := Config{
ServerCert: "server.crt",
}

certs, err := loadServerTrust(conf)
assert.NoError(t, err)
assert.NotZero(t, certs)
}
16 changes: 13 additions & 3 deletions device.go
Original file line number Diff line number Diff line change
Expand Up @@ -145,9 +145,19 @@ func (d *device) EnableUpdatedPartition() error {
}

func (d *device) CommitUpdate() error {
log.Info("Commiting update")
// For now set only appropriate boot flags
return d.WriteEnv(BootVars{"upgrade_available": "0"})
// Check if the user has an upgrade to commit, if not, throw an error
hasUpdate, err := d.HasUpdate()
if err != nil {
return err
}
if hasUpdate {
log.Info("Commiting update")
// For now set only appropriate boot flags
return d.WriteEnv(BootVars{"upgrade_available": "0"})
}
errorNoUpgradeMounted := "There is nothing to commit"
log.Errorln(errorNoUpgradeMounted)
return errors.New(errorNoUpgradeMounted)
}

func (d *device) HasUpdate() (bool, error) {
Expand Down
44 changes: 40 additions & 4 deletions device_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,17 +21,53 @@ import (
"github.com/stretchr/testify/assert"
)

// implements BootEnvReadWriter
type fakeBootEnv struct {
readVars BootVars
readErr error
writeVars BootVars
writeErr error
}

func (f *fakeBootEnv) ReadEnv(...string) (BootVars, error) {
return f.readVars, f.readErr
}

func (f *fakeBootEnv) WriteEnv(w BootVars) error {
f.writeVars = w
return f.writeErr
}

func Test_commitUpdate(t *testing.T) {
runner := newTestOSCalls("", 0)
fakeEnv := uBootEnv{&runner}
device := device{}
device.BootEnvReadWriter = &fakeEnv

device.BootEnvReadWriter = &fakeBootEnv{
readVars: BootVars{
"upgrade_available": "1",
},
}

if err := device.CommitUpdate(); err != nil {
t.FailNow()
}

runner = newTestOSCalls("", 1)
device.BootEnvReadWriter = &fakeBootEnv{
readVars: BootVars{
"upgrade_available": "0",
},
}

if err := device.CommitUpdate(); err == nil {
t.FailNow()
}

device.BootEnvReadWriter = &fakeBootEnv{
readVars: BootVars{
"upgrade_available": "1",
},
readErr: errors.New("IO error"),
}

if err := device.CommitUpdate(); err == nil {
t.FailNow()
}
Expand Down
7 changes: 6 additions & 1 deletion installer/installer.go
Original file line number Diff line number Diff line change
Expand Up @@ -59,12 +59,17 @@ func Install(art io.ReadCloser, dt string, key []byte, device UInstaller) error
ar.CompatibleDevicesCallback = func(devices []string) error {
log.Debugf("checking if device [%s] is on compatibile device list: %v\n",
dt, devices)
if dt == "" {
log.Errorf("Unknown device_type. Continuing with update")
return nil
}
for _, dev := range devices {
if dev == dt {
return nil
}
}
return errors.New("installer: image not compatible with device")
return errors.Errorf("installer: image (device types %v) not compatible with device %v",
devices, dt)
}

// VerifySignatureCallback needs to be registered both for
Expand Down
4 changes: 2 additions & 2 deletions installer/installer_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ func TestInstall(t *testing.T) {
err = Install(art, "fake-device", nil, nil)
assert.Error(t, err)
assert.Contains(t, errors.Cause(err).Error(),
"image not compatible with device")
"not compatible with device fake-device")

art, err = MakeRootfsImageArtifact(1, false)
assert.NoError(t, err)
Expand All @@ -62,7 +62,7 @@ func TestInstallSigned(t *testing.T) {
err = Install(art, "fake-device", []byte(PublicRSAKey), new(fDevice))
assert.Error(t, err)
assert.Contains(t, errors.Cause(err).Error(),
"image not compatible with device")
"not compatible with device fake-device")

// installation successful
art, err = MakeRootfsImageArtifact(2, true)
Expand Down
5 changes: 4 additions & 1 deletion main.go
Original file line number Diff line number Diff line change
Expand Up @@ -405,7 +405,10 @@ func doMain(args []string) error {
switch {

case *runOptions.imageFile != "":
dt := GetDeviceType(defaultDeviceTypeFile)
dt, err := GetDeviceType(defaultDeviceTypeFile)
if err != nil {
log.Errorf("Unable to verify the existing hardware. Update will continue anyways: %v : %v", defaultDeviceTypeFile, err)
}
vKey := config.GetVerificationKey()
return doRootfs(device, runOptions, dt, vKey)

Expand Down
56 changes: 36 additions & 20 deletions mender.go
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ type UInstallCommitRebooter interface {
type Controller interface {
Authorize() menderError
Bootstrap() menderError
GetCurrentArtifactName() string
GetCurrentArtifactName() (string, error)
GetUpdatePollInterval() time.Duration
GetInventoryPollInterval() time.Duration
GetRetryPollInterval() time.Duration
Expand Down Expand Up @@ -209,12 +209,11 @@ func NewMender(config menderConfig, pieces MenderPieces) (*mender, error) {
return m, nil
}

func getManifestData(dataType, manifestFile string) string {
func getManifestData(dataType, manifestFile string) (string, error) {
// This is where Yocto stores buid information
manifest, err := os.Open(manifestFile)
if err != nil {
log.Error("Can not read manifest data.")
return ""
return "", err
}

scanner := bufio.NewScanner(manifest)
Expand All @@ -226,35 +225,36 @@ func getManifestData(dataType, manifestFile string) string {
lineID := strings.Split(line, "=")
if len(lineID) != 2 {
log.Errorf("Broken device manifest file: (%v)", lineID)
return ""
return "", fmt.Errorf("Broken device manifest file: (%v)", lineID)
}
log.Debug("Current manifest data: ", strings.TrimSpace(lineID[1]))
return strings.TrimSpace(lineID[1])
return strings.TrimSpace(lineID[1]), nil
}
}
if err := scanner.Err(); err != nil {
err = scanner.Err()
if err != nil {
log.Error(err)
}
return ""
return "", err
}

func (m *mender) GetCurrentArtifactName() string {
func (m *mender) GetCurrentArtifactName() (string, error) {
return getManifestData("artifact_name", m.artifactInfoFile)
}

func (m *mender) GetDeviceType() string {
func (m *mender) GetDeviceType() (string, error) {
return getManifestData("device_type", m.deviceTypeFile)
}

func (m *mender) GetArtifactVerifyKey() []byte {
return m.config.GetVerificationKey()
}

func GetCurrentArtifactName(artifactInfoFile string) string {
func GetCurrentArtifactName(artifactInfoFile string) (string, error) {
return getManifestData("artifact_name", artifactInfoFile)
}

func GetDeviceType(deviceTypeFile string) string {
func GetDeviceType(deviceTypeFile string) (string, error) {
return getManifestData("device_type", deviceTypeFile)
}

Expand Down Expand Up @@ -357,15 +357,19 @@ func (m *mender) FetchUpdate(url string) (io.ReadCloser, int64, error) {
// that occurred. If no update is available *UpdateResponse is nil, otherwise it
// contains update information.
func (m *mender) CheckUpdate() (*client.UpdateResponse, menderError) {
currentArtifactName := m.GetCurrentArtifactName()
//TODO: if currentArtifactName == "" {
// return errors.New("")
// }
currentArtifactName, err := m.GetCurrentArtifactName()
if err != nil {
log.Error("could not get the current artifact name")
}

deviceType, err := m.GetDeviceType()
if err != nil {
log.Errorf("Unable to verify the existing hardware. Update will continue anyways: %v : %v", defaultDeviceTypeFile, err)
}
haveUpdate, err := m.updater.GetScheduledUpdate(m.api.Request(m.authToken),
m.config.ServerURL, client.CurrentUpdate{
Artifact: currentArtifactName,
DeviceType: m.GetDeviceType(),
DeviceType: deviceType,
})

if err != nil {
Expand Down Expand Up @@ -478,9 +482,17 @@ func (m *mender) InventoryRefresh() error {
log.Errorf("failed to obtain inventory data: %s", err.Error())
}

deviceType, err := m.GetDeviceType()
if err != nil {
log.Errorf("Unable to verify the existing hardware. Update will continue anyways: %v : %v", defaultDeviceTypeFile, err)
}
artifactName, err := m.GetCurrentArtifactName()
if err != nil {
log.Errorf("Cannot determine current artifact. Update will continue anyways: %v : %v", defaultDeviceTypeFile, err)
}
reqAttr := []client.InventoryAttribute{
{Name: "device_type", Value: m.GetDeviceType()},
{Name: "artifact_name", Value: m.GetCurrentArtifactName()},
{Name: "device_type", Value: deviceType},
{Name: "artifact_name", Value: artifactName},
{Name: "mender_client_version", Value: VersionString()},
}

Expand All @@ -503,6 +515,10 @@ func (m *mender) InventoryRefresh() error {
}

func (m *mender) InstallUpdate(from io.ReadCloser, size int64) error {
return installer.Install(from, m.GetDeviceType(),
deviceType, err := m.GetDeviceType()
if err != nil {
log.Errorf("Unable to verify the existing hardware. Update will continue anyways: %v : %v", defaultDeviceTypeFile, err)
}
return installer.Install(from, deviceType,
m.GetArtifactVerifyKey(), m.UInstallCommitRebooter)
}
17 changes: 12 additions & 5 deletions mender_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -53,10 +53,12 @@ func Test_getArtifactName_noArtifactNameInFile_returnsEmptyName(t *testing.T) {

mender.artifactInfoFile = "artifact_info"

assert.Equal(t, "", mender.GetCurrentArtifactName())
artName, err := mender.GetCurrentArtifactName()
assert.NoError(t, err)
assert.Equal(t, "", artName)
}

func Test_getArtifactName_malformedArtifactNameLine_returnsEmptyName(t *testing.T) {
func Test_getArtifactName_malformedArtifactNameLine_returnsError(t *testing.T) {
mender := newDefaultTestMender()

artifactInfoFile, _ := os.Create("artifact_info")
Expand All @@ -69,7 +71,9 @@ func Test_getArtifactName_malformedArtifactNameLine_returnsEmptyName(t *testing.

mender.artifactInfoFile = "artifact_info"

assert.Equal(t, "", mender.GetCurrentArtifactName())
artName, err := mender.GetCurrentArtifactName()
assert.Error(t, err)
assert.Equal(t, "", artName)
}

func Test_getArtifactName_haveArtifactName_returnsName(t *testing.T) {
Expand All @@ -82,7 +86,9 @@ func Test_getArtifactName_haveArtifactName_returnsName(t *testing.T) {
artifactInfoFile.WriteString(fileContent)
mender.artifactInfoFile = "artifact_info"

assert.Equal(t, "mender-image", mender.GetCurrentArtifactName())
artName, err := mender.GetCurrentArtifactName()
assert.NoError(t, err)
assert.Equal(t, "mender-image", artName)
}

func newTestMender(runner *testOSCalls, config menderConfig, pieces testMenderPieces) *mender {
Expand Down Expand Up @@ -281,7 +287,8 @@ func Test_CheckUpdateSimple(t *testing.T) {
ioutil.WriteFile(artifactInfo, []byte("artifact_name=fake-id\nDEVICE_TYPE=hammer"), 0600)
ioutil.WriteFile(deviceType, []byte("device_type=hammer"), 0600)

currID := mender.GetCurrentArtifactName()
currID, sErr := mender.GetCurrentArtifactName()
assert.NoError(t, sErr)
assert.Equal(t, "fake-id", currID)
// make artifact name same as current, will result in no updates being available
srv.Update.Data.Artifact.ArtifactName = currID
Expand Down
Loading

0 comments on commit 086b55e

Please sign in to comment.